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
[] = N_("ApplyVendor()");
106 static const char apply_vendor_help
[] =
107 N_("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
[] = N_("ToggleVendor()");
130 static const char toggle_vendor_help
[] =
131 N_("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
[] = N_("EnableVendor()");
161 static const char enable_vendor_help
[] =
162 N_("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
[] = N_("DisableVendor()");
189 static const char disable_vendor_help
[] =
190 N_("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
[] = N_("UnloadVendor()");
215 static const char unload_vendor_help
[] =
216 N_("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
[] = N_("LoadVendorFrom(filename)");
247 static const char load_vendor_help
[] =
248 N_("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
;
372 Message (_("\"%s\" is not a valid rounding type. "
373 "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
),
494 Message (_("Via at %.2f, %.2f not changed. "
495 "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
->
534 Message (_("Pin %s (%s) at %.2f, %.2f "
535 "(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
)));
548 Message (_("Locked pin at %-6.2f, %-6.2f not changed.\n"),
549 0.01 * pin
->X
, 0.01 * pin
->Y
);
558 Message (_("Updated %d drill sizes out of %d total\n"), changed
, tot
);
560 /* Update the current Via */
561 if (Settings
.ViaDrillingHole
!=
562 vendorDrillMap (Settings
.ViaDrillingHole
))
565 Settings
.ViaDrillingHole
=
566 vendorDrillMap (Settings
.ViaDrillingHole
);
567 Message (_("Adjusted active via hole size to be %6.2f mils\n"),
568 0.01 * Settings
.ViaDrillingHole
);
571 /* and update the vias for the various routing styles */
572 for (i
= 0; i
< NUM_STYLES
; i
++)
574 if (PCB
->RouteStyle
[i
].Hole
!=
575 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
))
578 PCB
->RouteStyle
[i
].Hole
=
579 vendorDrillMap (PCB
->RouteStyle
[i
].Hole
);
580 Message (_("Adjusted %s routing style via hole size to be "
582 PCB
->RouteStyle
[i
].Name
,
583 0.01 * PCB
->RouteStyle
[i
].Hole
);
584 if (PCB
->RouteStyle
[i
].Diameter
<
585 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
)
587 PCB
->RouteStyle
[i
].Diameter
=
588 PCB
->RouteStyle
[i
].Hole
+ MIN_PINORVIACOPPER
;
589 Message (_("Increased %s routing style via diameter to "
591 PCB
->RouteStyle
[i
].Name
,
592 0.01 * PCB
->RouteStyle
[i
].Diameter
);
598 * if we've changed anything, indicate that we need to save the
599 * file, redraw things, and make sure we can undo.
603 SetChangedFlag (true);
605 IncrementUndoSerialNumber ();
609 /* restore mapping on/off */
610 vendorMapEnable
= state
;
613 /* for a given drill size, find the closest vendor drill size */
615 vendorDrillMap (int in
)
619 if (in
== cached_drill
)
623 /* skip the mapping if we don't have a vendor drill table */
624 if ((n_vendor_drills
== 0) || (vendor_drills
== NULL
)
625 || (vendorMapEnable
== false))
631 /* are we smaller than the smallest drill? */
632 if (in
<= vendor_drills
[0])
634 cached_map
= vendor_drills
[0];
635 return vendor_drills
[0];
638 /* are we larger than the largest drill? */
639 if (in
> vendor_drills
[n_vendor_drills
- 1])
641 Message (_("Vendor drill list does not contain a drill >= %6.2f mil\n"
642 "Using %6.2f mil instead.\n"),
643 0.01 * in
, 0.01 * vendor_drills
[n_vendor_drills
- 1]);
644 cached_map
= vendor_drills
[n_vendor_drills
- 1];
645 return vendor_drills
[n_vendor_drills
- 1];
648 /* figure out which 2 drills are closest in size */
650 max
= n_vendor_drills
- 1;
651 while (max
- min
> 1)
654 if (in
> vendor_drills
[i
])
661 /* now round per the rounding mode */
662 if (rounding_method
== CLOSEST
)
664 /* find the closest drill size */
665 if ((in
- vendor_drills
[i
- 1]) > (vendor_drills
[i
] - in
))
667 cached_map
= vendor_drills
[i
];
668 return vendor_drills
[i
];
672 cached_map
= vendor_drills
[i
- 1];
673 return vendor_drills
[i
- 1];
678 /* always round up */
679 cached_map
= vendor_drills
[i
];
680 return vendor_drills
[i
];
685 /* add a drill size to the vendor drill list */
687 add_to_drills (char *sval
)
693 /* increment the count and make sure we have memory */
695 if ((vendor_drills
= (int *)realloc (vendor_drills
,
696 n_vendor_drills
* sizeof (int))) == NULL
)
698 fprintf (stderr
, _("realloc() failed to allocate %ld bytes\n"),
699 (unsigned long) n_vendor_drills
* sizeof (int));
703 /* string to a value with the units scale factor in place */
705 val
= floor (sf
* tmpd
+ 0.5);
708 * We keep the array of vendor drills sorted to make it easier to
709 * do the rounding later. The algorithm used here is not so efficient,
710 * but we're not dealing with much in the way of data.
713 /* figure out where to insert the value to keep the array sorted. */
715 while ((k
< n_vendor_drills
- 1) && (vendor_drills
[k
] < val
))
718 if (k
== n_vendor_drills
- 1)
720 vendor_drills
[n_vendor_drills
- 1] = val
;
724 /* move up the existing drills to make room */
725 for (j
= n_vendor_drills
- 1; j
> k
; j
--)
727 vendor_drills
[j
] = vendor_drills
[j
- 1];
730 vendor_drills
[k
] = val
;
734 /* deal with the "skip" subresource */
736 process_skips (Resource
* res
)
747 for (i
= 0; i
< res
->c
; i
++)
749 type
= resource_type (res
->v
[i
]);
754 * an unnamed sub resource. This is something like
757 sval
= res
->v
[i
].subres
->v
[0].value
;
760 Message (_("Error: null skip value\n"));
764 if (NSTRCMP (sval
, "refdes") == 0)
767 lst
= &ignore_refdes
;
769 else if (NSTRCMP (sval
, "value") == 0)
774 else if (NSTRCMP (sval
, "descr") == 0)
784 /* add the entry to the appropriate list */
787 for (k
= 1; k
< res
->v
[i
].subres
->c
; k
++)
789 sval
= res
->v
[i
].subres
->v
[k
].value
;
792 (char **) realloc (*lst
,
793 (*cnt
) * sizeof (char *))) ==
796 fprintf (stderr
, _("realloc() failed\n"));
799 (*lst
)[*cnt
- 1] = strdup (sval
);
806 Message (_("Ignored resource type = %d in skips= section\n"), type
);
813 vendorIsElementMappable (ElementType
*element
)
818 if (vendorMapEnable
== false)
822 for (i
= 0; i
< n_refdes
; i
++)
824 if ((NSTRCMP (UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]) ==
826 || rematch (ignore_refdes
[i
], UNKNOWN (NAMEONPCB_NAME (element
))))
828 Message (_("Vendor mapping skipped because "
829 "refdes = %s matches %s\n"),
830 UNKNOWN (NAMEONPCB_NAME (element
)), ignore_refdes
[i
]);
835 for (i
= 0; i
< n_value
; i
++)
837 if ((NSTRCMP (UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]) == 0)
838 || rematch (ignore_value
[i
], UNKNOWN (VALUE_NAME (element
))))
840 Message (_("Vendor mapping skipped because "
841 "value = %s matches %s\n"),
842 UNKNOWN (VALUE_NAME (element
)), ignore_value
[i
]);
848 for (i
= 0; i
< n_descr
; i
++)
850 if ((NSTRCMP (UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
])
852 || rematch (ignore_descr
[i
],
853 UNKNOWN (DESCRIPTION_NAME (element
))))
855 Message (_("Vendor mapping skipped because "
856 "descr = %s matches %s\n"),
857 UNKNOWN (DESCRIPTION_NAME (element
)), ignore_descr
[i
]);
862 if (noskip
&& TEST_FLAG (LOCKFLAG
, element
))
864 Message (_("Vendor mapping skipped because element %s is locked\n"),
865 UNKNOWN (NAMEONPCB_NAME (element
)));
876 rematch (const char *re
, const char *s
)
879 * If this system has regular expression capability, then
880 * add support for regular expressions in the skip lists.
883 #if defined(HAVE_REGCOMP)
889 /* compile the regular expression */
890 result
= regcomp (&compiled
, re
, REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
893 char errorstring
[128];
895 regerror (result
, &compiled
, errorstring
, sizeof (errorstring
));
896 Message (_("regexp error: %s\n"), errorstring
);
901 result
= regexec (&compiled
, s
, 1, &match
, 0);
909 #elif defined(HAVE_RE_COMP)
913 /* compile the regular expression */
914 if ((rslt
= re_comp (re
)) != NULL
)
916 Message (_("re_comp error: %s\n"), rslt
);
933 Message (_("re_exec error\n"));
943 HID_Action vendor_action_list
[] = {
944 {"ApplyVendor", 0, ActionApplyVendor
,
945 apply_vendor_help
, apply_vendor_syntax
}
947 {"ToggleVendor", 0, ActionToggleVendor
,
948 toggle_vendor_help
, toggle_vendor_syntax
}
950 {"EnableVendor", 0, ActionEnableVendor
,
951 enable_vendor_help
, enable_vendor_syntax
}
953 {"DisableVendor", 0, ActionDisableVendor
,
954 disable_vendor_help
, disable_vendor_syntax
}
956 {"UnloadVendor", 0, ActionUnloadVendor
,
957 unload_vendor_help
, unload_vendor_syntax
}
959 {"LoadVendorFrom", 0, ActionLoadVendorFrom
,
960 load_vendor_help
, load_vendor_syntax
}
963 REGISTER_ACTIONS (vendor_action_list
)
965 static int vendor_get_enabled (void *data
)
967 return vendorMapEnable
;
970 HID_Flag vendor_flag_list
[] = {
971 {"VendorMapOn", vendor_get_enabled
, NULL
}
974 REGISTER_FLAGS (vendor_flag_list
)