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
)
273 static char *default_file
= NULL
;
275 Resource
*res
, *drcres
, *drlres
;
277 bool free_fname
= false;
281 fname
= argc
? argv
[0] : 0;
283 if (!fname
|| !*fname
)
285 fname
= gui
->fileselect (_("Load Vendor Resource File..."),
286 _("Picks a vendor resource file to load.\n"
287 "This file can contain drc settings for a\n"
288 "particular vendor as well as a list of\n"
289 "predefined drills which are allowed."),
290 default_file
, ".res", "vendor",
291 HID_FILESELECT_READ
);
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;
468 apply_vendor_map (void)
474 state
= vendorMapEnable
;
477 vendorMapEnable
= true;
479 /* reset our counts */
483 /* If we have loaded vendor drills, then apply them to the design */
484 if (n_vendor_drills
> 0)
487 /* first all the vias */
488 VIA_LOOP (PCB
->Data
);
491 if (via
->DrillingHole
!= vendorDrillMap (via
->DrillingHole
))
493 /* only change unlocked vias */
494 if (!TEST_FLAG (LOCKFLAG
, via
))
496 if (ChangeObject2ndSize (VIA_TYPE
, via
, NULL
, NULL
,
497 vendorDrillMap (via
->DrillingHole
),
503 ("Via at %.2f, %.2f not changed. Possible reasons:\n"
504 "\t- pad size too small\n"
505 "\t- new size would be too large or too small\n"),
506 0.01 * via
->X
, 0.01 * via
->Y
);
511 Message (_("Locked via at %.2f, %.2f not changed.\n"),
512 0.01 * via
->X
, 0.01 * via
->Y
);
518 /* and now the pins */
519 ELEMENT_LOOP (PCB
->Data
);
522 * first figure out if this element should be skipped for some
525 if (vendorIsElementMappable (element
))
527 /* the element is ok to modify, so iterate over its pins */
531 if (pin
->DrillingHole
!= vendorDrillMap (pin
->DrillingHole
))
533 if (!TEST_FLAG (LOCKFLAG
, pin
))
535 if (ChangeObject2ndSize (PIN_TYPE
, element
, pin
, NULL
,
536 vendorDrillMap (pin
->
543 ("Pin %s (%s) at %.2f, %.2f (element %s, %s, %s) not changed.\n"
544 "\tPossible reasons:\n"
545 "\t- pad size too small\n"
546 "\t- new size would be too large or too small\n"),
547 UNKNOWN (pin
->Number
), UNKNOWN (pin
->Name
),
548 0.01 * pin
->X
, 0.01 * pin
->Y
,
549 UNKNOWN (NAMEONPCB_NAME (element
)),
550 UNKNOWN (VALUE_NAME (element
)),
551 UNKNOWN (DESCRIPTION_NAME (element
)));
557 ("Locked pin at %-6.2f, %-6.2f not changed.\n"),
558 0.01 * pin
->X
, 0.01 * pin
->Y
);
567 Message (_("Updated %d drill sizes out of %d total\n"), changed
, tot
);
569 /* Update the current Via */
570 if (Settings
.ViaDrillingHole
!=
571 vendorDrillMap (Settings
.ViaDrillingHole
))
574 Settings
.ViaDrillingHole
=
575 vendorDrillMap (Settings
.ViaDrillingHole
);
576 Message (_("Adjusted active via hole size to be %6.2f mils\n"),
577 0.01 * Settings
.ViaDrillingHole
);
580 /* and update the vias for the various routing styles */
581 for (i
= 0; i
< NUM_STYLES
; i
++)
583 if (PCB
->RouteStyle
[i
].Hole
!=
584 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
))
587 PCB
->RouteStyle
[i
].Hole
=
588 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
);
590 ("Adjusted %s routing style via hole size to be %6.2f mils\n"),
591 PCB
->RouteStyle
[i
].Name
,
592 0.01 * PCB
->RouteStyle
[i
].Hole
);
593 if (PCB
->RouteStyle
[i
].Diameter
<
594 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
)
596 PCB
->RouteStyle
[i
].Diameter
=
597 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
;
599 ("Increased %s routing style via diameter to %6.2f mils\n"),
600 PCB
->RouteStyle
[i
].Name
,
601 0.01 * PCB
->RouteStyle
[i
].Diameter
);
607 * if we've changed anything, indicate that we need to save the
608 * file, redraw things, and make sure we can undo.
612 SetChangedFlag (true);
613 ClearAndRedrawOutput ();
614 IncrementUndoSerialNumber ();
618 /* restore mapping on/off */
619 vendorMapEnable
= state
;
622 /* for a given drill size, find the closest vendor drill size */
624 vendorDrillMap (int in
)
628 if (in
== cached_drill
)
632 /* skip the mapping if we don't have a vendor drill table */
633 if ((n_vendor_drills
== 0) || (vendor_drills
== NULL
)
634 || (vendorMapEnable
== false))
640 /* are we smaller than the smallest drill? */
641 if (in
<= vendor_drills
[0])
643 cached_map
= vendor_drills
[0];
644 return vendor_drills
[0];
647 /* are we larger than the largest drill? */
648 if (in
> vendor_drills
[n_vendor_drills
- 1])
650 Message (_("Vendor drill list does not contain a drill >= %6.2f mil\n"
651 "Using %6.2f mil instead.\n"),
652 0.01 * in
, 0.01 * vendor_drills
[n_vendor_drills
- 1]);
653 cached_map
= vendor_drills
[n_vendor_drills
- 1];
654 return vendor_drills
[n_vendor_drills
- 1];
657 /* figure out which 2 drills are closest in size */
659 max
= n_vendor_drills
- 1;
660 while (max
- min
> 1)
663 if (in
> vendor_drills
[i
])
670 /* now round per the rounding mode */
671 if (rounding_method
== CLOSEST
)
673 /* find the closest drill size */
674 if ((in
- vendor_drills
[i
- 1]) > (vendor_drills
[i
] - in
))
676 cached_map
= vendor_drills
[i
];
677 return vendor_drills
[i
];
681 cached_map
= vendor_drills
[i
- 1];
682 return vendor_drills
[i
- 1];
687 /* always round up */
688 cached_map
= vendor_drills
[i
];
689 return vendor_drills
[i
];
694 /* add a drill size to the vendor drill list */
696 add_to_drills (char *sval
)
702 /* increment the count and make sure we have memory */
704 if ((vendor_drills
= realloc (vendor_drills
,
705 n_vendor_drills
* sizeof (int))) == NULL
)
707 fprintf (stderr
, "realloc() failed to allocate %ld bytes\n",
708 (unsigned long) n_vendor_drills
* sizeof (int));
712 /* string to a value with the units scale factor in place */
714 val
= floor (sf
* tmpd
+ 0.5);
717 * We keep the array of vendor drills sorted to make it easier to
718 * do the rounding later. The algorithm used here is not so efficient,
719 * but we're not dealing with much in the way of data.
722 /* figure out where to insert the value to keep the array sorted. */
724 while ((k
< n_vendor_drills
- 1) && (vendor_drills
[k
] < val
))
727 if (k
== n_vendor_drills
- 1)
729 vendor_drills
[n_vendor_drills
- 1] = val
;
733 /* move up the existing drills to make room */
734 for (j
= n_vendor_drills
- 1; j
> k
; j
--)
736 vendor_drills
[j
] = vendor_drills
[j
- 1];
739 vendor_drills
[k
] = val
;
743 /* deal with the "skip" subresource */
745 process_skips (Resource
* res
)
756 for (i
= 0; i
< res
->c
; i
++)
758 type
= resource_type (res
->v
[i
]);
763 * an unnamed sub resource. This is something like
766 sval
= res
->v
[i
].subres
->v
[0].value
;
769 Message ("Error: null skip value\n");
773 if (NSTRCMP (sval
, "refdes") == 0)
776 lst
= &ignore_refdes
;
778 else if (NSTRCMP (sval
, "value") == 0)
783 else if (NSTRCMP (sval
, "descr") == 0)
793 /* add the entry to the appropriate list */
796 for (k
= 1; k
< res
->v
[i
].subres
->c
; k
++)
798 sval
= res
->v
[i
].subres
->v
[k
].value
;
801 (char **) realloc (*lst
,
802 (*cnt
) * sizeof (char *))) ==
805 fprintf (stderr
, "realloc() failed\n");
808 (*lst
)[*cnt
- 1] = strdup (sval
);
815 Message (_("Ignored resource type = %d in skips= section\n"), type
);
822 vendorIsElementMappable (ElementTypePtr element
)
827 if (vendorMapEnable
== false)
831 for (i
= 0; i
< n_refdes
; i
++)
833 if ((NSTRCMP (UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]) ==
835 || rematch (ignore_refdes
[i
], UNKNOWN (NAMEONPCB_NAME (element
))))
838 ("Vendor mapping skipped because refdes = %s matches %s\n"),
839 UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]);
844 for (i
= 0; i
< n_value
; i
++)
846 if ((NSTRCMP (UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]) == 0)
847 || rematch (ignore_value
[i
], UNKNOWN (VALUE_NAME (element
))))
850 ("Vendor mapping skipped because value = %s matches %s\n"),
851 UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]);
857 for (i
= 0; i
< n_descr
; i
++)
859 if ((NSTRCMP (UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
])
861 || rematch (ignore_descr
[i
],
862 UNKNOWN (DESCRIPTION_NAME (element
))))
865 ("Vendor mapping skipped because descr = %s matches %s\n"),
866 UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
]);
871 if (noskip
&& TEST_FLAG (LOCKFLAG
, element
))
873 Message (_("Vendor mapping skipped because element %s is locked\n"),
874 UNKNOWN (NAMEONPCB_NAME (element
)));
885 rematch (const char *re
, const char *s
)
888 * If this system has regular expression capability, then
889 * add support for regular expressions in the skip lists.
892 #if defined(HAVE_REGCOMP)
898 /* compile the regular expression */
899 result
= regcomp (&compiled
, re
, REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
902 char errorstring
[128];
904 regerror (result
, &compiled
, errorstring
, sizeof (errorstring
));
905 Message ("regexp error: %s\n", errorstring
);
910 result
= regexec (&compiled
, s
, 1, &match
, 0);
918 #elif defined(HAVE_RE_COMP)
922 /* compile the regular expression */
923 if ((rslt
= re_comp (re
)) != NULL
)
925 Message ("re_comp error: %s\n", rslt
);
942 Message ("re_exec error\n");
952 HID_Action vendor_action_list
[] = {
953 {"ApplyVendor", 0, ActionApplyVendor
,
954 apply_vendor_help
, apply_vendor_syntax
}
956 {"ToggleVendor", 0, ActionToggleVendor
,
957 toggle_vendor_help
, toggle_vendor_syntax
}
959 {"EnableVendor", 0, ActionEnableVendor
,
960 enable_vendor_help
, enable_vendor_syntax
}
962 {"DisableVendor", 0, ActionDisableVendor
,
963 disable_vendor_help
, disable_vendor_syntax
}
965 {"UnloadVendor", 0, ActionUnloadVendor
,
966 unload_vendor_help
, unload_vendor_syntax
}
968 {"LoadVendorFrom", 0, ActionLoadVendorFrom
,
969 load_vendor_help
, load_vendor_syntax
}
972 REGISTER_ACTIONS (vendor_action_list
)
973 static int vendor_get_enabled (int unused
)
975 return vendorMapEnable
;
978 HID_Flag vendor_flag_list
[] = {
979 {"VendorMapOn", vendor_get_enabled
, 0}
982 REGISTER_FLAGS (vendor_flag_list
)