1 /*
2 * Copyright 2019 Martin Åberg
3 *
4 * This file is part of Footag.
5 *
6 * Footag is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version.
10 *
11 * Footag is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include "priv.h"
22
23 extern const struct footag_op footag_op_chip;
24 extern const struct footag_op footag_op_chiparray;
25 extern const struct footag_op footag_op_ledsc;
26 extern const struct footag_op footag_op_melf;
27 extern const struct footag_op footag_op_molded;
28 extern const struct footag_op footag_op_capae;
29 extern const struct footag_op footag_op_so;
30 extern const struct footag_op footag_op_sod;
31 extern const struct footag_op footag_op_sodfl;
32 extern const struct footag_op footag_op_soj;
33 extern const struct footag_op footag_op_qfp;
34 extern const struct footag_op footag_op_son;
35 extern const struct footag_op footag_op_qfn;
36 extern const struct footag_op footag_op_pson;
37 extern const struct footag_op footag_op_pqfn;
38 extern const struct footag_op footag_op_bga;
39 extern const struct footag_op footag_op_sot223;
40 extern const struct footag_op footag_op_sot23;
41 extern const struct footag_op footag_op_dip;
42 extern const struct footag_op footag_op_sip;
43 extern const struct footag_op footag_op_pga;
44
45 static const struct footag_op *theop[FOOTAG_TYPE_NUM] = {
46 [FOOTAG_TYPE_CHIP] = &footag_op_chip,
47 [FOOTAG_TYPE_CHIPARRAY] = &footag_op_chiparray,
48 [FOOTAG_TYPE_LEDSC] = &footag_op_ledsc,
49 [FOOTAG_TYPE_MELF] = &footag_op_melf,
50 [FOOTAG_TYPE_MOLDED] = &footag_op_molded,
51 [FOOTAG_TYPE_CAPAE] = &footag_op_capae,
52 [FOOTAG_TYPE_SO] = &footag_op_so,
53 [FOOTAG_TYPE_SOD] = &footag_op_sod,
54 [FOOTAG_TYPE_SODFL] = &footag_op_sodfl,
55 [FOOTAG_TYPE_SOJ] = &footag_op_soj,
56 [FOOTAG_TYPE_QFP] = &footag_op_qfp,
57 [FOOTAG_TYPE_SON] = &footag_op_son,
58 [FOOTAG_TYPE_QFN] = &footag_op_qfn,
59 [FOOTAG_TYPE_PSON] = &footag_op_pson,
60 [FOOTAG_TYPE_PQFN] = &footag_op_pqfn,
61 [FOOTAG_TYPE_BGA] = &footag_op_bga,
62 [FOOTAG_TYPE_SOT223] = &footag_op_sot223,
63 [FOOTAG_TYPE_SOT23] = &footag_op_sot23,
64 [FOOTAG_TYPE_DIP] = &footag_op_dip,
65 [FOOTAG_TYPE_SIP] = &footag_op_sip,
66 [FOOTAG_TYPE_PGA] = &footag_op_pga,
67 };
68
69 /* here we do some parameter checking to not break the application */
footag_get_typeinfo(enum footag_type footype)70 const struct footag_typeinfo *footag_get_typeinfo(
71 enum footag_type footype
72 )
73 {
74 if (footype < 0 || FOOTAG_TYPE_NUM <= footype) {
75 return NULL;
76 }
77 const struct footag_op *op = theop[footype];
78 if (!op) {
79 return NULL;
80 }
81 return op->info;
82 }
83
footag_open(int footype)84 struct footag_ctx *footag_open(int footype)
85 {
86 const struct footag_op *op = theop[footype];
87 struct footag_ctx *ctx;
88 int ret;
89
90 if (!op) {
91 return NULL;
92 }
93 ctx = calloc(1, op->size);
94 if (!ctx) {
95 return NULL;
96 }
97
98 ctx->op = op;
99 ret = op->init(ctx);
100 if (ret) {
101 free(ctx);
102 return NULL;
103 }
104
105 return ctx;
106 }
107
footag_close(struct footag_ctx * ctx)108 int footag_close(struct footag_ctx *ctx)
109 {
110 ctx->op->fini(ctx);
111 free(ctx);
112 return 0;
113 }
114
footag_get_param(struct footag_ctx * ctx)115 struct footag_param *footag_get_param(
116 struct footag_ctx *ctx
117 )
118 {
119 return ctx->param;
120 }
121
footag_get_spec(struct footag_ctx * ctx)122 const struct footag_spec *footag_get_spec(
123 struct footag_ctx *ctx
124 )
125 {
126 int ret;
127 ret = ctx->op->calc(ctx);
128 if (ret) { return NULL; }
129 return &ctx->spec;
130 }
131
footag_init_from_template(struct footag_ctx * ctx,const struct footag_param * temp)132 int footag_init_from_template(
133 struct footag_ctx *ctx,
134 const struct footag_param *temp
135 )
136 {
137 /* count number of parameters, including DONE tag */
138 size_t nelem = 1;
139 for (const struct footag_param *p = temp; p->id != PARAM_DONE; p++) {
140 nelem++;
141 }
142
143 struct footag_param *param;
144
145 param = calloc(nelem, sizeof (*param));
146 if (!param) { return __LINE__; }
147
148 memcpy(param, temp, nelem * sizeof (*param));
149 ctx->param = param;
150
151 return 0;
152 }
153
footag_init_default(struct footag_ctx * ctx)154 int footag_init_default(struct footag_ctx *ctx)
155 {
156 int ret;
157 ctx->spec.pads = NULL;
158 ret = footag_init_from_template(ctx, ctx->op->temp);
159 return ret;
160 }
161
footag_init_twopin(struct footag_ctx * ctx)162 int footag_init_twopin(struct footag_ctx *ctx)
163 {
164 int ret;
165 ctx->spec.pads = NULL;
166 ret = footag_realloc_pads(ctx, 2);
167 if (ret) { return ret; }
168 ret = footag_init_from_template(ctx, ctx->op->temp);
169 return ret;
170 }
171
footag_fini_default(struct footag_ctx * ctx)172 int footag_fini_default(struct footag_ctx *ctx)
173 {
174 free(ctx->spec.pads);
175 free(ctx->param);
176 return 0;
177 }
178
footag_data_by_name(struct footag_ctx * ctx,const char * topic,const char * name)179 const union footag_data *footag_data_by_name(
180 struct footag_ctx *ctx,
181 const char *topic,
182 const char *name
183 )
184 {
185 const struct footag_param *p = ctx->param;
186
187 while (p->id != PARAM_DONE) {
188 if (p->id == PARAM_TOPIC) {
189 if (0 == strcmp(topic, p->name)) {
190 break;
191 }
192 }
193 p++;
194 }
195
196 while (p->id != PARAM_DONE) {
197 if (p->id != PARAM_TOPIC) {
198 if (0 == strcmp(name, p->name)) {
199 return &p->item.data;
200 }
201 }
202 p++;
203 }
204
205 return NULL;
206 }
207
footag_data_by_id(struct footag_ctx * ctx,int id)208 const union footag_data *footag_data_by_id(
209 struct footag_ctx *ctx,
210 int id
211 )
212 {
213 const struct footag_param *p = ctx->param;
214
215 while (p->id != PARAM_DONE) {
216 if (p->id == id) {
217 return &p->item.data;
218 }
219 p++;
220 }
221
222 return NULL;
223 }
224
225 static const char *const GRID_ROWNAMES[] = {
226 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
227 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
228 "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK",
229 "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", NULL
230 };
231
232 /* assumes strlen(rowname) */
skiprow(const char * const rowname,const struct footag_bitmask * const skipmask)233 static bool skiprow(
234 const char *const rowname,
235 const struct footag_bitmask *const skipmask
236 )
237 {
238 if (!skipmask) { return false; }
239 if (!rowname) { return false; }
240 for (unsigned int i = 0; i < skipmask->num; i++) {
241 if (!(skipmask->val & (1 << i))) {
242 continue;
243 }
244 const char skipchar = skipmask->strs[i][0];
245 if (strchr(rowname, skipchar)) {
246 return true;
247 }
248 }
249 return false;
250 }
251
footag_gridnames(struct footag_pad * p,const struct footag_bitmask * const skipmask,int rows,int cols)252 void footag_gridnames(
253 struct footag_pad *p,
254 const struct footag_bitmask *const skipmask,
255 int rows,
256 int cols
257 )
258 {
259 int i = 0;
260 int rowni = 0;
261
262 for (int row = 0; row < rows; row++) {
263 const char *rowname;
264 rowname = GRID_ROWNAMES[rowni];
265 while (rowname && skiprow(rowname, skipmask)) {
266 rowni = intmin(rowni + 1, NELEM(GRID_ROWNAMES)-1);
267 rowname = GRID_ROWNAMES[rowni];
268 }
269 if (!rowname) { rowname = "?"; }
270
271 for (int col = 0; col < cols; col++) {
272 snprintf(
273 p[i].name,
274 NELEM(p[0].name),
275 "%s%d",
276 rowname,
277 (col+1) % 1000
278 );
279 p[i].name[NELEM(p[0].name)-1] = '\0';
280 i++;
281 }
282 rowni = intmin(rowni + 1, NELEM(GRID_ROWNAMES)-1);
283 }
284 }
285
footag_gennames(struct footag_pad * p,int npads,int startnum,int deltanum)286 void footag_gennames(
287 struct footag_pad *p,
288 int npads,
289 int startnum,
290 int deltanum
291 )
292 {
293 for (int i = 0; i < npads; i++) {
294 unsigned int padnum = startnum + i * deltanum;
295 snprintf(
296 p->name,
297 NELEM(p->name),
298 "%u",
299 padnum % 1000
300 );
301 p->name[NELEM(p->name)-1] = '\0';
302 p++;
303 }
304 }
305
306 /* does not set w, h, translation, name, padstack */
footag_genrow(struct footag_pad * p,double addx,double addy,double pitch,int x,int y,int dx,int dy,int rows,long angle)307 void footag_genrow(
308 struct footag_pad *p,
309 double addx, double addy,
310 double pitch,
311 /* start positions */
312 int x, int y,
313 int dx, int dy,
314 int rows,
315 long angle
316 )
317 {
318 for (int i = 0; i < rows; i++) {
319 p->x = addx;
320 if (dx) {
321 p->x = footag_padypos(pitch, rows, x);
322 }
323 p->y = addy;
324 if (dy) {
325 p->y = footag_padypos(pitch, rows, y);
326 }
327 p->angle = angle;
328 x += dx;
329 y += dy;
330 p++;
331 }
332 }
333
footag_realloc_pads(struct footag_ctx * ctx,int npads)334 int footag_realloc_pads(
335 struct footag_ctx *ctx,
336 int npads
337 )
338 {
339 struct footag_pad *p;
340 p = realloc(
341 ctx->spec.pads,
342 npads * sizeof (*ctx->spec.pads)
343 );
344 if (!p) {
345 ctx->spec.npads = 0;
346 return 1;
347 }
348 if (p != ctx->spec.pads) {
349 memset(p, 0, npads * sizeof (*ctx->spec.pads));
350 }
351 ctx->spec.npads = npads;
352 ctx->spec.pads = p;
353 return 0;
354 }
355
footag_gengrid(struct footag_pad * p,double w,double h,double pitch,int rows,int cols,int prows,int pcols,enum footag_padstack stack)356 void footag_gengrid(
357 struct footag_pad *p,
358 double w, double h,
359 double pitch,
360 int rows, int cols,
361 int prows, int pcols,
362 enum footag_padstack stack
363 )
364 {
365 for (int row = 0; row < rows; row++) {
366 double y = footag_padypos(pitch, rows, rows - row - 1);
367 footag_genrow(
368 &p[row * cols],
369 0, y,
370 pitch,
371 0, 0,
372 1, 0,
373 cols,
374 FOOTAG_ANGLE_0
375 );
376 }
377
378 int i = 0;
379 for (int row = 0; row < rows; row++) {
380 for (int col = 0; col < cols; col++) {
381 p[i].w = w;
382 p[i].h = h;
383 if (
384 row < prows ||
385 col < pcols ||
386 (rows - prows) <= row ||
387 (cols - pcols) <= col
388 ) {
389 p[i].stack = stack;
390 } else {
391 p[i].stack = FOOTAG_PADSTACK_NONE;
392 }
393 i++;
394 }
395 }
396 footag_gennames(p, rows * cols, 1, 1);
397 }
398
footag_genlrow(struct footag_pad * p,double dist,double w,double h,double pitch,int npads,enum footag_padstack stack)399 void footag_genlrow(
400 struct footag_pad *p,
401 double dist,
402 double w, double h,
403 double pitch,
404 int npads,
405 enum footag_padstack stack
406 )
407 {
408 footag_genrow(
409 &p[0],
410 - dist / 2.0, 0,
411 pitch,
412 0, npads - 1,
413 0, -1,
414 npads,
415 FOOTAG_ANGLE_270
416 );
417
418 for (int i = 0; i < npads; i++) {
419 p[i].w = w;
420 p[i].h = h;
421 p[i].stack = stack;
422 }
423 footag_gennames(p, npads, 1, 1);
424 }
425
footag_genrrow(struct footag_pad * p,double dist,double w,double h,double pitch,int npads,enum footag_padstack stack)426 void footag_genrrow(
427 struct footag_pad *p,
428 double dist,
429 double w, double h,
430 double pitch,
431 int npads,
432 enum footag_padstack stack
433 )
434 {
435 footag_genrow(
436 &p[0],
437 dist / 2.0, 0,
438 pitch,
439 0, 0,
440 0, 1,
441 npads,
442 FOOTAG_ANGLE_90
443 );
444
445 for (int i = 0; i < npads; i++) {
446 p[i].w = w;
447 p[i].h = h;
448 p[i].stack = stack;
449 }
450 footag_gennames(p, npads, 1, 1);
451 }
452
footag_gentworow(struct footag_pad * p,double dist,double w,double h,double pitch,int npads,enum footag_padstack stack)453 void footag_gentworow(
454 struct footag_pad *p,
455 double dist,
456 double w, double h,
457 double pitch,
458 int npads,
459 enum footag_padstack stack
460 )
461 {
462 footag_genrow(
463 &p[0],
464 - dist / 2.0, 0,
465 pitch,
466 0, npads/2 - 1,
467 0, -1,
468 npads / 2,
469 FOOTAG_ANGLE_270
470 );
471 footag_genrow(
472 &p[npads/2],
473 dist / 2.0, 0,
474 pitch,
475 0, 0,
476 0, 1,
477 npads / 2,
478 FOOTAG_ANGLE_90
479 );
480
481 for (int i = 0; i < npads; i++) {
482 p[i].w = w;
483 p[i].h = h;
484 p[i].stack = stack;
485 }
486 footag_gennames(p, npads, 1, 1);
487 }
488
footag_genquad(struct footag_pad * p,double distrow,double wrow,double hrow,double distcol,double wcol,double hcol,double pitch,int rows,int cols,enum footag_padstack stack)489 void footag_genquad(
490 struct footag_pad *p,
491 double distrow,
492 double wrow, double hrow,
493 double distcol,
494 double wcol, double hcol,
495 double pitch,
496 int rows, int cols,
497 enum footag_padstack stack
498 )
499 {
500 footag_genrow(
501 &p[0],
502 - distrow / 2.0, 0,
503 pitch,
504 0, rows - 1,
505 0, -1,
506 rows,
507 FOOTAG_ANGLE_270
508 );
509 footag_genrow(
510 &p[rows],
511 0, - distcol / 2.0,
512 pitch,
513 0, 0,
514 1, 0,
515 cols,
516 FOOTAG_ANGLE_0
517 );
518 footag_genrow(
519 &p[rows + cols],
520 distrow / 2.0, 0,
521 pitch,
522 0, 0,
523 0, 1,
524 rows,
525 FOOTAG_ANGLE_90
526 );
527 footag_genrow(
528 &p[rows + cols + rows],
529 0, distcol / 2.0,
530 pitch,
531 cols - 1, 0,
532 -1, 0,
533 cols,
534 FOOTAG_ANGLE_180
535 );
536
537 for (int i = 0; i < rows; i++) {
538 p[i].w = wrow;
539 p[i].h = hrow;
540 p[i].stack = stack;
541 }
542 for (int i = rows; i < rows + cols; i++) {
543 p[i].w = wcol;
544 p[i].h = hcol;
545 p[i].stack = stack;
546 }
547 for (int i = rows + cols; i < rows + cols + rows; i++) {
548 p[i].w = wrow;
549 p[i].h = hrow;
550 p[i].stack = stack;
551 }
552 for (int i = rows + cols + rows; i < rows + cols + rows + cols; i++) {
553 p[i].w = wcol;
554 p[i].h = hcol;
555 p[i].stack = stack;
556 }
557 footag_gennames(p, 2 * (cols + rows), 1, 1);
558 }
559
footag_gentwopin(struct footag_pad * pads,double dist,double w,double h,enum footag_padstack stack)560 void footag_gentwopin(
561 struct footag_pad *pads,
562 double dist,
563 double w, double h,
564 enum footag_padstack stack
565 )
566 {
567 pads[0].stack = pads[1].stack = stack;
568 pads[0].x = - dist / 2.0;
569 pads[1].x = dist / 2.0;
570 pads[0].y = pads[1].y = 0;
571 pads[0].w = pads[1].w = w;
572 pads[0].h = pads[1].h = h;
573 pads[0].angle = FOOTAG_ANGLE_270;
574 pads[1].angle = FOOTAG_ANGLE_90;
575 pads[0].name[0] = '1';
576 pads[0].name[1] = '\0';
577 pads[1].name[0] = '2';
578 pads[1].name[1] = '\0';
579 }
580
footag_ipc7351b_setrrectpad(struct footag_pad * p)581 void footag_ipc7351b_setrrectpad(struct footag_pad *p)
582 {
583 if (p->stack == FOOTAG_PADSTACK_SMD_RRECT) {
584 double radius = fmin(p->w, p->h) / 5.0;
585 radius = fmin(radius, 0.25);
586 p->param = radius;
587 }
588 }
589
footag_ipc7351b_setrrectpads(const struct footag_spec * s)590 void footag_ipc7351b_setrrectpads(const struct footag_spec *s)
591 {
592 for (int i = 0; i < s->npads; i++) {
593 footag_ipc7351b_setrrectpad(&s->pads[i]);
594 }
595 }
596
footag_snap(struct footag_spec * s,double grid)597 void footag_snap(
598 struct footag_spec *s, double grid
599 )
600 {
601 if (!grid) { return; }
602 for (int i = 0; i < s->npads; i++) {
603 struct footag_pad *p = &s->pads[i];
604 p->x = snap(p->x, grid);
605 p->y = snap(p->y, grid);
606 p->w = snap(p->w, grid);
607 p->h = snap(p->h, grid);
608 p->diam = snap(p->diam, grid);
609 p->holediam = snap(p->holediam, grid);
610 p->param = snap(p->param, grid);
611 }
612 s->body.minx = snap(s->body.minx, grid);
613 s->body.maxx = snap(s->body.maxx, grid);
614 s->body.miny = snap(s->body.miny, grid);
615 s->body.maxy = snap(s->body.maxy, grid);
616 }
617
footag_setcourtyard(struct footag_spec * s,double cyexc)618 void footag_setcourtyard(
619 struct footag_spec *s,
620 double cyexc
621 )
622 {
623 /* pads and outline is now at its final (rounded) value */
624 s->courtyard = s->body;
625 /* determine theoretical courtyard */
626 for (int i = 0; i < s->npads; i++) {
627 struct footag_pad *p = &s->pads[i];
628 double w = p->w;
629 double h = p->h;
630 if (p->angle == FOOTAG_ANGLE_90 || p->angle == FOOTAG_ANGLE_270) {
631 w = p->h;
632 h = p->w;
633 }
634 double xadd = fmax(w, p->diam) / 2;
635 s->courtyard.maxx = fmax(s->courtyard.maxx, p->x + xadd);
636 s->courtyard.minx = fmin(s->courtyard.minx, p->x - xadd);
637 double yadd = fmax(h, p->diam) / 2;
638 s->courtyard.maxy = fmax(s->courtyard.maxy, p->y + yadd);
639 s->courtyard.miny = fmin(s->courtyard.miny, p->y - yadd);
640 }
641 /* add courtyard excess */
642 s->courtyard.maxx += cyexc;
643 s->courtyard.minx -= cyexc;
644 s->courtyard.maxy += cyexc;
645 s->courtyard.miny -= cyexc;
646 /* (round it) */
647 }
648
649