2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
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.
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.
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.
22 public int mm2mils100(real mm) = floor (mm / 25.4 * 1000 * 100 + 0.5);
24 public real mils1002mm(real mils100) = mils100 * 25.4 / 100 / 1000;
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);
33 /* default pad options */
34 public string pad_options = "square";
36 /* default pin options */
37 public string pin_options = "pin";
39 /* default ink thickness */
40 public real line_thickness = mils1002mm(1000);
49 public void element_start(string name) {
51 if (!is_uninit(&out_name)) {
52 tmp_name = sprintf("_tmp-%d.fp", PID::getpid());
53 out = open(tmp_name, "w");
54 reread = open(tmp_name, "r");
59 fprintf(out, "# author: Keith Packard\n");
60 fprintf(out, "# email: keithp@keithp.com\n");
61 fprintf(out, "# dist-license: GPL 2\n");
62 fprintf(out, "# use-license: unlimited\n");
63 fprintf(out, "Element [\"\" \"%s\" \"\" \"\" 0 0 0 0 0 100 \"\"]\n",
68 public void element_args() {
72 ParseArgs::argdesc argd = {
75 .var = (ParseArgs::arg_var.arg_string) &out_name,
78 .expr_name = "filename",
79 .desc = "Output file name"
82 .unknown = &(int other_args)
85 ParseArgs::parseargs(&argd, &argv);
87 if (!is_uninit(&other_args))
88 argv = (string[dim(argv)-other_args+1]) {
89 [i] = (i == 0) ? argv[0] : argv[i + other_args-1]
95 public void element_end() {
98 if (!is_uninit(&out_name)) {
101 twixt(file result = open(out_name, "w"); close(result)) {
102 while (!end(reread)) {
103 putb(getb(reread), result);
106 } catch open_error (string message, error_type error, string name) {
107 fprintf(stderr, "%s: %s\n", name, message);
113 public typedef struct {
114 real center_x; /* center of pad */
117 real width; /* size of pad */
120 real spacing; /* space between pad and other traces */
121 real soldermask; /* space between pad and solder mask */
122 string name; /* pad name */
123 string number; /* pad number */
124 string options; /* pad options */
126 /* normally computed, but can be provided */
127 real x1; /* start of pad "line" */
129 real x2; /* end of pad "line" */
131 real thickness; /* thickness of pad "line" */
132 real clearance; /* twice the spacing between pad and other traces */
133 real mask; /* thickness of pad and solder mask */
136 pad_t fill_pad(pad_t pad) {
137 if (is_uninit(&pad.x1))
138 pad.x1 = pad.center_x - max(0, (pad.width - pad.height) / 2);
139 if (is_uninit(&pad.x2))
140 pad.x2 = pad.center_x + max(0, (pad.width - pad.height) / 2);
142 if (is_uninit(&pad.y1))
143 pad.y1 = pad.center_y - max(0, (pad.height - pad.width) / 2);
144 if (is_uninit(&pad.y2))
145 pad.y2 = pad.center_y + max(0, (pad.height - pad.width) / 2);
147 if (is_uninit(&pad.spacing))
148 pad.spacing = process_space;
149 if (is_uninit(&pad.soldermask))
150 pad.soldermask = process_soldermask;
151 if (is_uninit(&pad.number))
152 pad.number = pad.name;
153 if (is_uninit(&pad.options))
154 pad.options = pad_options;
156 if (is_uninit(&pad.thickness))
157 pad.thickness = min(pad.width, pad.height);
159 if (is_uninit(&pad.clearance))
160 pad.clearance = pad.spacing * 2;
162 if (is_uninit(&pad.mask))
163 pad.mask = pad.thickness + pad.soldermask * 2;
165 # fprintf(out, "pad %v\n", pad);
170 public exception violation(string rule, real min, real val);
172 public check(string rule, real min, real val, bool zero_ok) {
173 if (zero_ok && val <= 0)
176 Debug::trace(Thread::current());
177 File::fprintf(stderr, "rule %s violated (%fmm %fmils < %fmm %fmils)\n",
179 val, mm2mils100(val)/100.0,
180 min, mm2mils100(min)/100.0);
185 public void pad(pad_t pad)
189 check("pad trace", process_trace, pad.thickness, false);
190 check("pad space", process_space, pad.clearance / 2, true);
191 check("pad mask", process_soldermask, (pad.mask - pad.thickness) / 2, true);
193 fprintf(out, " Pad[");
194 fprintf(out, " %6d %6d %6d %6d",
199 fprintf(out, " %6d %6d %6d",
200 mm2mils100(pad.thickness),
201 mm2mils100(pad.clearance),
202 mm2mils100(pad.mask));
203 fprintf(out, " \"%s\" \"%s\" \"%s\"]\n",
204 pad.name, pad.number, pad.options);
207 public void pad_mm_space_mask_options(real center_x,
218 .center_x = center_x,
219 .center_y = center_y,
223 .soldermask = soldermask,
230 public void pad_mm_space_options(real center_x,
240 .center_x = center_x,
241 .center_y = center_y,
251 public void pad_mm_mask_options(real center_x,
261 .center_x = center_x,
262 .center_y = center_y,
265 .soldermask = soldermask,
272 public void pad_mm_space(real center_x,
281 .center_x = center_x,
282 .center_y = center_y,
291 public void pad_mm(real center_x,
299 .center_x = center_x,
300 .center_y = center_y,
308 public void pad_mm_options(real center_x,
317 .center_x = center_x,
318 .center_y = center_y,
327 /* Pad with partial solder coverage.
328 * Useful for pads under parts which aren't
329 * big enough to use the center function below
331 public void pad_mm_partial(real center_x,
339 .center_x = center_x,
340 .center_y = center_y,
344 .options = pad_options + ",nopaste"
347 real ratio = floor(sqrt(partial) * 100.0 + 0.5) / 100;
350 .center_x = center_x,
351 .center_y = center_y,
352 .width = width * ratio,
353 .height = height * ratio,
358 public void pad_mm_arbitrary( real x1,
372 .thickness = thickness,
379 public typedef struct {
380 real x; /* center of pin */
382 real drill; /* diameter of drill hole */
384 real ring; /* width of annular ring around hole */
385 real spacing; /* space between pin and other traces */
386 real soldermask; /* space between pin and solder mask */
388 string name; /* pin name */
389 string number; /* pin number */
390 string options; /* pin options */
392 /* normally computed, but can be provided */
393 real thickness; /* thickness of pin "line" */
394 real clearance; /* twice the spacing between pin and other traces */
395 real mask; /* thickness of pin and solder mask */
398 pin_t fill_pin(pin_t pin) {
400 /* Fill in process rules if unset */
401 if (is_uninit(&pin.spacing))
402 pin.spacing = process_space;
403 if (is_uninit(&pin.ring))
404 pin.ring = process_ring;
405 if (is_uninit(&pin.soldermask))
406 pin.soldermask = process_soldermask;
408 if (is_uninit(&pin.number))
409 pin.number = pin.name;
410 if (is_uninit(&pin.options))
411 pin.options = pin_options;
413 if (is_uninit(&pin.thickness))
414 pin.thickness = pin.drill + pin.ring * 2;
416 if (is_uninit(&pin.mask))
417 pin.mask = pin.thickness + pin.soldermask * 2;
419 if (is_uninit(&pin.clearance))
420 pin.clearance = pin.spacing * 2;
425 public void pin(pin_t pin)
429 check("pin drill", process_drill, pin.drill, false);
430 check("pin ring", process_ring, (pin.thickness - pin.drill) / 2, true);
431 check("pin space", process_space, pin.clearance / 2, true);
432 if (String::index(pin.options, "via") < 0)
433 check("pin mask", process_soldermask, (pin.mask - pin.thickness) / 2, true);
435 fprintf(out, " Pin[");
436 fprintf(out, " %6d %6d",
439 fprintf(out, " %6d %6d %6d",
440 mm2mils100(pin.thickness),
441 mm2mils100(pin.clearance),
442 mm2mils100(pin.mask));
444 mm2mils100(pin.drill));
445 fprintf(out, " \"%s\" \"%s\" \"%s\"]\n",
446 pin.name, pin.number, pin.options);
449 public void pin_mm_space_mask_options(real x, real y,
450 real drill, real copper, real spacing, real soldermask,
451 string name, string number, string options)
459 .soldermask = soldermask,
462 .options = options });
465 public void pin_mm_space_options(real x, real y, real drill, real copper, real spacing,
478 .options = options });
481 public void pin_mm_space_mask(real x, real y,
482 real drill, real copper, real spacing, real soldermask,
483 string name, string number)
491 .soldermask = soldermask,
496 public void pin_mm_space(real x, real y, real drill, real copper, real spacing,
510 public void pin_mm(real x, real y, real drill, real copper,
523 public void pin_mm_options(real x, real y, real drill, real copper,
535 .options = options });
538 public void pin_mm_mask_options(real x, real y, real drill, real copper,
549 .soldermask = soldermask,
552 .options = options });
555 public void via_mm(real x, real y,
556 real drill, real copper,
570 public void line (real x1, real y1, real x2, real y2)
572 fprintf(out, " ElementLine[");
573 fprintf(out, " %6d %6d %6d %6d",
578 fprintf(out, " %d]\n", mm2mils100(line_thickness));
581 public void rect (real x, real y, real w, real h)
589 public void arc (real center_x, real center_y,
590 real radius_x, real radius_y,
591 real start_angle, real delta_angle)
593 fprintf(out, " ElementArc[ %6d %6d %6d %6d %3d %3d %d]\n",
594 mm2mils100(center_x), mm2mils100(center_y),
595 mm2mils100(radius_x), mm2mils100(radius_y),
596 start_angle, delta_angle, mm2mils100(line_thickness));
599 public typedef struct {
600 real x, y; /* center */
601 real width, height; /* size */
605 int via_cols, via_rows;
613 public void center_pad(center_t center) {
615 if (is_uninit(¢er.via_drill))
616 center.via_drill = process_drill;
618 if (is_uninit(¢er.via_copper))
619 center.via_copper = process_ring;
621 if (is_uninit(¢er.via_space_x)) {
622 real side_x = center.via_drill / 2 + center.via_copper;
623 real space_x = center.width - 2 * side_x;
625 center.via_space_x = space_x / (center.via_cols - 1);
628 if (is_uninit(¢er.via_space_y)) {
629 real side_y = center.via_drill / 2 + center.via_copper;
630 real space_y = center.width - 2 * side_y;
632 center.via_space_y = space_y / (center.via_rows - 1);
637 .center_x = center.x,
638 .center_y = center.y,
639 .width = center.width,
640 .height = center.height,
642 .options = "square,nopaste",
643 .spacing = process_space,
647 for (int r = 0; r < center.via_rows; r++)
648 for (int c = 0; c < center.via_cols; c++) {
649 real x = (c - (center.via_cols - 1) / 2) * center.via_space_x;
650 real y = (r - (center.via_rows - 1) / 2) * center.via_space_y;
652 via_mm(x, y, process_drill, process_ring, center.name);
655 .center_x = center.x + x,
656 .center_y = center.y + y,
657 .width = center.via_space_x / 2,
658 .height = center.via_space_y / 2,
660 .options = "square,nopaste",
666 for (real r = 0; r < center.via_rows - 0.5; r += 0.5) {
667 for (real c = 0; c < center.via_cols - 0.5; c += 0.5) {
669 if (is_int(r) && is_int(c))
672 real x = (c - (center.via_cols - 1) / 2) * center.via_space_x;
673 real y = (r - (center.via_rows - 1) / 2) * center.via_space_y;
677 .center_x = center.x + x,
678 .center_y = center.y + y,
679 .width = center.via_space_x / 2,
680 .height = center.via_space_x / 2,
683 .options = "square,nopaste",
688 .center_x = center.x + x,
689 .center_y = center.y + y,
690 .width = center.via_space_x / 3.5,
691 .height = center.via_space_y / 3.5,