#usage "Create library or libraries from schematic/board (Version 4.1)

\n" "Can be used to make individual changes to components in a project. " "Just load the board or the schematic and the board, use this ULP to " "generate a library or several libraries " "containing the used components, make your changes in the library, and use the " "UPDATE command to introduce the changes to the schematic or board.

" "Version 1.2: Put objects in forbidden layers into trash layer (edit variable trash_layer). " "Replace @ in library and device names with $, and spaces with _.

" "See Help for further details

" "Author: support@cadsoft.de" int trash_layer = 250; // put anything here which is in wrong layers string PrevName = ""; string x[]; string CurrentLbrName = ""; string EditName; string h, cmd = "", logf = ""; string ScriptName, PureScriptName; string LogName, PureLogName; string WorkPath; string Status = ""; int n; int NameIndex = 0; int IsPackage = 1; int onelib = 0, show_script = 0, save_log = 1; int in_board; enum {no_mode, in_symbol, in_package}; int mode = no_mode; string HelpText = "Create project library from schematic or board

\n" "This program collects the parts from a schematic or board and stores them back " "into one or several libraries.

\n" "Attention: Before using this program please make sure no library is open and all layers containing objects " "are used. If in doubt, execute the command
\n" "   SET USED_LAYERS ALL

\n" "If you use this ULP from a schematic, the respective board MUST be opened, too!

\n" "Creation Mode

\n" "If 'Multiple libraries' is checked, the program generates libraries with their original name. " "Thus you can edit symbols and/or packages in the generated libraries and " "use the UPDATE command to change all of the respective parts in the schematic or board.

\n" "If 'One library' is checked, a single project library with the name of the schematic or board is generated. " "Package/symbol/device names are then prefixed with the names of the original libraries.

\n" "Show scripts and file dialogs

" "If checked, you can edit the scripts and select path/filename for the library " "script and the log file before execution of the library generation script file.

\n" "Save log file

" "If checked, the logfile is saved before execution of the library generation script file.

\n" "Working path

" "Enter the path where the libraries and the log file go to, or use 'Browse' to select the directory.

\n" "Collect data, Create library

