// vim:syntax=c // $Id: silk_gen.ulp,v 1.4 2005/05/23 08:01:27 mcuddy Exp $ #usage "Generate a user defined silk screen\n" "

" "Some board manufacturers want to have at least a width of 8mil " "for silk screen lines in order to guarantee legible results. " "EAGLE libraries use 5 mil width for silk screen as default. " "

" "This ULP changes all silk screen elements to a minimum " "width supplied by user. All elements of layers 20, 21, 22, 25, 26 " "are written into new layers 121(_tsilk) and 122 (_bsilk). " "Texts are changes as well. The new ratio is set to minimum value " "that is requred to achieve the silk wire width. If the original " "text ratio is greater, it is not changed. " "

" "Two new layers will be defined and the new silk screen will be " "generated. For generating GERBER data be aware that you have to " "activate layers 121 or 122 instead of the original layers." "

" "Original authors: Richard Hammerl 26-05-1998, " "Changed for EAGLE 4.0 26-02-2002, support@cadsoft.de " "Fixed for EAGLE 4.11, OLIMEX special 04-11-2003, Y.Onodera, " "Further fixed and modified by Antti Arola 11.03.2005 " "user interface, general code cleanup, ability to delete new " "layers before re-creating them, and board-level text support " "added by M.Cuddy 20.03.2005" "" // THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED // Define your own silk screen width here, in mils real Silkwidth = 8.0; // Default value suggested by dialog // layer name constants int dimension = LAYER_DIMENSION, tplace = LAYER_TPLACE, bplace = LAYER_BPLACE, tnames = LAYER_TNAMES, bnames = LAYER_BNAMES, tvalues = LAYER_TVALUES, bvalues = LAYER_BVALUES, _tsilk = LAYER_TPLACE + LAYER_USER, _bsilk = LAYER_BPLACE + LAYER_USER; // name of new, generated layers string _tsilkName = "_tsilk"; string _bsilkName = "_bsilk"; // boolean flags for which layers to operate on int do_tplace = 1, do_bplace = 1, do_tnames = 1, do_bnames = 1, do_tvalues = 1, do_bvalues = 1, do_dimension = 1, do_confirm = 1; int erase_silk = 1, show_results = 1, warn_ratio = 1; int eraseOnly = 0; // built-up command string string cmd = ""; // 'curLayer', 'curRatio', and 'curSize' are cached globals so we don't // generate more script commands than needed. int curLayer = -1; // start as an invalid number, so first call will int curRatio = -1; // always set real curSize = -1.0; void setLayer(int dstlay) { string h; if (dstlay == curLayer) return; curLayer = dstlay; sprintf(h,"LAYER %d;\n",curLayer); cmd += h; } // return true if currently selected layer is top layer, false otherwise int destLayerIsTop() { if (curLayer == _bsilk) return 0; return 1; } void setRatio(int newRatio) { string h; if (curRatio == newRatio) return; curRatio = newRatio; sprintf(h, "CHANGE RATIO %d;\n", curRatio); cmd += h; } void setSize(real newSize) { string h; if (curSize == newSize) return; curSize = newSize; sprintf(h, "CHANGE SIZE %5.3f;\n", curSize); cmd += h; } void del_layer(int layer, real x1, real y1, real x2, real y2) { string h; sprintf(h, "DISPLAY NONE %d;\n", layer); cmd += h; sprintf(h, "GROUP (>%f %f) (%f %f) (%f %f) (%f %f) (>%f %f);\n", x1, y1, x1, y2, x2, y2, x2, y1, x1, y1 ); cmd += h; sprintf(h, "DELETE (>%f %f);\n", x1, x2 ); cmd += h; sprintf(h, "LAYER ?? -%d;\n", layer); cmd += h; sprintf(h, "WINDOW;\n" ); cmd += h; } // generate a string showing all active layers ( but ignore layers mentioned // in 'ignore' array. //string findActiveLayers(UL_BOARD B, int ignore[], int nIgnore) int ignore[]; int nIgnore; string findActiveLayers(UL_BOARD B) { int i; int skip; string h, cur_active_layers; cur_active_layers = ""; B.layers(L) { skip = 0; for ( i = 0; i < nIgnore; i++) { if ( L.number == ignore[i] ) { skip = 1; break; } } if (skip || !L.visible) continue; sprintf(h," %d", L.number); cur_active_layers += h; } return cur_active_layers; } void erase_silk_layers(UL_BOARD B) { string h; real x1,x2,y1,y2; // size of board area.. x1 = u2mil(B.area.x1); x2 = u2mil(B.area.x2); y1 = u2mil(B.area.y1); y2 = u2mil(B.area.y2); // delete silk screen layers string cur_active_layers = ""; int got_a_silk = 0; B.layers(L) { if (L.number == _tsilk || L.number == _bsilk) { got_a_silk = 1; break; } } // XXX - can't pass arrays to funcs? ignore[0] = _tsilk; ignore[1] = _bsilk; nIgnore = 2; cur_active_layers = findActiveLayers(B); // find currently active layers, exclude _tsilk and _bsilk from the // mix. if (got_a_silk) { // hide all layers sprintf(h, "DISPLAY NONE;\n"); cmd += h; // remove the _tsilk and _bsilk layers B.layers(L) { if (L.number == _tsilk || L.number == _bsilk ) { del_layer(L.number,x1,y1,x2,y2); } } // restore previously visible layers sprintf(h, "DISPLAY %s;\n", cur_active_layers); cmd += h; } } void do_show_results(UL_BOARD B) { string h; // turn on tsilk, bsilk, tstop and bstop. sprintf(h, "DISPLAY NONE %d %d %d %d;\n", _tsilk, _bsilk, LAYER_TSTOP, LAYER_BSTOP ); cmd += h; } void header(UL_BOARD B) { string h; if (erase_silk) { erase_silk_layers(B); } // create the new layers. sprintf(h, "LAYER %d %s;\n", _tsilk, _tsilkName);cmd += h; sprintf(h, "LAYER %d %s;\n", _bsilk, _bsilkName);cmd += h; sprintf(h, "SET COLOR_LAYER %d YELLOW;\n", _tsilk);cmd += h; // and sprintf(h, "SET COLOR_LAYER %d YELLOW;\n", _bsilk);cmd += h; // colors sprintf(h, "SET WIRE_BEND 2;\n\n");cmd += h; } real calcwidth(int size, int ratio) // returns mils { return (u2mil(size) * (ratio/100.0)); } int getreqratio(int size) // returns integer { return ceil((Silkwidth / u2mil(size)) * 100); } /* given a source layer, return the correct destination layer */ int getDstLayer(int source, int dimrun) { int dstlay; if (source == bvalues || source == bplace || source == bnames || (source == dimension && dimrun == 2)) { dstlay = _bsilk; } else { dstlay = _tsilk; } return dstlay; } void do_text(string ename, UL_TEXT T) { real OrigWidth; string orient; int newRatio; string value; string h; if (T.value == "") return; OrigWidth = calcwidth(T.size, T.ratio); if (OrigWidth < Silkwidth) newRatio = getreqratio(T.size); else newRatio = T.ratio; // Check if required ratio is >31 (maximum), give warning if (newRatio > 31) { if (warn_ratio) { sprintf(h, "Element %s non-smashed text \"%s\":\nsize is %5.3f mils, required ratio %d\nUsing maximum ratio (31).\n", ename, T.value, u2mil(T.size), newRatio); dlgMessageBox(h); } newRatio = 31; } setRatio(newRatio); setSize(u2mil(T.size)); // double-up single quotes in text. value = T.value; if (strchr(value,'\'') != -1) { string ary[]; int n = strsplit(ary,value,'\''); int i; value = ""; for (i = 0; i < n; i++) { if (i != 0) value += "''"; value += ary[i]; } } if (destLayerIsTop()) { orient = "R"; } else { orient = "MR"; } sprintf(h, "TEXT '%s' %s%1.0f (%5.3f %5.3f);\n", value, orient, T.angle, u2mil(T.x), u2mil(T.y)); cmd += h; } // make sure curWidth (in mils) to no less than Silkwidth real clampSilkWidth(real curWidth) { if (curWidth < Silkwidth) return Silkwidth; return curWidth; } void searchWires(UL_WIRE W, int source) { real sw; string h; // fixed arcs for v4.11 if (W.arc) { if (W.arc.layer != source) return; sw = clampSilkWidth(u2mil(W.arc.width)); sprintf(h, "ARC %5.3f ccw (%5.3f %5.3f) (%5.3f %5.3f) (%5.3f %5.3f);\n", sw, u2mil(W.arc.x1), u2mil(W.arc.y1), u2mil(2*(W.arc.xc)-W.arc.x1),u2mil(2*(W.arc.yc)-W.arc.y1), u2mil(W.arc.x2), u2mil(W.arc.y2)); cmd += h; } else { if (W.layer != source) return; sw = clampSilkWidth(u2mil(W.width)); sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", Silkwidth, u2mil(W.x1), u2mil(W.y1), u2mil(W.x2), u2mil(W.y2)); cmd += h; } } void searchCircles(UL_CIRCLE C, int source) { real sw; string h; if (C.layer != source) return; sw = clampSilkWidth(u2mil(C.width)); sprintf(h, "CIRCLE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", sw, u2mil(C.x), u2mil(C.y), u2mil(C.x + C.radius), u2mil(C.y)); cmd += h; } void searchRectangles(UL_RECTANGLE R, int source) { string h; if (R.layer != source) return; sprintf(h, "RECT R%1.0f (%5.3f %5.3f) (%5.3f %5.3f);\n", R.angle, u2mil(R.x1), u2mil(R.y1), u2mil(R.x2), u2mil(R.y2)); cmd += h; } void searchPolygons(UL_POLYGON P, int source) { string h; real sw; int first; if (P.layer != source) return; sw = clampSilkWidth(P.width); first = 1; P.wires(WP) { if (first) { sprintf(h, "POLYGON %5.3f (%5.3f %5.3f)", sw, u2mil(WP.x1), u2mil(WP.y1)); cmd += h; } else { sprintf(h, "\n %+f (%5.3f %5.3f)", WP.curve, u2mil(WP.x2), u2mil(WP.y2)); cmd += h; } first = 0; } sprintf(h, ";\n");cmd += h; } void searchElements(UL_ELEMENT E, int source) { string h; E.package.wires(W) { searchWires(W,source); } E.package.circles(C) { searchCircles(C,source); } // fixed angle E.package.rectangles(R) { searchRectangles(R,source); } E.package.polygons(P) { searchPolygons(P,source); } // non-smashed texts E.package.texts(T) { if (T.layer == source) do_text(E.name, T); } // smashed texts E.texts(T) { if (T.layer == source) do_text(E.name, T); } } void searchTexts(UL_TEXT T, int source) { if (T.layer == source) do_text("", T); } string settingsFile() { string fn; string boardName; project.board(B) { boardName = B.name; } fn = filesetext(boardName,".silk"); return fn; } void saveSettings() { string fn, data; string lines[], words[]; int nlines, nwords; fn = settingsFile(); output(fn,"w") { printf("Silkwidth=%f\n", Silkwidth); printf("dimension=%d\n", dimension); printf("tplace=%d\n", tplace); printf("bplace=%d\n", bplace); printf("tnames=%d\n", tnames); printf("bnames=%d\n", bnames); printf("tvalues=%d\n", tvalues); printf("bvalues=%d\n", bvalues); printf("_tsilk=%d\n", _tsilk); printf("_bsilk=%d\n", _bsilk); printf("_tsilkName=%s\n", _tsilkName); printf("_bsilkName=%s\n", _bsilkName); printf("do_tplace=%d\n", do_tplace); printf("do_bplace=%d\n", do_bplace); printf("do_tnames=%d\n", do_tnames); printf("do_bnames=%d\n", do_bnames); printf("do_tvalues=%d\n", do_tvalues); printf("do_bvalues=%d\n", do_bvalues); printf("do_dimension=%d\n", do_dimension); printf("do_confirm=%d\n", do_confirm); printf("show_results=%d\n", show_results); printf("erase_silk=%d\n", erase_silk); printf("warn_ratio=%d\n", warn_ratio); } } void loadSettings() { string fn, data; string lines[], words[]; int nlines, nwords, i; fn = settingsFile(); fileerror(); // clear any previous error. fileread(data,fn); // it's okay if the settings file can't be read. if (fileerror()) return; nlines = strsplit(lines, data,'\n'); for (i = 0; i < nlines; i++) { nwords = strsplit(words,lines[i],'='); if (nwords != 2) continue; if (words[0] == "Silkwidth") { Silkwidth = strtod(words[1]); } else if (words[0] == "dimension") { dimension = strtol(words[1]); } else if (words[0] == "tplace") { tplace = strtol(words[1]); } else if (words[0] == "bplace") { bplace = strtol(words[1]); } else if (words[0] == "tnames") { tnames = strtol(words[1]); } else if (words[0] == "bnames") { bnames = strtol(words[1]); } else if (words[0] == "tvalues") { tvalues = strtol(words[1]); } else if (words[0] == "bvalues") { bvalues = strtol(words[1]); } else if (words[0] == "_tsilk") { _tsilk = strtol(words[1]); } else if (words[0] == "_bsilk") { _bsilk = strtol(words[1]); } else if (words[0] == "_tsilkName") { _tsilkName = words[1]; } else if (words[0] == "_bsilkName") { _bsilkName = words[1]; } else if (words[0] == "do_tplace") { do_tplace = strtol(words[1]); } else if (words[0] == "do_bplace") { do_bplace = strtol(words[1]); } else if (words[0] == "do_tnames") { do_tnames = strtol(words[1]); } else if (words[0] == "do_bnames") { do_bnames = strtol(words[1]); } else if (words[0] == "do_tvalues") { do_tvalues = strtol(words[1]); } else if (words[0] == "do_bvalues") { do_bvalues = strtol(words[1]); } else if (words[0] == "do_dimension") { do_dimension = strtol(words[1]); } else if (words[0] == "do_confirm") { do_confirm = strtol(words[1]); } else if (words[0] == "show_results") { show_results = strtol(words[1]); } else if (words[0] == "erase_silk") { erase_silk = strtol(words[1]); } else if (words[0] == "warn_ratio") { warn_ratio = strtol(words[1]); } } } if (! board) { dlgMessageBox("\n Start this ULP in a Board \n"); exit (0); } board(B) { string h; int rc; loadSettings(); rc = dlgDialog ("Enter silkscreen width") { dlgVBoxLayout { dlgHBoxLayout { dlgLabel ("Minimum silkscreen wire width in mils:"); dlgRealEdit (Silkwidth, 0.0, 99.9); dlgStretch(1); } dlgLabel ("Source layers:"); dlgHBoxLayout { dlgLabel ("Dimension:"); dlgIntEdit (dimension, 0, 999); dlgCheckBox ("", do_dimension); dlgStretch(1); } dlgHBoxLayout { dlgLabel ("Place top:"); dlgIntEdit (tplace, 0, 999); dlgCheckBox ("", do_tplace); dlgLabel (" bottom:"); dlgIntEdit (bplace, 0, 999); dlgCheckBox ("", do_bplace); } dlgHBoxLayout { dlgLabel ("Names top:"); dlgIntEdit (tnames, 0, 999); dlgCheckBox ("", do_tnames); dlgLabel (" bottom:"); dlgIntEdit (bnames, 0, 999); dlgCheckBox ("", do_bnames); } dlgHBoxLayout { dlgLabel ("Values top:"); dlgIntEdit (tvalues, 0, 999); dlgCheckBox ("", do_tvalues); dlgLabel (" bottom:"); dlgIntEdit (bvalues, 0, 999); dlgCheckBox ("", do_bvalues); } dlgLabel ("Generated Silk screen layers:"); dlgHBoxLayout { dlgLabel ("top layer number:"); dlgIntEdit (_tsilk, 100, 999); dlgLabel (" name:"); dlgStringEdit (_tsilkName); } dlgHBoxLayout { dlgLabel ("bottom layer number:"); dlgIntEdit (_bsilk, 100, 999); dlgLabel (" name:"); dlgStringEdit (_bsilkName); } dlgHBoxLayout { dlgCheckBox ("Erase existing tSilk/bSilk layer:", erase_silk); dlgCheckBox ("Warn about invalid text ratios", warn_ratio); dlgStretch(1); } dlgHBoxLayout { dlgCheckBox ("Show Results", show_results); dlgCheckBox ("Confirm Script before execution", do_confirm); dlgStretch(1); } dlgHBoxLayout { dlgPushButton ("+Make Silkscreen layers") dlgAccept (1); dlgStretch(1); dlgPushButton ("Erase old silkscreen") dlgAccept(2); dlgStretch(1); dlgPushButton("-Cancel") dlgAccept(3); } } }; if (rc == 3) { // abort exit(0); } if (rc == 2) { eraseOnly = 1; } else { int err = 0; eraseOnly = 0; if (do_tplace+do_bplace+do_tnames+do_bnames+do_tvalues+do_bvalues == 0){ dlgMessageBox("No source layers selected."); exit(0); } // make sure that new layers we're about to create don't exist already B.layers(L) { if (L.name == _tsilkName && L.number != _tsilk) { sprintf(h,"Duplicate top-silk-layer name '%s' with different layer number (%d != %d)\nTry erasing old silk-screen layers first.", L.name, L.number, _tsilk ); dlgMessageBox(h); err = 1; } if (L.name == _bsilkName && L.number != _bsilk) { sprintf(h,"Duplicate bottom-silk-layer name '%s' with different layer number (%d != %d)\nTry erasing old silk-screen layers first.", L.name, L.number, _tsilk ); dlgMessageBox(h); err = 1; } } if (err) exit(1); } sprintf(h, "\nGRID mil;\n\n");cmd += h; if (eraseOnly) { erase_silk_layers(B); } else { int src[]; int dst[]; int nLayers; int i; nLayers = 0; if (do_tplace) { src[nLayers] = tplace; dst[nLayers] = getDstLayer(tplace,0); nLayers++; } if (do_bplace) { src[nLayers] = bplace; dst[nLayers] = getDstLayer(bplace,0); nLayers++; } if (do_tnames) { src[nLayers] = tnames; dst[nLayers] = getDstLayer(tnames,0); nLayers++; } if (do_bnames) { src[nLayers] = bnames; dst[nLayers] = getDstLayer(bnames,0); nLayers++; } if (do_tvalues) { src[nLayers] = tvalues; dst[nLayers] = getDstLayer(tvalues,0); nLayers++; } if (do_bvalues) { src[nLayers] = bvalues; dst[nLayers] = getDstLayer(bplace,0); nLayers++; } cmd += "SET UNDO_LOG OFF;\n"; // advisable for speed reasons header(B); if (do_dimension) { // process dimension layers onto top / bottom // 1 = top, 2 = bottom for ( i = 1; i <= 2; i++) { setLayer(getDstLayer(dimension,i)); B.texts(T) { searchTexts(T,dimension); } B.wires(W) { searchWires(W,dimension); } B.elements(E) { searchElements(E,dimension); } } } // process source layers... for (i = 0; i < nLayers; i++) { setLayer(dst[i]); B.texts(T) { searchTexts(T,src[i]); } B.wires(W) { searchWires(W,src[i]); } B.elements(E) { searchElements(E,src[i]); } } if (show_results) do_show_results(B); cmd += "SET UNDO_LOG ON;\n"; } } if (do_confirm) { int Result = dlgDialog("Script to generate the new silk screen") { dlgVBoxLayout { dlgTextEdit(cmd); dlgHBoxLayout { dlgSpacing(300); dlgStretch(1); dlgPushButton("+Execute") dlgAccept(); dlgPushButton("-Cancel") dlgReject(); } } }; if (Result == 0) exit(0); } if (!eraseOnly) saveSettings(); exit(cmd);