4 * PCB, interactive printed circuit board design
5 * Copyright (C) 2004, 2007 Dan McMahill
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
39 #ifdef HAVE_SYS_TYPES_H
40 #include <sys/types.h>
61 #ifdef HAVE_LIBDMALLOC
65 static void add_to_drills (char *);
66 static void apply_vendor_map (void);
67 static void process_skips (Resource
*);
68 static bool rematch (const char *, const char *);
70 /* list of vendor drills and a count of them */
71 static int *vendor_drills
= NULL
;
72 static int n_vendor_drills
= 0;
74 static int cached_drill
= -1;
75 static int cached_map
= -1;
77 /* lists of elements to ignore */
78 static char **ignore_refdes
= NULL
;
79 static int n_refdes
= 0;
80 static char **ignore_value
= NULL
;
81 static int n_value
= 0;
82 static char **ignore_descr
= NULL
;
83 static int n_descr
= 0;
86 static char *vendor_name
= NULL
;
88 /* resource file to PCB units scale factor */
92 /* enable/disable mapping */
93 static bool vendorMapEnable
= false;
95 /* type of drill mapping */
98 static int rounding_method
= ROUND_UP
;
100 #define FREE(x) if((x) != NULL) { free (x) ; (x) = NULL; }
102 /* ************************************************************ */
104 static const char apply_vendor_syntax
[] = "ApplyVendor()";
106 static const char apply_vendor_help
[] =
107 "Applies the currently loaded vendor drill table to the current design.";
109 /* %start-doc actions ApplyVendor
111 @cindex vendor drill table
112 @findex ApplyVendor()
114 This will modify all of your drill holes to match the list of allowed
115 sizes for your vendor.
119 ActionApplyVendor (int argc
, char **argv
, Coord x
, Coord y
)
126 /* ************************************************************ */
128 static const char toggle_vendor_syntax
[] = "ToggleVendor()";
130 static const char toggle_vendor_help
[] =
131 "Toggles the state of automatic drill size mapping.";
133 /* %start-doc actions ToggleVendor
136 @cindex vendor drill table
137 @findex ToggleVendor()
139 When drill mapping is enabled, new instances of pins and vias will
140 have their drill holes mapped to one of the allowed drill sizes
141 specified in the currently loaded vendor drill table. To enable drill
142 mapping, a vendor resource file containing a drill table must be
148 ActionToggleVendor (int argc
, char **argv
, Coord x
, Coord y
)
151 vendorMapEnable
= false;
153 vendorMapEnable
= true;
157 /* ************************************************************ */
159 static const char enable_vendor_syntax
[] = "EnableVendor()";
161 static const char enable_vendor_help
[] =
162 "Enables automatic drill size mapping.";
164 /* %start-doc actions EnableVendor
167 @cindex vendor drill table
168 @findex EnableVendor()
170 When drill mapping is enabled, new instances of pins and vias will
171 have their drill holes mapped to one of the allowed drill sizes
172 specified in the currently loaded vendor drill table. To enable drill
173 mapping, a vendor resource file containing a drill table must be
179 ActionEnableVendor (int argc
, char **argv
, Coord x
, Coord y
)
181 vendorMapEnable
= true;
185 /* ************************************************************ */
187 static const char disable_vendor_syntax
[] = "DisableVendor()";
189 static const char disable_vendor_help
[] =
190 "Disables automatic drill size mapping.";
192 /* %start-doc actions DisableVendor
195 @cindex vendor drill table
196 @findex DisableVendor()
198 When drill mapping is enabled, new instances of pins and vias will
199 have their drill holes mapped to one of the allowed drill sizes
200 specified in the currently loaded vendor drill table.
205 ActionDisableVendor (int argc
, char **argv
, Coord x
, Coord y
)
207 vendorMapEnable
= false;
211 /* ************************************************************ */
213 static const char unload_vendor_syntax
[] = "UnloadVendor()";
215 static const char unload_vendor_help
[] =
216 "Unloads the current vendor drill mapping table.";
218 /* %start-doc actions UnloadVendor
221 @cindex vendor drill table
222 @findex UnloadVendor()
227 ActionUnloadVendor (int argc
, char **argv
, Coord x
, Coord y
)
231 /* Unload any vendor table we may have had */
236 FREE (vendor_drills
);
237 FREE (ignore_refdes
);
243 /* ************************************************************ */
245 static const char load_vendor_syntax
[] = "LoadVendorFrom(filename)";
247 static const char load_vendor_help
[] =
248 "Loads the specified vendor resource file.";
250 /* %start-doc actions LoadVendorFrom
253 @cindex vendor drill table
254 @findex LoadVendorFrom()
258 Name of the vendor resource file. If not specified, the user will
259 be prompted to enter one.
265 ActionLoadVendorFrom (int argc
, char **argv
, Coord x
, Coord y
)
269 static char *default_file
= NULL
;
271 Resource
*res
, *drcres
, *drlres
;
273 bool free_fname
= false;
277 fname
= argc
? argv
[0] : 0;
279 if (!fname
|| !*fname
)
281 fname
= gui
->fileselect (_("Load Vendor Resource File..."),
282 _("Picks a vendor resource file to load.\n"
283 "This file can contain drc settings for a\n"
284 "particular vendor as well as a list of\n"
285 "predefined drills which are allowed."),
286 default_file
, ".res", "vendor",
287 HID_FILESELECT_READ
);
297 default_file
= strdup (fname
);
300 /* Unload any vendor table we may have had */
305 FREE (vendor_drills
);
306 FREE (ignore_refdes
);
311 /* load the resource file */
312 res
= resource_parse (fname
, NULL
);
315 Message (_("Could not load vendor resource file \"%s\"\n"), fname
);
319 /* figure out the vendor name, if specified */
320 vendor_name
= (char *)UNKNOWN (resource_value (res
, "vendor"));
322 /* figure out the units, if specified */
323 sval
= resource_value (res
, "units");
326 sf
= MIL_TO_COORD(1);
328 else if ((NSTRCMP (sval
, "mil") == 0) || (NSTRCMP (sval
, "mils") == 0))
330 sf
= MIL_TO_COORD(1);
332 else if ((NSTRCMP (sval
, "inch") == 0) || (NSTRCMP (sval
, "inches") == 0))
334 sf
= INCH_TO_COORD(1);
336 else if (NSTRCMP (sval
, "mm") == 0)
342 Message ("\"%s\" is not a supported units. Defaulting to inch\n",
344 sf
= INCH_TO_COORD(1);
348 /* default to ROUND_UP */
349 rounding_method
= ROUND_UP
;
351 /* extract the drillmap resource */
352 drlres
= resource_subres (res
, "drillmap");
355 Message (_("No drillmap resource found\n"));
359 sval
= resource_value (drlres
, "round");
362 if (NSTRCMP (sval
, "up") == 0)
364 rounding_method
= ROUND_UP
;
366 else if (NSTRCMP (sval
, "nearest") == 0)
368 rounding_method
= CLOSEST
;
373 ("\"%s\" is not a valid rounding type. Defaulting to up\n"),
375 rounding_method
= ROUND_UP
;
379 process_skips (resource_subres (drlres
, "skips"));
381 for (i
= 0; i
< drlres
->c
; i
++)
383 type
= resource_type (drlres
->v
[i
]);
388 add_to_drills (drlres
->v
[i
].value
);
397 /* Extract the DRC resource */
398 drcres
= resource_subres (res
, "drc");
400 sval
= resource_value (drcres
, "copper_space");
403 PCB
->Bloat
= floor (sf
* atof (sval
) + 0.5);
404 Message (_("Set DRC minimum copper spacing to %.2f mils\n"),
408 sval
= resource_value (drcres
, "copper_overlap");
411 PCB
->Shrink
= floor (sf
* atof (sval
) + 0.5);
412 Message (_("Set DRC minimum copper overlap to %.2f mils\n"),
416 sval
= resource_value (drcres
, "copper_width");
419 PCB
->minWid
= floor (sf
* atof (sval
) + 0.5);
420 Message (_("Set DRC minimum copper spacing to %.2f mils\n"),
424 sval
= resource_value (drcres
, "silk_width");
427 PCB
->minSlk
= floor (sf
* atof (sval
) + 0.5);
428 Message (_("Set DRC minimum silk width to %.2f mils\n"),
432 sval
= resource_value (drcres
, "min_drill");
435 PCB
->minDrill
= floor (sf
* atof (sval
) + 0.5);
436 Message (_("Set DRC minimum drill diameter to %.2f mils\n"),
437 0.01 * PCB
->minDrill
);
440 sval
= resource_value (drcres
, "min_ring");
443 PCB
->minRing
= floor (sf
* atof (sval
) + 0.5);
444 Message (_("Set DRC minimum annular ring to %.2f mils\n"),
445 0.01 * PCB
->minRing
);
448 Message (_("Loaded %d vendor drills from %s\n"), n_vendor_drills
, fname
);
449 Message (_("Loaded %d RefDes skips, %d Value skips, %d Descr skips\n"),
450 n_refdes
, n_value
, n_descr
);
452 vendorMapEnable
= true;
460 apply_vendor_map (void)
466 state
= vendorMapEnable
;
469 vendorMapEnable
= true;
471 /* reset our counts */
475 /* If we have loaded vendor drills, then apply them to the design */
476 if (n_vendor_drills
> 0)
479 /* first all the vias */
480 VIA_LOOP (PCB
->Data
);
483 if (via
->DrillingHole
!= vendorDrillMap (via
->DrillingHole
))
485 /* only change unlocked vias */
486 if (!TEST_FLAG (LOCKFLAG
, via
))
488 if (ChangeObject2ndSize (VIA_TYPE
, via
, NULL
, NULL
,
489 vendorDrillMap (via
->DrillingHole
),
495 ("Via at %.2f, %.2f not changed. Possible reasons:\n"
496 "\t- pad size too small\n"
497 "\t- new size would be too large or too small\n"),
498 0.01 * via
->X
, 0.01 * via
->Y
);
503 Message (_("Locked via at %.2f, %.2f not changed.\n"),
504 0.01 * via
->X
, 0.01 * via
->Y
);
510 /* and now the pins */
511 ELEMENT_LOOP (PCB
->Data
);
514 * first figure out if this element should be skipped for some
517 if (vendorIsElementMappable (element
))
519 /* the element is ok to modify, so iterate over its pins */
523 if (pin
->DrillingHole
!= vendorDrillMap (pin
->DrillingHole
))
525 if (!TEST_FLAG (LOCKFLAG
, pin
))
527 if (ChangeObject2ndSize (PIN_TYPE
, element
, pin
, NULL
,
528 vendorDrillMap (pin
->
535 ("Pin %s (%s) at %.2f, %.2f (element %s, %s, %s) not changed.\n"
536 "\tPossible reasons:\n"
537 "\t- pad size too small\n"
538 "\t- new size would be too large or too small\n"),
539 UNKNOWN (pin
->Number
), UNKNOWN (pin
->Name
),
540 0.01 * pin
->X
, 0.01 * pin
->Y
,
541 UNKNOWN (NAMEONPCB_NAME (element
)),
542 UNKNOWN (VALUE_NAME (element
)),
543 UNKNOWN (DESCRIPTION_NAME (element
)));
549 ("Locked pin at %-6.2f, %-6.2f not changed.\n"),
550 0.01 * pin
->X
, 0.01 * pin
->Y
);
559 Message (_("Updated %d drill sizes out of %d total\n"), changed
, tot
);
561 /* Update the current Via */
562 if (Settings
.ViaDrillingHole
!=
563 vendorDrillMap (Settings
.ViaDrillingHole
))
566 Settings
.ViaDrillingHole
=
567 vendorDrillMap (Settings
.ViaDrillingHole
);
568 Message (_("Adjusted active via hole size to be %6.2f mils\n"),
569 0.01 * Settings
.ViaDrillingHole
);
572 /* and update the vias for the various routing styles */
573 for (i
= 0; i
< NUM_STYLES
; i
++)
575 if (PCB
->RouteStyle
[i
].Hole
!=
576 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
))
579 PCB
->RouteStyle
[i
].Hole
=
580 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
);
582 ("Adjusted %s routing style via hole size to be %6.2f mils\n"),
583 PCB
->RouteStyle
[i
].Name
,
584 0.01 * PCB
->RouteStyle
[i
].Hole
);
585 if (PCB
->RouteStyle
[i
].Diameter
<
586 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
)
588 PCB
->RouteStyle
[i
].Diameter
=
589 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
;
591 ("Increased %s routing style via diameter to %6.2f mils\n"),
592 PCB
->RouteStyle
[i
].Name
,
593 0.01 * PCB
->RouteStyle
[i
].Diameter
);
599 * if we've changed anything, indicate that we need to save the
600 * file, redraw things, and make sure we can undo.
604 SetChangedFlag (true);
606 IncrementUndoSerialNumber ();
610 /* restore mapping on/off */
611 vendorMapEnable
= state
;
614 /* for a given drill size, find the closest vendor drill size */
616 vendorDrillMap (int in
)
620 if (in
== cached_drill
)
624 /* skip the mapping if we don't have a vendor drill table */
625 if ((n_vendor_drills
== 0) || (vendor_drills
== NULL
)
626 || (vendorMapEnable
== false))
632 /* are we smaller than the smallest drill? */
633 if (in
<= vendor_drills
[0])
635 cached_map
= vendor_drills
[0];
636 return vendor_drills
[0];
639 /* are we larger than the largest drill? */
640 if (in
> vendor_drills
[n_vendor_drills
- 1])
642 Message (_("Vendor drill list does not contain a drill >= %6.2f mil\n"
643 "Using %6.2f mil instead.\n"),
644 0.01 * in
, 0.01 * vendor_drills
[n_vendor_drills
- 1]);
645 cached_map
= vendor_drills
[n_vendor_drills
- 1];
646 return vendor_drills
[n_vendor_drills
- 1];
649 /* figure out which 2 drills are closest in size */
651 max
= n_vendor_drills
- 1;
652 while (max
- min
> 1)
655 if (in
> vendor_drills
[i
])
662 /* now round per the rounding mode */
663 if (rounding_method
== CLOSEST
)
665 /* find the closest drill size */
666 if ((in
- vendor_drills
[i
- 1]) > (vendor_drills
[i
] - in
))
668 cached_map
= vendor_drills
[i
];
669 return vendor_drills
[i
];
673 cached_map
= vendor_drills
[i
- 1];
674 return vendor_drills
[i
- 1];
679 /* always round up */
680 cached_map
= vendor_drills
[i
];
681 return vendor_drills
[i
];
686 /* add a drill size to the vendor drill list */
688 add_to_drills (char *sval
)
694 /* increment the count and make sure we have memory */
696 if ((vendor_drills
= (int *)realloc (vendor_drills
,
697 n_vendor_drills
* sizeof (int))) == NULL
)
699 fprintf (stderr
, "realloc() failed to allocate %ld bytes\n",
700 (unsigned long) n_vendor_drills
* sizeof (int));
704 /* string to a value with the units scale factor in place */
706 val
= floor (sf
* tmpd
+ 0.5);
709 * We keep the array of vendor drills sorted to make it easier to
710 * do the rounding later. The algorithm used here is not so efficient,
711 * but we're not dealing with much in the way of data.
714 /* figure out where to insert the value to keep the array sorted. */
716 while ((k
< n_vendor_drills
- 1) && (vendor_drills
[k
] < val
))
719 if (k
== n_vendor_drills
- 1)
721 vendor_drills
[n_vendor_drills
- 1] = val
;
725 /* move up the existing drills to make room */
726 for (j
= n_vendor_drills
- 1; j
> k
; j
--)
728 vendor_drills
[j
] = vendor_drills
[j
- 1];
731 vendor_drills
[k
] = val
;
735 /* deal with the "skip" subresource */
737 process_skips (Resource
* res
)
748 for (i
= 0; i
< res
->c
; i
++)
750 type
= resource_type (res
->v
[i
]);
755 * an unnamed sub resource. This is something like
758 sval
= res
->v
[i
].subres
->v
[0].value
;
761 Message ("Error: null skip value\n");
765 if (NSTRCMP (sval
, "refdes") == 0)
768 lst
= &ignore_refdes
;
770 else if (NSTRCMP (sval
, "value") == 0)
775 else if (NSTRCMP (sval
, "descr") == 0)
785 /* add the entry to the appropriate list */
788 for (k
= 1; k
< res
->v
[i
].subres
->c
; k
++)
790 sval
= res
->v
[i
].subres
->v
[k
].value
;
793 (char **) realloc (*lst
,
794 (*cnt
) * sizeof (char *))) ==
797 fprintf (stderr
, "realloc() failed\n");
800 (*lst
)[*cnt
- 1] = strdup (sval
);
807 Message (_("Ignored resource type = %d in skips= section\n"), type
);
814 vendorIsElementMappable (ElementType
*element
)
819 if (vendorMapEnable
== false)
823 for (i
= 0; i
< n_refdes
; i
++)
825 if ((NSTRCMP (UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]) ==
827 || rematch (ignore_refdes
[i
], UNKNOWN (NAMEONPCB_NAME (element
))))
830 ("Vendor mapping skipped because refdes = %s matches %s\n"),
831 UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]);
836 for (i
= 0; i
< n_value
; i
++)
838 if ((NSTRCMP (UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]) == 0)
839 || rematch (ignore_value
[i
], UNKNOWN (VALUE_NAME (element
))))
842 ("Vendor mapping skipped because value = %s matches %s\n"),
843 UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]);
849 for (i
= 0; i
< n_descr
; i
++)
851 if ((NSTRCMP (UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
])
853 || rematch (ignore_descr
[i
],
854 UNKNOWN (DESCRIPTION_NAME (element
))))
857 ("Vendor mapping skipped because descr = %s matches %s\n"),
858 UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
]);
863 if (noskip
&& TEST_FLAG (LOCKFLAG
, element
))
865 Message (_("Vendor mapping skipped because element %s is locked\n"),
866 UNKNOWN (NAMEONPCB_NAME (element
)));
877 rematch (const char *re
, const char *s
)
880 * If this system has regular expression capability, then
881 * add support for regular expressions in the skip lists.
884 #if defined(HAVE_REGCOMP)
890 /* compile the regular expression */
891 result
= regcomp (&compiled
, re
, REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
894 char errorstring
[128];
896 regerror (result
, &compiled
, errorstring
, sizeof (errorstring
));
897 Message ("regexp error: %s\n", errorstring
);
902 result
= regexec (&compiled
, s
, 1, &match
, 0);
910 #elif defined(HAVE_RE_COMP)
914 /* compile the regular expression */
915 if ((rslt
= re_comp (re
)) != NULL
)
917 Message ("re_comp error: %s\n", rslt
);
934 Message ("re_exec error\n");
944 HID_Action vendor_action_list
[] = {
945 {"ApplyVendor", 0, ActionApplyVendor
,
946 apply_vendor_help
, apply_vendor_syntax
}
948 {"ToggleVendor", 0, ActionToggleVendor
,
949 toggle_vendor_help
, toggle_vendor_syntax
}
951 {"EnableVendor", 0, ActionEnableVendor
,
952 enable_vendor_help
, enable_vendor_syntax
}
954 {"DisableVendor", 0, ActionDisableVendor
,
955 disable_vendor_help
, disable_vendor_syntax
}
957 {"UnloadVendor", 0, ActionUnloadVendor
,
958 unload_vendor_help
, unload_vendor_syntax
}
960 {"LoadVendorFrom", 0, ActionLoadVendorFrom
,
961 load_vendor_help
, load_vendor_syntax
}
964 REGISTER_ACTIONS (vendor_action_list
)
966 static int vendor_get_enabled (void *data
)
968 return vendorMapEnable
;
971 HID_Flag vendor_flag_list
[] = {
972 {"VendorMapOn", vendor_get_enabled
, NULL
}
975 REGISTER_FLAGS (vendor_flag_list
)