6 * PCB, interactive printed circuit board design
7 * Copyright (C) 2004, 2007 Dan McMahill
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h>
63 #ifdef HAVE_LIBDMALLOC
69 static void add_to_drills (char *);
70 static void apply_vendor_map (void);
71 static void process_skips (Resource
*);
72 static bool rematch (const char *, const char *);
74 /* list of vendor drills and a count of them */
75 static int *vendor_drills
= NULL
;
76 static int n_vendor_drills
= 0;
78 static int cached_drill
= -1;
79 static int cached_map
= -1;
81 /* lists of elements to ignore */
82 static char **ignore_refdes
= NULL
;
83 static int n_refdes
= 0;
84 static char **ignore_value
= NULL
;
85 static int n_value
= 0;
86 static char **ignore_descr
= NULL
;
87 static int n_descr
= 0;
90 static char *vendor_name
= NULL
;
92 /* resource file to PCB units scale factor */
96 /* enable/disable mapping */
97 static bool vendorMapEnable
= false;
99 /* type of drill mapping */
102 static int rounding_method
= ROUND_UP
;
104 #define FREE(x) if((x) != NULL) { free (x) ; (x) = NULL; }
106 /* ************************************************************ */
108 static const char apply_vendor_syntax
[] = "ApplyVendor()";
110 static const char apply_vendor_help
[] =
111 "Applies the currently loaded vendor drill table to the current design.";
113 /* %start-doc actions ApplyVendor
115 @cindex vendor drill table
116 @findex ApplyVendor()
118 This will modify all of your drill holes to match the list of allowed
119 sizes for your vendor.
123 ActionApplyVendor (int argc
, char **argv
, int x
, int y
)
130 /* ************************************************************ */
132 static const char toggle_vendor_syntax
[] = "ToggleVendor()";
134 static const char toggle_vendor_help
[] =
135 "Toggles the state of automatic drill size mapping.";
137 /* %start-doc actions ToggleVendor
140 @cindex vendor drill table
141 @findex ToggleVendor()
143 When drill mapping is enabled, new instances of pins and vias will
144 have their drill holes mapped to one of the allowed drill sizes
145 specified in the currently loaded vendor drill table. To enable drill
146 mapping, a vendor resource file containing a drill table must be
152 ActionToggleVendor (int argc
, char **argv
, int x
, int y
)
155 vendorMapEnable
= false;
157 vendorMapEnable
= true;
161 /* ************************************************************ */
163 static const char enable_vendor_syntax
[] = "EnableVendor()";
165 static const char enable_vendor_help
[] =
166 "Enables automatic drill size mapping.";
168 /* %start-doc actions EnableVendor
171 @cindex vendor drill table
172 @findex EnableVendor()
174 When drill mapping is enabled, new instances of pins and vias will
175 have their drill holes mapped to one of the allowed drill sizes
176 specified in the currently loaded vendor drill table. To enable drill
177 mapping, a vendor resource file containing a drill table must be
183 ActionEnableVendor (int argc
, char **argv
, int x
, int y
)
185 vendorMapEnable
= true;
189 /* ************************************************************ */
191 static const char disable_vendor_syntax
[] = "DisableVendor()";
193 static const char disable_vendor_help
[] =
194 "Disables automatic drill size mapping.";
196 /* %start-doc actions DisableVendor
199 @cindex vendor drill table
200 @findex DisableVendor()
202 When drill mapping is enabled, new instances of pins and vias will
203 have their drill holes mapped to one of the allowed drill sizes
204 specified in the currently loaded vendor drill table.
209 ActionDisableVendor (int argc
, char **argv
, int x
, int y
)
211 vendorMapEnable
= false;
215 /* ************************************************************ */
217 static const char unload_vendor_syntax
[] = "UnloadVendor()";
219 static const char unload_vendor_help
[] =
220 "Unloads the current vendor drill mapping table.";
222 /* %start-doc actions UnloadVendor
225 @cindex vendor drill table
226 @findex UnloadVendor()
231 ActionUnloadVendor (int argc
, char **argv
, int x
, int y
)
235 /* Unload any vendor table we may have had */
240 FREE (vendor_drills
);
241 FREE (ignore_refdes
);
247 /* ************************************************************ */
249 static const char load_vendor_syntax
[] = "LoadVendorFrom(filename)";
251 static const char load_vendor_help
[] =
252 "Loads the specified vendor resource file.";
254 /* %start-doc actions LoadVendorFrom
257 @cindex vendor drill table
258 @findex LoadVendorFrom()
262 Name of the vendor resource file. If not specified, the user will
263 be prompted to enter one.
269 ActionLoadVendorFrom (int argc
, char **argv
, int x
, int y
)
272 char *fname
= NULL
, *name
= NULL
;
273 static char *default_file
= NULL
;
275 Resource
*res
, *drcres
, *drlres
;
280 fname
= argc
? argv
[0] : 0;
282 if (!fname
|| !*fname
)
284 fname
= gui
->fileselect (_("Load Vendor Resource File..."),
285 _("Picks a vendor resource file to load.\n"
286 "This file can contain drc settings for a\n"
287 "particular vendor as well as a list of\n"
288 "predefined drills which are allowed."),
289 default_file
, ".res", "vendor",
290 HID_FILESELECT_READ
);
294 if (default_file
!= NULL
)
301 default_file
= strdup (fname
);
304 /* Unload any vendor table we may have had */
309 FREE (vendor_drills
);
310 FREE (ignore_refdes
);
315 /* load the resource file */
316 res
= resource_parse (fname
, NULL
);
319 Message (_("Could not load vendor resource file \"%s\"\n"), fname
);
323 /* figure out the vendor name, if specified */
324 vendor_name
= UNKNOWN (resource_value (res
, "vendor"));
326 /* figure out the units, if specified */
327 sval
= resource_value (res
, "units");
332 else if ((NSTRCMP (sval
, "mil") == 0) || (NSTRCMP (sval
, "mils") == 0))
336 else if ((NSTRCMP (sval
, "inch") == 0) || (NSTRCMP (sval
, "inches") == 0))
340 else if (NSTRCMP (sval
, "mm") == 0)
343 * divide by .0254 to convert mm to mils. Then multiply by 100
346 sf
= (100.0 / 0.0254);
350 Message ("\"%s\" is not a supported units. Defaulting to inch\n",
356 /* default to ROUND_UP */
357 rounding_method
= ROUND_UP
;
359 /* extract the drillmap resource */
360 drlres
= resource_subres (res
, "drillmap");
363 Message (_("No drillmap resource found\n"));
367 sval
= resource_value (drlres
, "round");
370 if (NSTRCMP (sval
, "up") == 0)
372 rounding_method
= ROUND_UP
;
374 else if (NSTRCMP (sval
, "nearest") == 0)
376 rounding_method
= CLOSEST
;
381 ("\"%s\" is not a valid rounding type. Defaulting to up\n"),
383 rounding_method
= ROUND_UP
;
387 process_skips (resource_subres (drlres
, "skips"));
389 for (i
= 0; i
< drlres
->c
; i
++)
391 type
= resource_type (drlres
->v
[i
]);
396 add_to_drills (drlres
->v
[i
].value
);
405 /* Extract the DRC resource */
406 drcres
= resource_subres (res
, "drc");
408 sval
= resource_value (drcres
, "copper_space");
411 PCB
->Bloat
= floor (sf
* atof (sval
) + 0.5);
412 Message (_("Set DRC minimum copper spacing to %.2f mils\n"),
416 sval
= resource_value (drcres
, "copper_overlap");
419 PCB
->Shrink
= floor (sf
* atof (sval
) + 0.5);
420 Message (_("Set DRC minimum copper overlap to %.2f mils\n"),
424 sval
= resource_value (drcres
, "copper_width");
427 PCB
->minWid
= floor (sf
* atof (sval
) + 0.5);
428 Message (_("Set DRC minimum copper spacing to %.2f mils\n"),
432 sval
= resource_value (drcres
, "silk_width");
435 PCB
->minSlk
= floor (sf
* atof (sval
) + 0.5);
436 Message (_("Set DRC minimum silk width to %.2f mils\n"),
440 sval
= resource_value (drcres
, "min_drill");
443 PCB
->minDrill
= floor (sf
* atof (sval
) + 0.5);
444 Message (_("Set DRC minimum drill diameter to %.2f mils\n"),
445 0.01 * PCB
->minDrill
);
448 sval
= resource_value (drcres
, "min_ring");
451 PCB
->minRing
= floor (sf
* atof (sval
) + 0.5);
452 Message (_("Set DRC minimum annular ring to %.2f mils\n"),
453 0.01 * PCB
->minRing
);
456 Message (_("Loaded %d vendor drills from %s\n"), n_vendor_drills
, fname
);
457 Message (_("Loaded %d RefDes skips, %d Value skips, %d Descr skips\n"),
458 n_refdes
, n_value
, n_descr
);
460 vendorMapEnable
= true;
467 apply_vendor_map (void)
473 state
= vendorMapEnable
;
476 vendorMapEnable
= true;
478 /* reset our counts */
482 /* If we have loaded vendor drills, then apply them to the design */
483 if (n_vendor_drills
> 0)
486 /* first all the vias */
487 VIA_LOOP (PCB
->Data
);
490 if (via
->DrillingHole
!= vendorDrillMap (via
->DrillingHole
))
492 /* only change unlocked vias */
493 if (!TEST_FLAG (LOCKFLAG
, via
))
495 if (ChangeObject2ndSize (VIA_TYPE
, via
, NULL
, NULL
,
496 vendorDrillMap (via
->DrillingHole
),
502 ("Via at %.2f, %.2f not changed. Possible reasons:\n"
503 "\t- pad size too small\n"
504 "\t- new size would be too large or too small\n"),
505 0.01 * via
->X
, 0.01 * via
->Y
);
510 Message (_("Locked via at %.2f, %.2f not changed.\n"),
511 0.01 * via
->X
, 0.01 * via
->Y
);
517 /* and now the pins */
518 ELEMENT_LOOP (PCB
->Data
);
521 * first figure out if this element should be skipped for some
524 if (vendorIsElementMappable (element
))
526 /* the element is ok to modify, so iterate over its pins */
530 if (pin
->DrillingHole
!= vendorDrillMap (pin
->DrillingHole
))
532 if (!TEST_FLAG (LOCKFLAG
, pin
))
534 if (ChangeObject2ndSize (PIN_TYPE
, element
, pin
, NULL
,
535 vendorDrillMap (pin
->
542 ("Pin %s (%s) at %.2f, %.2f (element %s, %s, %s) not changed.\n"
543 "\tPossible reasons:\n"
544 "\t- pad size too small\n"
545 "\t- new size would be too large or too small\n"),
546 UNKNOWN (pin
->Number
), UNKNOWN (pin
->Name
),
547 0.01 * pin
->X
, 0.01 * pin
->Y
,
548 UNKNOWN (NAMEONPCB_NAME (element
)),
549 UNKNOWN (VALUE_NAME (element
)),
550 UNKNOWN (DESCRIPTION_NAME (element
)));
556 ("Locked pin at %-6.2f, %-6.2f not changed.\n"),
557 0.01 * pin
->X
, 0.01 * pin
->Y
);
566 Message (_("Updated %d drill sizes out of %d total\n"), changed
, tot
);
568 /* Update the current Via */
569 if (Settings
.ViaDrillingHole
!=
570 vendorDrillMap (Settings
.ViaDrillingHole
))
573 Settings
.ViaDrillingHole
=
574 vendorDrillMap (Settings
.ViaDrillingHole
);
575 Message (_("Adjusted active via hole size to be %6.2f mils\n"),
576 0.01 * Settings
.ViaDrillingHole
);
579 /* and update the vias for the various routing styles */
580 for (i
= 0; i
< NUM_STYLES
; i
++)
582 if (PCB
->RouteStyle
[i
].Hole
!=
583 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
))
586 PCB
->RouteStyle
[i
].Hole
=
587 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
);
589 ("Adjusted %s routing style via hole size to be %6.2f mils\n"),
590 PCB
->RouteStyle
[i
].Name
,
591 0.01 * PCB
->RouteStyle
[i
].Hole
);
592 if (PCB
->RouteStyle
[i
].Diameter
<
593 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
)
595 PCB
->RouteStyle
[i
].Diameter
=
596 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
;
598 ("Increased %s routing style via diameter to %6.2f mils\n"),
599 PCB
->RouteStyle
[i
].Name
,
600 0.01 * PCB
->RouteStyle
[i
].Diameter
);
606 * if we've changed anything, indicate that we need to save the
607 * file, redraw things, and make sure we can undo.
611 SetChangedFlag (true);
612 ClearAndRedrawOutput ();
613 IncrementUndoSerialNumber ();
617 /* restore mapping on/off */
618 vendorMapEnable
= state
;
621 /* for a given drill size, find the closest vendor drill size */
623 vendorDrillMap (int in
)
627 if (in
== cached_drill
)
631 /* skip the mapping if we don't have a vendor drill table */
632 if ((n_vendor_drills
== 0) || (vendor_drills
== NULL
)
633 || (vendorMapEnable
== false))
639 /* are we smaller than the smallest drill? */
640 if (in
<= vendor_drills
[0])
642 cached_map
= vendor_drills
[0];
643 return vendor_drills
[0];
646 /* are we larger than the largest drill? */
647 if (in
> vendor_drills
[n_vendor_drills
- 1])
649 Message (_("Vendor drill list does not contain a drill >= %6.2f mil\n"
650 "Using %6.2f mil instead.\n"),
651 0.01 * in
, 0.01 * vendor_drills
[n_vendor_drills
- 1]);
652 cached_map
= vendor_drills
[n_vendor_drills
- 1];
653 return vendor_drills
[n_vendor_drills
- 1];
656 /* figure out which 2 drills are closest in size */
658 max
= n_vendor_drills
- 1;
659 while (max
- min
> 1)
662 if (in
> vendor_drills
[i
])
669 /* now round per the rounding mode */
670 if (rounding_method
== CLOSEST
)
672 /* find the closest drill size */
673 if ((in
- vendor_drills
[i
- 1]) > (vendor_drills
[i
] - in
))
675 cached_map
= vendor_drills
[i
];
676 return vendor_drills
[i
];
680 cached_map
= vendor_drills
[i
- 1];
681 return vendor_drills
[i
- 1];
686 /* always round up */
687 cached_map
= vendor_drills
[i
];
688 return vendor_drills
[i
];
693 /* add a drill size to the vendor drill list */
695 add_to_drills (char *sval
)
701 /* increment the count and make sure we have memory */
703 if ((vendor_drills
= realloc (vendor_drills
,
704 n_vendor_drills
* sizeof (int))) == NULL
)
706 fprintf (stderr
, "realloc() failed to allocate %ld bytes\n",
707 (unsigned long) n_vendor_drills
* sizeof (int));
711 /* string to a value with the units scale factor in place */
713 val
= floor (sf
* tmpd
+ 0.5);
716 * We keep the array of vendor drills sorted to make it easier to
717 * do the rounding later. The algorithm used here is not so efficient,
718 * but we're not dealing with much in the way of data.
721 /* figure out where to insert the value to keep the array sorted. */
723 while ((k
< n_vendor_drills
- 1) && (vendor_drills
[k
] < val
))
726 if (k
== n_vendor_drills
- 1)
728 vendor_drills
[n_vendor_drills
- 1] = val
;
732 /* move up the existing drills to make room */
733 for (j
= n_vendor_drills
- 1; j
> k
; j
--)
735 vendor_drills
[j
] = vendor_drills
[j
- 1];
738 vendor_drills
[k
] = val
;
742 /* deal with the "skip" subresource */
744 process_skips (Resource
* res
)
755 for (i
= 0; i
< res
->c
; i
++)
757 type
= resource_type (res
->v
[i
]);
762 * an unnamed sub resource. This is something like
765 sval
= res
->v
[i
].subres
->v
[0].value
;
768 Message ("Error: null skip value\n");
772 if (NSTRCMP (sval
, "refdes") == 0)
775 lst
= &ignore_refdes
;
777 else if (NSTRCMP (sval
, "value") == 0)
782 else if (NSTRCMP (sval
, "descr") == 0)
792 /* add the entry to the appropriate list */
795 for (k
= 1; k
< res
->v
[i
].subres
->c
; k
++)
797 sval
= res
->v
[i
].subres
->v
[k
].value
;
800 (char **) realloc (*lst
,
801 (*cnt
) * sizeof (char *))) ==
804 fprintf (stderr
, "realloc() failed\n");
807 (*lst
)[*cnt
- 1] = strdup (sval
);
814 Message (_("Ignored resource type = %d in skips= section\n"), type
);
821 vendorIsElementMappable (ElementTypePtr element
)
826 if (vendorMapEnable
== false)
830 for (i
= 0; i
< n_refdes
; i
++)
832 if ((NSTRCMP (UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]) ==
834 || rematch (ignore_refdes
[i
], UNKNOWN (NAMEONPCB_NAME (element
))))
837 ("Vendor mapping skipped because refdes = %s matches %s\n"),
838 UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]);
843 for (i
= 0; i
< n_value
; i
++)
845 if ((NSTRCMP (UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]) == 0)
846 || rematch (ignore_value
[i
], UNKNOWN (VALUE_NAME (element
))))
849 ("Vendor mapping skipped because value = %s matches %s\n"),
850 UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]);
856 for (i
= 0; i
< n_descr
; i
++)
858 if ((NSTRCMP (UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
])
860 || rematch (ignore_descr
[i
],
861 UNKNOWN (DESCRIPTION_NAME (element
))))
864 ("Vendor mapping skipped because descr = %s matches %s\n"),
865 UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
]);
870 if (noskip
&& TEST_FLAG (LOCKFLAG
, element
))
872 Message (_("Vendor mapping skipped because element %s is locked\n"),
873 UNKNOWN (NAMEONPCB_NAME (element
)));
884 rematch (const char *re
, const char *s
)
887 * If this system has regular expression capability, then
888 * add support for regular expressions in the skip lists.
891 #if defined(HAVE_REGCOMP)
897 /* compile the regular expression */
898 result
= regcomp (&compiled
, re
, REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
901 char errorstring
[128];
903 regerror (result
, &compiled
, errorstring
, sizeof (errorstring
));
904 Message ("regexp error: %s\n", errorstring
);
909 result
= regexec (&compiled
, s
, 1, &match
, 0);
917 #elif defined(HAVE_RE_COMP)
921 /* compile the regular expression */
922 if ((rslt
= re_comp (re
)) != NULL
)
924 Message ("re_comp error: %s\n", rslt
);
941 Message ("re_exec error\n");
951 HID_Action vendor_action_list
[] = {
952 {"ApplyVendor", 0, ActionApplyVendor
,
953 apply_vendor_help
, apply_vendor_syntax
}
955 {"ToggleVendor", 0, ActionToggleVendor
,
956 toggle_vendor_help
, toggle_vendor_syntax
}
958 {"EnableVendor", 0, ActionEnableVendor
,
959 enable_vendor_help
, enable_vendor_syntax
}
961 {"DisableVendor", 0, ActionDisableVendor
,
962 disable_vendor_help
, disable_vendor_syntax
}
964 {"UnloadVendor", 0, ActionUnloadVendor
,
965 unload_vendor_help
, unload_vendor_syntax
}
967 {"LoadVendorFrom", 0, ActionLoadVendorFrom
,
968 load_vendor_help
, load_vendor_syntax
}
971 REGISTER_ACTIONS (vendor_action_list
)
972 static int vendor_get_enabled (int unused
)
974 return vendorMapEnable
;
977 HID_Flag vendor_flag_list
[] = {
978 {"VendorMapOn", vendor_get_enabled
, 0}
981 REGISTER_FLAGS (vendor_flag_list
)