" "Use these buttons in this order to create the project library or libraries.
" "If one of the library files to be created already exists, you will be prompted if " "the existing file may be deleted." ; void DisplayHelp(void) { dlgDialog("Bill Of Material - Help") { dlgHBoxLayout dlgSpacing(400); dlgHBoxLayout { dlgVBoxLayout dlgSpacing(300); dlgTextView(HelpText); } dlgHBoxLayout { dlgStretch(1); dlgPushButton("-Close") dlgReject(); } }; } string get_project_path() { if (board) board(B) return(filedir(B.name)); if (schematic) schematic(B) return(filedir(B.name)); if (library) library(B) return(filedir(B.name)); } string replacenewline(string nl) { string a[]; int n = strsplit(a, nl, '\n'); if (n > 0) { nl = ""; for (int x = 0; x < n - 1; x++) { nl += a[x] + "\\n"; } nl += a[x]; } return "'" + nl + "'"; } string change_at(string s) { // replace @->$ and space->_ int i; for (i=0; i96 && LNr<100))) { h = ""; sprintf(h, "Layer trash %d;\n", trash_layer); cmd += h; LNr = trash_layer; } if (mode==in_package && (LNr>90 && LNr<100)) { LNr = trash_layer; h = ""; sprintf(h, "Layer trash %d;\n", trash_layer); cmd += h; } h = ""; sprintf(h, "Layer %d;\n", LNr); cmd += h; } void DrawCircle(UL_CIRCLE C) { PrintValidLayer(C.layer); h = ""; sprintf(h, "Circle %f (%f %f) (%f %f);\n", u2mic(C.width), u2mic(C.x), u2mic(C.y), u2mic(C.x + C.radius), u2mic(C.y)); cmd += h; } void DrawWire(UL_WIRE W) { PrintValidLayer(W.layer); if (W.arc) { h = ""; sprintf(h, "Arc CCW %f (%f %f) (%f %f) (%f %f);\n", u2mic(W.width), u2mic(W.arc.x1), u2mic(W.arc.y1), u2mic(W.arc.xc + W.arc.xc - W.arc.x1), u2mic(W.arc.yc + W.arc.yc - W.arc.y1), u2mic(W.arc.x2), u2mic(W.arc.y2)); cmd += h; } else { h = ""; sprintf(h, "Wire %f (%f %f) (%f %f);\n", u2mic(W.width), u2mic(W.x1), u2mic(W.y1), u2mic(W.x2), u2mic(W.y2)); cmd += h; } } void DrawRectangle(UL_RECTANGLE R) { PrintValidLayer(R.layer); h = ""; sprintf(h, "Rect (%f %f) (%f %f);\n", u2mic(R.x1), u2mic(R.y1), u2mic(R.x2), u2mic(R.y2)); cmd += h; } void DrawContact(UL_CONTACT C) { string ShapeString; string ShapeFlag; if (C.pad) { switch(C.pad.shape[16]) { case PAD_SHAPE_SQUARE : ShapeString = "Square"; break; case PAD_SHAPE_ROUND : ShapeString = "Round"; break; case PAD_SHAPE_OCTAGON : ShapeString = "Octagon"; break; case PAD_SHAPE_LONG : ShapeString = "Long"; break; case PAD_SHAPE_OFFSET : ShapeString = "Offset"; break; } if (!(C.pad.flags & PAD_FLAG_STOP) ) ShapeFlag = "NOSTOP "; if (!(C.pad.flags & PAD_FLAG_THERMALS) ) ShapeFlag += "NOTHERMALS "; if (!(C.pad.flags & PAD_FLAG_FIRST) ) ShapeFlag += "FIRST "; // // PAD [diameter] [shape] [orientation] [flags] ['name'] *.. // h = ""; sprintf(h, "Change Drill %f;\n", u2mic(C.pad.drill)); cmd += h; h = ""; sprintf(h, "Pad %f %s R%.1f %s '%s' (%f %f);\n", u2mic(C.pad.diameter[16]), ShapeString, C.pad.angle, ShapeFlag, C.pad.name, u2mic(C.pad.x), u2mic(C.pad.y)); cmd += h; } else if (C.smd) { if (!(C.smd.flags & PAD_FLAG_STOP) ) ShapeFlag = "NOSTOP "; if (!(C.smd.flags & SMD_FLAG_THERMALS) ) ShapeFlag += "NOTHERMALS "; if (!(C.smd.flags & SMD_FLAG_CREAM) ) ShapeFlag += "NOCREAM "; PrintValidLayer(C.smd.layer); h = ""; sprintf(h, "CHANGE Roundness %d;\n", C.smd.roundness); cmd += h; // // SMD [x_width y_width] [-roundness] [orientation] [flags] ['name'] *.. // h = ""; sprintf(h, "SMD %f %f -%d R%.1f %s '%s' (%f %f);\n", u2mic(C.smd.dx), u2mic(C.smd.dy), C.smd.roundness, C.smd.angle, ShapeFlag, C.smd.name, u2mic(C.smd.x), u2mic(C.smd.y)); cmd += h; } } void DrawText(UL_TEXT T) { PrintValidLayer(T.layer); switch(T.font) { case FONT_VECTOR : sprintf(h, "CHANGE FONT VECTOR;\n"); cmd += h; break; case FONT_PROPORTIONAL : sprintf(h, "CHANGE FONT PROPORTIONAL;\n"); cmd += h; break; case FONT_FIXED : sprintf(h, "CHANGE FONT FIXED;\n"); cmd += h; break; } string Spin = ""; string Mirror = ""; if (T.spin) Spin = "S"; if (T.mirror) Mirror = "M"; sprintf(h, "Change Size %f;\n", u2mic(T.size)); cmd += h; sprintf(h, "Change Ratio %d;\n", T.ratio); cmd += h; sprintf(h, "Text %s%sR%.1f '%s' (%f %f);\n", Spin, Mirror, T.angle, T.value, u2mic(T.x), u2mic(T.y) ); cmd += h; } void DrawHole(UL_HOLE H) { h = ""; sprintf(h, "Change Drill %f;\n", u2mic(H.drill)); cmd += h; h = ""; sprintf(h, "Hole (%f %f);\n", u2mic(H.x), u2mic(H.y)); cmd += h; } void DrawPolygon(UL_POLYGON PL) { PrintValidLayer(PL.layer); h = ""; sprintf(h, "Change Isolate %f;\n", u2mic(PL.isolate)); cmd += h; h = ""; sprintf(h, "Change Spacing %f;\n", u2mic(PL.spacing)); cmd += h; if (PL.orphans) { h = ""; sprintf(h, "Change Orphans On;\n"); cmd += h; } else { h = ""; sprintf(h, "Change Orphans Off;\n"); cmd += h; } if (PL.thermals) { h = ""; sprintf(h, "Change Thermals On;\n"); cmd += h; } else { h = ""; sprintf(h, "Change Thermals Off;\n"); cmd += h; } if (PL.pour == POLYGON_POUR_SOLID) { h = ""; sprintf(h, "Change Pour Solid;\n"); cmd += h; } else { h = ""; sprintf(h, "Change Pour Hatch;\n"); cmd += h; } h = ""; sprintf(h, "Polygon %f ", u2mic(PL.width)); cmd += h; PL.wires(W) { h = ""; sprintf(h, "(%f %f) ", u2mic(W.x1), u2mic(W.y1)); cmd += h; /*start coord.*/ break; }; PL.wires(W) { h = ""; sprintf(h, " %+f (%f %f) ", W.curve, u2mic(W.x2), u2mic(W.y2)); cmd += h; }; h = ""; sprintf(h, ";\n"); cmd += h; } void DrawPin(UL_PIN P) { string DIR = "", FUNC = "", LEN = "", VIS = "", ANGLE = "R0"; if (P.angle == 90) (ANGLE = "R90"); if (P.angle == 180) (ANGLE = "R180"); if (P.angle == 270) (ANGLE = "R270"); if (P.function == PIN_FUNCTION_FLAG_NONE) (FUNC = "None"); if (P.function == PIN_FUNCTION_FLAG_DOT) (FUNC = "Dot"); if (P.function == PIN_FUNCTION_FLAG_CLK) (FUNC = "Clk"); if (P.function == (PIN_FUNCTION_FLAG_DOT | PIN_FUNCTION_FLAG_CLK)) (FUNC = "DotClk"); if (P.visible == PIN_VISIBLE_FLAG_OFF) (VIS = "Off"); if (P.visible == PIN_VISIBLE_FLAG_PIN) (VIS = "Pin"); if (P.visible == PIN_VISIBLE_FLAG_PAD) (VIS = "Pad"); if (P.visible == (PIN_VISIBLE_FLAG_PIN | PIN_VISIBLE_FLAG_PAD)) (VIS = "Both"); switch(P.direction) { case PIN_DIRECTION_NC : DIR = "NC"; break; case PIN_DIRECTION_IN : DIR = "In"; break; case PIN_DIRECTION_OUT : DIR = "Out"; break; case PIN_DIRECTION_IO : DIR = "I/O"; break; case PIN_DIRECTION_OC : DIR = "OC"; break; case PIN_DIRECTION_PWR : DIR = "Pwr"; break; case PIN_DIRECTION_PAS : DIR = "Pas"; break; case PIN_DIRECTION_HIZ : DIR = "Hiz"; break; case PIN_DIRECTION_SUP : DIR = "Sup"; } switch(P.length) { case PIN_LENGTH_POINT : LEN = "Point"; break; case PIN_LENGTH_SHORT : LEN = "Short"; break; case PIN_LENGTH_MIDDLE : LEN = "Middle"; break; case PIN_LENGTH_LONG : LEN = "Long"; } h = ""; sprintf(h, "Pin '%s' %s %s %s %s %s %d (%f %f);\n", P.name, DIR, FUNC, LEN, ANGLE, VIS, P.swaplevel, u2mic(P.x), u2mic(P.y)); cmd += h; } void DrawSymbol(UL_SYMBOL S) { mode = in_symbol; IsPackage = 0; S.circles(C) DrawCircle(C); S.rectangles(R) DrawRectangle(R); S.wires(W) DrawWire(W); S.pins(P) DrawPin(P); S.texts(T) DrawText(T); S.polygons(PL) DrawPolygon(PL); mode = no_mode; } void DrawPackage(UL_PACKAGE P) { mode = in_package; IsPackage = 1; // P.arcs(A) DrawArc(A); P.circles(C) DrawCircle(C); P.wires(W) DrawWire(W); P.rectangles(R) DrawRectangle(R); P.contacts(C) DrawContact(C); P.texts(T) DrawText(T); P.holes(H) DrawHole(H); P.polygons(PL) DrawPolygon(PL); mode = no_mode; } void DrawDevice(UL_DEVICESET D, UL_LIBRARY LBR) { string GateAddlevel; string symname; cmd += "DESCRIPTION "+replacenewline(D.description)+";\n"; cmd += "PREFIX '"+D.prefix+"';\n"; cmd += "VALUE "+D.value+";\n"; D.gates(G) { switch (G.addlevel) { case GATE_ADDLEVEL_NEXT : GateAddlevel = "Next"; break; case GATE_ADDLEVEL_MUST : GateAddlevel = "Must"; break; case GATE_ADDLEVEL_CAN : GateAddlevel = "Can"; break; case GATE_ADDLEVEL_REQUEST : GateAddlevel = "Request"; break; case GATE_ADDLEVEL_ALWAYS : GateAddlevel = "Always"; }; h = ""; sprintf(h, "CHANGE Addlevel %s;\n", GateAddlevel); cmd += h; h = ""; sprintf(h, "CHANGE Swaplevel %d;\n", G.swaplevel); cmd += h; if (onelib) symname = LBR.name+"_"+G.symbol.name; else symname = G.symbol.name; h = ""; sprintf(h, "ADD %s '%s' (%f %f);\n", symname ,G.name, u2mic(G.x), u2mic(G.y)); cmd += h; } D.devices(DV) { if (DV.package) { if (onelib) cmd += "PACKAGE '"+LBR.name+"_"+DV.package.name+"' "+DV.name+";\n"; else cmd += "PACKAGE '"+DV.package.name+"' "+DV.name+";\n"; cmd += "TECHNOLOGY "+DV.technologies+";\n"; } DV.gates(G) { G.symbol.pins(P) { if (DV.package) { h = ""; sprintf(h, "CONNECT '%s.%s' '%s';\n", G.name, P.name, P.contact.name); cmd += h; } } } } } //---------------- void OutputUnmistakablePackages (UL_LIBRARY LBR) { PrevName = ""; if (exist_file(WorkPath+CurrentLbrName+".lbr")) { h = ""; sprintf(h, "REMOVE %s;\n", WorkPath+CurrentLbrName+".lbr"); cmd += h; // delete exitsting lbr } h = ""; sprintf(h, "OPEN %s.lbr;\n", WorkPath+CurrentLbrName); cmd += h; CreateHeader(LBR); LBR.packages(P) { if (PrevName != P.name) { logf += " PAC: "+P.name+"\n"; Status = " PAC: "+P.name; dlgRedisplay(); NameIndex = 0; h = ""; sprintf(h, "Edit %s.PAC;\n", P.name); cmd += h; DrawPackage(P); } else { NameIndex++; h = ""; sprintf(h, "Edit %s$%02d.PAC;\n", P.name, NameIndex); cmd += h; //logfile h = ""; sprintf(h, " PAC: %s renamed to %s$%02d\n", P.name, P.name, NameIndex); logf += h; Status = h; dlgRedisplay(); // end logfile DrawPackage(P); } PrevName = P.name; cmd += "DESCRIPTION "+replacenewline(P.description)+";\n"; } } // ---------------------------------------------------------------------------------------- int is_new(void) { // n = nr of entries int i; if (n == 0) return 1; for (i = 0; i < n; i++) { if (x[n] == x[i]) { return(0); } } return 1; } // --------- void CreateOneLibHeader(UL_LIBRARY LBR) { if (exist_file(WorkPath+CurrentLbrName+".lbr")) { h = ""; sprintf(h, "REMOVE %s;\n", WorkPath+CurrentLbrName+".lbr"); cmd += h; // delete exitsting lbr } h = ""; sprintf(h, "OPEN %s.lbr;\n", WorkPath+CurrentLbrName); cmd += h; CreateHeader(LBR); } // --------- void OutputPackages (UL_LIBRARY LBR) { string pacname; LBR.packages(P) { if (onelib) pacname = LBR.name+"_"+P.name; else pacname = P.name; n++; x[n] = pacname; if (is_new()) { logf += " PAC: "+pacname+"\n"; Status = " PAC: "+P.name; dlgRedisplay(); h = ""; sprintf(h, "Edit %s.PAC;\n", pacname); cmd += h; DrawPackage(P); cmd += "DESCRIPTION "+replacenewline(P.description)+";\n"; } } } void OutputSymbols (UL_LIBRARY LBR) { string symname; LBR.symbols(S) { if (onelib) symname = LBR.name+"_"+S.name; else symname = S.name; n++; x[n] = symname; if (is_new()) { logf += " SYM: "+symname+"\n"; Status = " SYM: "+S.name; dlgRedisplay(); h = ""; sprintf(h, "Edit %s.SYM;\n", symname); cmd += h; DrawSymbol(S); } } } void OutputDevices (UL_LIBRARY LBR) { string dname; LBR.devicesets(D) { if (onelib) { dname = LBR.name+"_"+D.name; } else { dname = D.name; } n++; x[n] = dname; if (is_new()) { logf += " DEV: "+dname+"\n"; Status = " DEV: "+D.name; dlgRedisplay(); NameIndex = 0; dname = change_at(dname); h = ""; sprintf(h, "Edit %s.DEV;\n", dname); cmd += h; DrawDevice(D, LBR); } } } // ------------ void make_lbr(void) { if (board) board(B) { in_board = 1; B.libraries(LBR) { CurrentLbrName = change_at(LBR.name); LBR.packages(PAC) { logf += "LIBRARY: "+CurrentLbrName+".lbr\n"; OutputUnmistakablePackages(LBR); cmd += "WRITE;\n"; break; } } CreateTrailer(); } if (schematic) schematic(SCH) { in_board = 0; SCH.libraries(LBR) { CurrentLbrName = change_at(LBR.name); LBR.devices(DEV) { logf += "LIBRARY: "+CurrentLbrName+".lbr\n"; OutputUnmistakablePackages(LBR); n=0; OutputSymbols(LBR); n=0; OutputDevices(LBR); cmd += "WRITE;\n"; break; }; } CreateTrailer(); } } //------------------- void make_one_lbr(void) { if (board) board(B) { in_board = 1; B.libraries(LBR) { CurrentLbrName = change_at(filesetext(EditName, "")); logf += "LIBRARY: "+CurrentLbrName+".lbr\n"; CreateOneLibHeader(LBR); break; } B.libraries(LBR) { n = 0; OutputPackages(LBR); } cmd += "WRITE;\n"; CreateTrailer(); } if (schematic) schematic(SCH) { in_board = 0; SCH.libraries(LBR) { CurrentLbrName = change_at(filesetext(EditName, "")); logf += "LIBRARY: "+CurrentLbrName+".lbr\n"; CreateOneLibHeader(LBR); break; } SCH.libraries(LBR) { n = 0; OutputPackages(LBR); } SCH.libraries(LBR) { n = 0; LBR.devices(DEV) { OutputSymbols(LBR); } } SCH.libraries(LBR) { n = 0; LBR.devices(DEV) { OutputDevices(LBR); } } cmd += "WRITE;\n"; CreateTrailer(); } } // ----------- void show_save_log_file(string cm) { if(show_script) { int R = dlgDialog("Save Log File") { dlgVBoxLayout { dlgLabel("Edit only if you are sure what you do!"); dlgTextEdit(cm); dlgHBoxLayout { dlgPushButton("+Ok") dlgAccept(); dlgPushButton("-Cancel") dlgReject(); } } }; if (R) { LogName = dlgFileSave("Save Script File", WorkPath+PureLogName, "*.log"); if (LogName != "") output(LogName, "wt") printf("%s", cm); } } else { output(WorkPath+PureLogName, "wt") printf("%s", cm); } } // ----------- void show_save_script_file(string cm) { if (show_script) { int R = dlgDialog("Save Script File") { dlgVBoxLayout { dlgLabel("Edit only if you are sure what you do!"); dlgTextEdit(cm); dlgHBoxLayout { dlgPushButton("+Ok") dlgAccept(); dlgPushButton("-Cancel") dlgReject(); } } }; if (R) { ScriptName = dlgFileSave("Save Script File", WorkPath+PureScriptName, "*.scr"); if (ScriptName != "") output(ScriptName, "wt") printf("%s", cm); } } else { ScriptName = WorkPath+PureScriptName; output(ScriptName, "wt") printf("%s", cm); } } //------------ main ---------------------------------------- if (library) { dlgMessageBox(usage + "ERROR


