// vim:syntax=c #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; int erase_silk = 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; } 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; } 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; // find currently active layers, exclude _tsilk and _bsilk from the // mix. B.layers(L) { if (L.number == _tsilk || L.number == _bsilk ) { got_a_silk = 1; continue; } else if (L.visible) { sprintf(h," %d", L.number); cur_active_layers += h; } } 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 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); } void do_text(string ename, UL_TEXT T, int dstlay, string orient) { real OrigWidth; 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; } setLayer(dstlay); 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]; } } sprintf(h, "TEXT '%s' %s%1.0f (%5.3f %5.3f);\n", value, orient, T.angle, u2mil(T.x), u2mil(T.y)); cmd += h; } /* 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; } // make sure curWidth (in mils) to no less than Silkwidth real clampSilkWidth(real curWidth) { if (curWidth < Silkwidth) return Silkwidth; return curWidth; } void searchElements(UL_ELEMENT E, int source, int dimrun, string orient) { int dstlay = getDstLayer(source, dimrun); real sw; string h; // iterate over wires in element E.package.wires(W) { // fixed arcs for v4.11 if (W.arc) { if (W.arc.layer != source) continue; sw = clampSilkWidth(u2mil(W.arc.width)); setLayer(dstlay); 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) continue; sw = clampSilkWidth(u2mil(W.width)); setLayer(dstlay); 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; } } E.package.circles(C) { if (C.layer != source) continue; sw = clampSilkWidth(u2mil(C.width)); setLayer(dstlay); 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; } // fixed angle // Removed TextOrientation string, always "R" E.package.rectangles(R) { if (R.layer != source) continue; setLayer(dstlay); 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; } E.package.polygons(P) { int first; if (P.layer != source) continue; 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; } // non-smashed texts E.package.texts(T) { if (T.layer == source) do_text(E.name, T, dstlay, orient); } // smashed texts E.texts(T) { if (T.layer == source) do_text(E.name, T, dstlay, orient); } } void searchTexts(UL_TEXT T, int source, int dimrun, string orient) { int dstlay = getDstLayer(source, dimrun); if (T.layer == source) do_text("", T, dstlay, orient); } 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("erase_silk=%d\n", dimension); printf("warn_ratio=%d\n", dimension); } } 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] == "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); } dlgLabel ("Source layers:"); 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); } dlgHBoxLayout { dlgPushButton ("+Make Silkscreen layers") dlgAccept (1); dlgPushButton ("Erase old silkscreen") dlgAccept(2); } } }; 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 { cmd += "SET UNDO_LOG OFF;\n"; // advisable for speed reasons header(B); // board level text. B.texts(T) { searchTexts(T,dimension,1,"R"); // draw dimensions for bottom side searchTexts(T,dimension,2,"MR"); if (do_tplace) searchTexts(T,tplace,0,"R"); if (do_bplace) searchTexts(T,bplace,0,"MR"); if (do_tnames) searchTexts(T,tnames,0,"R"); if (do_bnames) searchTexts(T,bnames,0,"MR"); if (do_tvalues) searchTexts(T,tvalues,0,"R"); if (do_bvalues) searchTexts(T,bvalues,0,"MR"); } B.elements(E) { // draw dimensions for top side searchElements(E,dimension,1,"R"); // draw dimensions for bottom side searchElements(E,dimension,2,"MR"); if (do_tplace) searchElements(E,tplace,0,"R"); if (do_bplace) searchElements(E,bplace,0,"MR"); if (do_tnames) searchElements(E,tnames,0,"R"); if (do_bnames) searchElements(E,bnames,0,"MR"); if (do_tvalues) searchElements(E,tvalues,0,"R"); if (do_bvalues) searchElements(E,bvalues,0,"R"); } cmd += "SET UNDO_LOG ON;\n"; } } 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);