pull in a 40-pin DIP footprint from old pcb library
[hw/altusmetrum] / packages / footprint.5c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 namespace Footprint {
19
20         import File;
21
22         public int mm2mils100(real mm) = floor (mm / 25.4 * 1000 * 100 + 0.5);
23
24         public real mils1002mm(real mils100) = mils100 * 25.4 / 100 / 1000;
25
26         /* OSH park adprocess requirement */
27         public real process_soldermask = mils1002mm(300);
28         public real process_trace = mils1002mm(600);
29         public real process_space = mils1002mm(600);
30         public real process_drill = mils1002mm(1300);
31         public real process_ring = mils1002mm(700);
32
33         /* default pad options */
34         public string pad_options = "square";
35
36         /* default pin options */
37         public string pin_options = "pin";
38
39         /* default ink thickness */
40         public real line_thickness = mils1002mm(1000);
41
42         file out;
43         file reread;
44
45         string out_name;
46
47         string tmp_name;
48
49         bool[string] override_rules = {};
50
51         public void override(string rule) {
52                 override_rules[rule] = true;
53         }
54
55         bool overridden(string rule) {
56                 return hash_test(override_rules, rule) && override_rules[rule];
57         }
58
59         public void element_start(string name) {
60
61                 if (!is_uninit(&out_name)) {
62                         tmp_name = sprintf("_tmp-%d.fp", PID::getpid());
63                         out = open(tmp_name, "w");
64                         reread = open(tmp_name, "r");
65                         unlink(tmp_name);
66                 } else
67                         out = stdout;
68
69                 fprintf(out, "# author: Keith Packard\n");
70                 fprintf(out, "# email: keithp@keithp.com\n");
71                 fprintf(out, "# dist-license: GPL 2\n");
72                 fprintf(out, "# use-license: unlimited\n");
73                 fprintf(out, "Element [\"\" \"%s\" \"\" \"\" 0 0 0 0 0 100 \"\"]\n",
74                         name);
75                 fprintf(out, "(\n");
76         }
77
78         public void element_args() {
79
80                 int other_args;
81
82                 ParseArgs::argdesc argd = {
83                         .args = {
84                                 {
85                                         .var = (ParseArgs::arg_var.arg_string) &out_name,
86                                         .name = "output",
87                                         .abbr = 'o',
88                                         .expr_name = "filename",
89                                         .desc = "Output file name"
90                                 }
91                         },
92                         .unknown = &(int other_args)
93                 };
94
95                 ParseArgs::parseargs(&argd, &argv);
96
97                 if (!is_uninit(&other_args))
98                         argv = (string[dim(argv)-other_args+1]) {
99                                 [i] = (i == 0) ? argv[0] : argv[i + other_args-1]
100                         };
101         }
102
103         element_args();
104
105         public void element_end() {
106                 fprintf(out, ")\n");
107
108                 if (!is_uninit(&out_name)) {
109                         try {
110                                 close(out);
111                                 twixt(file result = open(out_name, "w"); close(result)) {
112                                         while (!end(reread)) {
113                                                 putb(getb(reread), result);
114                                         }
115                                 }
116                         } catch open_error (string message, error_type error, string name) {
117                                 fprintf(stderr, "%s: %s\n", name, message);
118                                 exit(1);
119                         }
120                 }
121         }
122
123         public typedef struct {
124                 real    center_x;       /* center of pad */
125                 real    center_y;
126
127                 real    width;          /* size of pad */
128                 real    height;
129
130                 real    spacing;        /* space between pad and other traces */
131                 real    soldermask;     /* space between pad and solder mask */
132                 string  name;           /* pad name */
133                 string  number;         /* pad number */
134                 string  options;        /* pad options */
135
136                 /* normally computed, but can be provided */
137                 real    x1;             /* start of pad "line" */
138                 real    y1;
139                 real    x2;             /* end of pad "line" */
140                 real    y2;
141                 real    thickness;      /* thickness of pad "line" */
142                 real    clearance;      /* twice the spacing between pad and other traces */
143                 real    mask;           /* thickness of pad and solder mask */
144         } pad_t;
145
146         pad_t fill_pad(pad_t pad) {
147                 if (is_uninit(&pad.x1))
148                         pad.x1 = pad.center_x - max(0, (pad.width - pad.height) / 2);
149                 if (is_uninit(&pad.x2))
150                         pad.x2 = pad.center_x + max(0, (pad.width - pad.height) / 2);
151
152                 if (is_uninit(&pad.y1))
153                         pad.y1 = pad.center_y - max(0, (pad.height - pad.width) / 2);
154                 if (is_uninit(&pad.y2))
155                         pad.y2 = pad.center_y + max(0, (pad.height - pad.width) / 2);
156
157                 if (is_uninit(&pad.spacing))
158                         pad.spacing = process_space;
159                 if (is_uninit(&pad.soldermask))
160                         pad.soldermask = process_soldermask;
161                 if (is_uninit(&pad.number))
162                         pad.number = pad.name;
163                 if (is_uninit(&pad.options))
164                         pad.options = pad_options;
165
166                 if (is_uninit(&pad.thickness))
167                         pad.thickness = min(pad.width, pad.height);
168
169                 if (is_uninit(&pad.clearance))
170                         pad.clearance = pad.spacing * 2;
171
172                 if (is_uninit(&pad.mask))
173                         pad.mask = pad.thickness + pad.soldermask * 2;
174
175 #               fprintf(out, "pad %v\n", pad);
176
177                 return pad;
178         }
179
180         public exception violation(string rule, real min, real val);
181
182         public check(string rule, real min, real val, bool zero_ok) {
183
184                 if (overridden(rule))
185                         return;
186                 if (zero_ok && val <= 0)
187                         return;
188                 if (val < min) {
189                         Debug::trace(Thread::current());
190                         File::fprintf(stderr, "rule %s violated (%fmm %fmils < %fmm %fmils)\n",
191                                       rule,
192                                       val, mm2mils100(val)/100.0,
193                                       min, mm2mils100(min)/100.0);
194                         exit(1);
195                 }
196         }
197
198         public void pad(pad_t pad)
199         {
200                 pad = fill_pad(pad);
201
202                 check("pad trace", process_trace, pad.thickness, false);
203                 check("pad space", process_space, pad.clearance / 2, true);
204                 check("pad mask", process_soldermask, (pad.mask - pad.thickness) / 2, true);
205
206                 fprintf(out, "    Pad[");
207                 fprintf(out, " %6d %6d %6d %6d",
208                         mm2mils100(pad.x1),
209                         mm2mils100(pad.y1),
210                         mm2mils100(pad.x2),
211                         mm2mils100(pad.y2));
212                 fprintf(out, " %6d %6d %6d",
213                         mm2mils100(pad.thickness),
214                         mm2mils100(pad.clearance),
215                         mm2mils100(pad.mask));
216                 fprintf(out, " \"%s\" \"%s\" \"%s\"]\n",
217                         pad.name, pad.number, pad.options);
218         }
219
220         public void pad_mm_space_mask_options(real center_x,
221                                               real center_y,
222                                               real width,
223                                               real height,
224                                               real spacing,
225                                               real soldermask,
226                                               string name,
227                                               string number,
228                                               string options)
229         {
230                 pad((pad_t) {
231                                 .center_x = center_x,
232                                 .center_y = center_y,
233                                 .width = width,
234                                 .height = height,
235                                 .spacing = spacing,
236                                 .soldermask = soldermask,
237                                 .name = name,
238                                 .number = number,
239                                 .options = options
240                                 });
241         }
242
243         public void pad_mm_space_options(real center_x,
244                                          real center_y,
245                                          real width,
246                                          real height,
247                                          real spacing,
248                                          string name,
249                                          string number,
250                                          string options)
251         {
252                 pad((pad_t) {
253                                 .center_x = center_x,
254                                 .center_y = center_y,
255                                 .width = width,
256                                 .height = height,
257                                 .spacing = spacing,
258                                 .name = name,
259                                 .number = number,
260                                 .options = options
261                                 });
262         }
263
264         public void pad_mm_mask_options(real center_x,
265                                          real center_y,
266                                          real width,
267                                          real height,
268                                          real soldermask,
269                                          string name,
270                                          string number,
271                                          string options)
272         {
273                 pad((pad_t) {
274                                 .center_x = center_x,
275                                 .center_y = center_y,
276                                 .width = width,
277                                 .height = height,
278                                 .soldermask = soldermask,
279                                 .name = name,
280                                 .number = number,
281                                 .options = options
282                                 });
283         }
284
285         public void pad_mm_space(real center_x,
286                                  real center_y,
287                                  real width,
288                                  real height,
289                                  real spacing,
290                                  string name,
291                                  string number)
292         {
293                 pad((pad_t) {
294                                 .center_x = center_x,
295                                 .center_y = center_y,
296                                 .width = width,
297                                 .height = height,
298                                 .spacing = spacing,
299                                 .name = name,
300                                 .number = number,
301                                 });
302         }
303
304         public void pad_mm(real center_x,
305                            real center_y,
306                            real width,
307                            real height,
308                            string name,
309                            string number)
310         {
311                 pad((pad_t) {
312                                 .center_x = center_x,
313                                 .center_y = center_y,
314                                 .width = width,
315                                 .height = height,
316                                 .name = name,
317                                 .number = number,
318                                 });
319         }
320
321         public void pad_mm_options(real center_x,
322                                    real center_y,
323                                    real width,
324                                    real height,
325                                    string name,
326                                    string number,
327                                    string options)
328         {
329                 pad((pad_t) {
330                                 .center_x = center_x,
331                                 .center_y = center_y,
332                                 .width = width,
333                                 .height = height,
334                                 .name = name,
335                                 .number = number,
336                                 .options = options
337                                 });
338         }
339
340         /* Pad with partial solder coverage.
341          * Useful for pads under parts which aren't
342          * big enough to use the center function below
343          */
344         public void pad_mm_partial(real center_x,
345                                    real center_y,
346                                    real width,
347                                    real height,
348                                    real partial,
349                                    string name)
350         {
351                 pad((pad_t) {
352                                 .center_x = center_x,
353                                 .center_y = center_y,
354                                 .width = width,
355                                 .height = height,
356                                 .name = name,
357                                 .options = pad_options + ",nopaste"
358                                 });
359
360                 real    ratio = floor(sqrt(partial) * 100.0 + 0.5) / 100;
361
362                 pad((pad_t) {
363                                 .center_x = center_x,
364                                 .center_y = center_y,
365                                 .width = width * ratio,
366                                 .height = height * ratio,
367                                 .name = name,
368                                 });
369         }
370
371         public void pad_mm_arbitrary(   real x1,
372                                         real y1,
373                                         real x2,
374                                         real y2,
375                                         real thickness,
376                                         string name,
377                                         string number,
378                                         string options)
379         {
380                 pad((pad_t) {
381                                 .x1 = x1,
382                                 .y1 = y1,
383                                 .x2 = x2,
384                                 .y2 = y2,
385                                 .thickness = thickness,
386                                 .name = name,
387                                 .number = number,
388                                 .options = options
389                                 });
390         }
391
392         public typedef struct {
393                 real    x;              /* center of pin */
394                 real    y;
395                 real    drill;          /* diameter of drill hole */
396
397                 real    ring;           /* width of annular ring around hole */
398                 real    spacing;        /* space between pin and other traces */
399                 real    soldermask;     /* space between pin and solder mask */
400
401                 string  name;           /* pin name */
402                 string  number;         /* pin number */
403                 string  options;        /* pin options */
404
405                 /* normally computed, but can be provided */
406                 real    thickness;      /* thickness of pin "line" */
407                 real    clearance;      /* twice the spacing between pin and other traces */
408                 real    mask;           /* thickness of pin and solder mask */
409         } pin_t;
410
411         pin_t fill_pin(pin_t pin) {
412
413                 /* Fill in process rules if unset */
414                 if (is_uninit(&pin.spacing))
415                         pin.spacing = process_space;
416                 if (is_uninit(&pin.ring))
417                         pin.ring = process_ring;
418                 if (is_uninit(&pin.soldermask))
419                         pin.soldermask = process_soldermask;
420
421                 if (is_uninit(&pin.number))
422                         pin.number = pin.name;
423                 if (is_uninit(&pin.options))
424                         pin.options = pin_options;
425
426                 if (is_uninit(&pin.thickness))
427                         pin.thickness = pin.drill + pin.ring * 2;
428
429                 if (is_uninit(&pin.mask))
430                         pin.mask = pin.thickness + pin.soldermask * 2;
431
432                 if (is_uninit(&pin.clearance))
433                         pin.clearance = pin.spacing * 2;
434
435                 return pin;
436         }
437
438         public void pin(pin_t pin)
439         {
440                 pin = fill_pin(pin);
441
442                 check("pin drill", process_drill, pin.drill, false);
443                 check("pin ring", process_ring, (pin.thickness - pin.drill) / 2, true);
444                 check("pin space", process_space, pin.clearance / 2, true);
445                 if (String::index(pin.options, "via") < 0)
446                         check("pin mask", process_soldermask, (pin.mask - pin.thickness) / 2, true);
447
448                 fprintf(out, "    Pin[");
449                 fprintf(out, " %6d %6d",
450                         mm2mils100(pin.x),
451                         mm2mils100(pin.y));
452                 fprintf(out, " %6d %6d %6d",
453                         mm2mils100(pin.thickness),
454                         mm2mils100(pin.clearance),
455                         mm2mils100(pin.mask));
456                 fprintf(out," %6d",
457                        mm2mils100(pin.drill));
458                 fprintf(out, " \"%s\" \"%s\" \"%s\"]\n",
459                         pin.name, pin.number, pin.options);
460         }
461
462         public void pin_mm_space_mask_options(real x, real y,
463                                               real drill, real copper, real spacing, real soldermask,
464                                               string name, string number, string options)
465         {
466                 pin ((pin_t) {
467                                 .x = x,
468                                 .y = y,
469                                 .drill = drill,
470                                 .ring = copper,
471                                 .spacing = spacing,
472                                 .soldermask = soldermask,
473                                 .name = name,
474                                 .number = number,
475                                 .options = options });
476         }
477
478         public void pin_mm_space_options(real x, real y, real drill, real copper, real spacing,
479                                          string name,
480                                          string number,
481                                          string options)
482         {
483                 pin ((pin_t) {
484                                 .x = x,
485                                 .y = y,
486                                 .drill = drill,
487                                 .ring = copper,
488                                 .spacing = spacing,
489                                 .name = name,
490                                 .number = number,
491                                 .options = options });
492         }
493
494         public void pin_mm_space_mask(real x, real y,
495                                       real drill, real copper, real spacing, real soldermask,
496                                       string name, string number)
497         {
498                 pin ((pin_t) {
499                                 .x = x,
500                                 .y = y,
501                                 .drill = drill,
502                                 .ring = copper,
503                                 .spacing = spacing,
504                                 .soldermask = soldermask,
505                                 .name = name,
506                                 .number = number });
507         }
508
509         public void pin_mm_space(real x, real y, real drill, real copper, real spacing,
510                         string name,
511                         string number)
512         {
513                 pin ((pin_t) {
514                                 .x = x,
515                                 .y = y,
516                                 .drill = drill,
517                                 .ring = copper,
518                                 .spacing = spacing,
519                                 .name = name,
520                                 .number = number });
521         }
522
523         public void pin_mm(real x, real y, real drill, real copper,
524                         string name,
525                         string number)
526         {
527                 pin ((pin_t) {
528                                 .x = x,
529                                 .y = y,
530                                 .drill = drill,
531                                 .ring = copper,
532                                 .name = name,
533                                 .number = number,});
534         }
535
536         public void pin_mm_options(real x, real y, real drill, real copper,
537                                    string name,
538                                    string number,
539                                    string options)
540         {
541                 pin ((pin_t) {
542                                 .x = x,
543                                 .y = y,
544                                 .drill = drill,
545                                 .ring = copper,
546                                 .name = name,
547                                 .number = number,
548                                 .options = options });
549         }
550
551         public void pin_mm_mask_options(real x, real y, real drill, real copper,
552                                         real soldermask,
553                                         string name,
554                                         string number,
555                                         string options)
556         {
557                 pin ((pin_t) {
558                                 .x = x,
559                                 .y = y,
560                                 .drill = drill,
561                                 .ring = copper,
562                                 .soldermask = soldermask,
563                                 .name = name,
564                                 .number = number,
565                                 .options = options });
566         }
567
568         public void via_mm(real x, real y,
569                            real drill, real copper,
570                            string name)
571         {
572                 pin ((pin_t) {
573                                 .x = x,
574                                 .y = y,
575                                 .drill = drill,
576                                 .ring = copper,
577                                 .mask = 0,
578                                 .name = name,
579                                 .options = "via"
580                         });
581         }
582
583         public void line (real x1, real y1, real x2, real y2)
584         {
585                 fprintf(out, "    ElementLine[");
586                 fprintf(out, " %6d %6d %6d %6d",
587                         mm2mils100(x1),
588                         mm2mils100(y1),
589                         mm2mils100(x2),
590                         mm2mils100(y2));
591                 fprintf(out, " %d]\n", mm2mils100(line_thickness));
592         }
593
594         public void rect (real x, real y, real w, real h)
595         {
596                 line(x,y,x+w,y);
597                 line(x+w,y,x+w,y+h);
598                 line(x+w,y+h,x,y+h);
599                 line(x,y+h,x,y);
600         }
601
602         public void arc (real center_x, real center_y,
603                          real radius_x, real radius_y,
604                          real start_angle, real delta_angle)
605         {
606                 fprintf(out, "    ElementArc[ %6d %6d %6d %6d %3d %3d %d]\n",
607                         mm2mils100(center_x), mm2mils100(center_y),
608                         mm2mils100(radius_x), mm2mils100(radius_y),
609                         start_angle, delta_angle, mm2mils100(line_thickness));
610         }
611
612         public typedef struct {
613                 real    x, y;           /* center */
614                 real    width, height;  /* size */
615
616                 real    via_space_x;
617                 real    via_space_y;
618                 int     via_cols, via_rows;
619                 string  name;
620
621                 real    via_drill;
622                 real    via_copper;
623
624         } center_t;
625
626         public void center_pad(center_t center) {
627
628                 if (is_uninit(&center.via_drill))
629                         center.via_drill = process_drill;
630
631                 if (is_uninit(&center.via_copper))
632                         center.via_copper = process_ring;
633
634                 if (is_uninit(&center.via_space_x)) {
635                         real    side_x = center.via_drill / 2 + center.via_copper;
636                         real    space_x = center.width - 2 * side_x;
637
638                         center.via_space_x = space_x / (center.via_cols - 1);
639                 }
640
641                 if (is_uninit(&center.via_space_y)) {
642                         real    side_y = center.via_drill / 2 + center.via_copper;
643                         real    space_y = center.width - 2 * side_y;
644
645                         center.via_space_y = space_y / (center.via_rows - 1);
646                 }
647
648                 /* whole pad */
649                 pad((pad_t) {
650                                 .center_x = center.x,
651                                 .center_y = center.y,
652                                 .width = center.width,
653                                 .height = center.height,
654                                 .name = center.name,
655                                 .options = "square,nopaste",
656                                 .spacing = process_space,
657                                 .mask = 0});
658
659                 /* vias */
660                 for (int r = 0; r < center.via_rows; r++)
661                         for (int c = 0; c < center.via_cols; c++) {
662                                 real    x = (c - (center.via_cols - 1) / 2) * center.via_space_x;
663                                 real    y = (r - (center.via_rows - 1) / 2) * center.via_space_y;
664
665                                 via_mm(x, y, process_drill, process_ring, center.name);
666
667                                 pad((pad_t) {
668                                                 .center_x = center.x + x,
669                                                 .center_y = center.y + y,
670                                                 .width = center.via_space_x / 2,
671                                                 .height = center.via_space_y / 2,
672                                                 .name = center.name,
673                                                 .options = "square,nopaste",
674                                                 .clearance = 0,
675                                                 .mask = 0,
676                                         });
677                         }
678
679                 for (real r = 0; r < center.via_rows - 0.5; r += 0.5) {
680                         for (real c = 0; c < center.via_cols - 0.5; c += 0.5) {
681
682                                 if (is_int(r) && is_int(c))
683                                         continue;
684
685                                 real    x = (c - (center.via_cols - 1) / 2) * center.via_space_x;
686                                 real    y = (r - (center.via_rows - 1) / 2) * center.via_space_y;
687
688                                 /* exposed copper */
689                                 pad((pad_t) {
690                                                 .center_x = center.x + x,
691                                                 .center_y = center.y + y,
692                                                 .width = center.via_space_x / 2,
693                                                 .height = center.via_space_x / 2,
694                                                 .soldermask = 0,
695                                                 .name = center.name,
696                                                 .options = "square,nopaste",
697                                                         });
698
699                                 /* paste spot */
700                                 pad((pad_t) {
701                                                 .center_x = center.x + x,
702                                                 .center_y = center.y + y,
703                                                 .width = center.via_space_x / 3.5,
704                                                 .height = center.via_space_y / 3.5,
705                                                 .name = center.name,
706                                                 .options = "square",
707                                         });
708                         }
709                 }
710         }
711 }