This program can only work in the schematic or package editor."); exit(1); } else { if (board) board(B) EditName = filename(B.name); // name of loaded board/schematic w/o path if (schematic) schematic(S) EditName = filename(S.name); } PureScriptName = filesetext(EditName, ".scr"); // name of generated script w/o path PureLogName = filesetext(EditName, ".log"); // name of generated log msgs w/o path WorkPath = get_project_path(); int Result = dlgDialog("Create Project Library") { string globList[]; int globListIndex = -1; int globCnt = 0; dlgHBoxLayout { dlgStretch(1); dlgSpacing(500); dlgStretch(1); } dlgHBoxLayout { dlgVBoxLayout { dlgGroup("Creation Mode") { dlgRadioButton("&Multiple libraries", onelib); dlgRadioButton("&One library", onelib); } dlgGroup("User Interface") { dlgCheckBox("Show scripts and file dialogs", show_script); dlgCheckBox("Save log file", save_log); } } dlgVBoxLayout { dlgLabel("Log file"); dlgTextView(logf); } } dlgHBoxLayout { dlgLabel(" &Working path:"); dlgStringEdit(WorkPath); dlgPushButton("Bro&wse") { string NewFileName; h = WorkPath; WorkPath = dlgDirectory("Select a directory", WorkPath); if (WorkPath == "") WorkPath = h; } } dlgSpacing(10); dlgHBoxLayout { dlgLabel(Status, 1); dlgStretch(1); dlgPushButton("+&Collect data") {logf = "Project Library Creation Log File "+t2string(time())+"\n" +EAGLE_SIGNATURE+"\nCreated from: "+EditName+"\n\n"; if (onelib) make_one_lbr(); else make_lbr(); show_save_script_file(cmd); Status = ""; dlgRedisplay(); if (save_log) show_save_log_file(logf); } dlgPushButton("Create &library") {if (cmd == "") dlgMessageBox("Use 'Collect data' first!","&OK"); else { exit("SCRIPT "+ScriptName+";\n"); } } dlgPushButton("-&Quit") dlgReject(); dlgSpacing(23); dlgPushButton("&Help") DisplayHelp(); } };