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