#usage "Create library or libraries from schematic/board
\n" "Can be used to make individual changes to components in a project. " "Just load the schematic, use this ULP to generate a library or several libraries " "containing the used components, make you changes in the library, and use the " "UPDATE command to introduce the changes to the schematic or board.
" "See Help for further details
"
"
\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 that all layers containing objects "
"are used. If in doubt, execute the command
\n"
" SET USED_LAYERS ALL
\n" "If parts coming from old libraries contain objects in forbidden layers, these objects are moved " "automatically to new layers and it is reported in the log file.
\n" "Creation Mode
\n"
"If 'Multiple libraries' is checked, the program generates libraries named
"
" boardname_libraryname
\n"
"where libraryname is the name of the original library the parts are coming from. "
"Otherwise a single project library with the name of the schematic or board is generated. "
"In the latter case the assumption "
"is made that equally named devices, symbols and packages are identical! No checks are "
"performed if this is true. Violating this condition causes errors during the creation process.
\n" "Multiple Symbols
" "This parameter takes effect only if 'One library' is selected. If checked, the symbols of each individual " "library copied into the resulting library. This avoids errors due to " "symbols with the same name which are not identical.
" "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 propted 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 + "'";
}
int exist_file(string FileName) {
string a[];
int n = fileglob(a, FileName);
if (n == 0) return 0;
else return 1;
}
void OutputLayers(UL_LAYER L)
{
int l = L.number;
if ((l==1) || ((l>15) && (l<=51)) || ((l>=91) && (l<=96)) ||(l>=100)) {
h = ""; sprintf(h, "Layer %d %s;\n", L.number, L.name); cmd += h;
}
}
void CreateHeader(UL_LIBRARY LBR)
{
LBR.layers(L) OutputLayers(L);
h = ""; sprintf(h, "Set Wire_bend 2;\nSet Select_factor 0;\nSet Undo_log off;\n"); cmd += h;
h = ""; sprintf(h, "Grid mic 1;\n"); cmd += h;
h = ""; sprintf(h, "Display All;\n"); cmd += h;
cmd += "DESCRIPTION "+replacenewline(LBR.description)+";\n";
}
void CreateTrailer(void)
{
h = ""; sprintf(h, "Set Undo_log On;\nSet Select_factor 0.02;\nGrid last;\n"); cmd += h;
}
void PrintMovedLayer(int LNr, int Offset)
{
h = ""; sprintf(h, "Layer %d L$%d;\n", LNr + Offset, LNr + Offset); cmd += h;
h = ""; sprintf(h, "Layer %d;\n", LNr + Offset); cmd += h;
// logfile
h = ""; sprintf(h, "%s.lbr: Moved Object from Layer %d to Layer %d\n", CurrentLbrName, LNr, LNr + Offset); logf += h; Status = h; dlgRedisplay();
}
void PrintValidLayer(int LNr)
{
/* Move the following layers to
always 52-90 to 150-190
always 97-99 to 191-193
package 91-96 to 194-199
symbol 1-51 to 200-248
*/
int AlwOffset1 = 100;
int AlwOffset2 = 94;
int PackOffset = 103;
int SymbOffset = 199;
if ((LNr >= 52) && (LNr <= 90))
PrintMovedLayer(LNr, AlwOffset1);
if ((LNr >= 97) && (LNr <= 99))
PrintMovedLayer(LNr, AlwOffset2);
if (IsPackage) {
if ((LNr >= 91) && (LNr <= 96)) /* forbidden layers */
PrintMovedLayer(LNr, PackOffset);
else if ((LNr<=51) || (LNr >=100))
h = ""; sprintf(h, "Layer %d;\n", LNr); cmd += h;
}
else { /* symbol */
if (LNr <= 51) /* forbidden layers */
PrintMovedLayer(LNr, SymbOffset);
else if (((LNr>=91) && (LNr <=96)) || (LNr>=100))
h = ""; sprintf(h, "Layer %d;\n", LNr); cmd += h;
};
}
void DrawArc(UL_ARC A)
{
PrintValidLayer(A.layer);
h = ""; sprintf(h, "Arc CCW %f (%f %f) (%f %f) (%f %f);\n",
u2mic(A.width),
u2mic(A.x1), u2mic(A.y1),
u2mic(A.xc + A.xc - A.x1), u2mic(A.yc + A.yc - A.y1),
u2mic(A.x2), u2mic(A.y2));
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);
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;
if (C.pad) {
switch(C.pad.shape[1]) {
case PAD_SHAPE_SQUARE : ShapeString = "Square"; break;
case PAD_SHAPE_ROUND : ShapeString = "Round"; break;
case PAD_SHAPE_OCTAGON : ShapeString = "Octagon"; break;
case PAD_SHAPE_XLONGOCT : ShapeString = "Xlongoct";break;
case PAD_SHAPE_YLONGOCT : ShapeString = "Ylongoct";
}
h = ""; sprintf(h, "Change Drill %f;\n", u2mic(C.pad.drill)); cmd += h;
h = ""; sprintf(h, "Pad %f %s '%s' (%f %f);\n",
u2mic(C.pad.diameter[1]),
ShapeString, C.pad.name,
u2mic(C.pad.x), u2mic(C.pad.y));
cmd += h;
}
else if (C.smd) {
PrintValidLayer(C.smd.layer);
h = ""; sprintf(h, "CHANGE Roundness %d;\n", C.smd.roundness); cmd += h;
h = ""; sprintf(h, "SMD %f %f '%s' (%f %f);\n",
u2mic(C.smd.dx), u2mic(C.smd.dy),
C.smd.name,
u2mic(C.smd.x), u2mic(C.smd.y));
cmd += h;
}
}
void DrawText(UL_TEXT T)
{
string s = "R0";
if (T.angle == 90) (s = "R90");
if (T.angle == 180) (s = "R180");
if (T.angle == 270) (s = "R270");
PrintValidLayer(T.layer);
h = ""; sprintf(h, "Change Size %f;\n", u2mic(T.size)); cmd += h;
h = ""; sprintf(h, "Change Ratio %d;\n", T.ratio); cmd += h;
h = ""; sprintf(h, "Text '%s' %s (%f %f);\n",
T.value, s, u2mic(T.x), u2mic(T.y));
cmd += h;
if (T.mirror) {h = ""; sprintf(h, "Mirror (%f %f);\n", 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) ", 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)
{
IsPackage = 0;
S.circles(C) DrawCircle(C);
S.rectangles(R) DrawRectangle(R);
S.wires(W) DrawWire(W);
S.arcs(A) DrawArc(A);
S.pins(P) DrawPin(P);
S.texts(T) DrawText(T);
S.polygons(PL) DrawPolygon(PL);
}
void DrawPackage(UL_PACKAGE P)
{
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);
}
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 (multiple_symbols)
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) {
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";
}
}
void OutputUnmistakableSymbols (UL_LIBRARY LBR)
{
PrevName = "";
LBR.symbols(S) {
if (PrevName != S.name) {
logf += " SYM: "+S.name+"\n"; Status = " SYM: "+S.name; dlgRedisplay();
NameIndex = 0;
h = ""; sprintf(h, "Edit %s.SYM;\n", S.name); cmd += h;
DrawSymbol(S);
}
else {
NameIndex = NameIndex + 1;
h = ""; sprintf(h, "Edit %s$%02d.SYM;\n", S.name, NameIndex); cmd += h;
// logfile
h = ""; sprintf(h, " SYM: %s renamed to %s$%02d\n", S.name, S.name, NameIndex); logf += h; Status = h; dlgRedisplay();
// end logfile
DrawSymbol(S);
}
PrevName = S.name;
}
}
void OutputUnmistakableDevices (UL_LIBRARY LBR)
{
PrevName = "";
LBR.devicesets(D) {
if (PrevName != D.name) {
logf += " DEV: "+D.name+"\n"; Status = " DEV: "+D.name; dlgRedisplay();
NameIndex = 0;
h = ""; sprintf(h, "Edit %s.DEV;\n", D.name); cmd += h;
DrawDevice(D, LBR);
}
else {
NameIndex = NameIndex + 1;
h = ""; sprintf(h, "Edit %s$%02d.DEV;\n", D.name, NameIndex); cmd += h;
// logfile
h = ""; sprintf(h, " DEV: %s renamed to %s$%02d\n", D.name, D.name, NameIndex); logf += h; Status = h; dlgRedisplay();
DrawDevice(D, LBR);
}
PrevName = D.name;
}
}
// -----------
void make_lbr(void) {
if (board) board(B) {
B.libraries(LBR) {
CurrentLbrName = filesetext(EditName, "")+"_"+LBR.name;
LBR.packages(PAC) {
logf += "LIBRARY: "+CurrentLbrName+".lbr\n";
OutputUnmistakablePackages(LBR);
cmd += "WRITE;\n";
break;
}
}
CreateTrailer();
}
if (schematic) schematic(SCH) {
SCH.libraries(LBR) {
CurrentLbrName = filesetext(EditName, "")+"_"+LBR.name;
LBR.devices(DEV) {
logf += "LIBRARY: "+CurrentLbrName+".lbr\n";
OutputUnmistakablePackages(LBR);
OutputUnmistakableSymbols(LBR);
OutputUnmistakableDevices(LBR);
cmd += "WRITE;\n";
break;
};
}
CreateTrailer();
}
}
// ----------------------------------------------------------------------------------------
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)
{
LBR.packages(P) {
n++;
x[n] = P.name;
if (is_new()) {
logf += " PAC: "+P.name+"\n"; Status = " PAC: "+P.name; dlgRedisplay();
h = ""; sprintf(h, "Edit %s.PAC;\n", P.name); cmd += h;
DrawPackage(P);
cmd += "DESCRIPTION "+replacenewline(P.description)+";\n";
}
else {
logf += " not used PAC: "+P.name+"\n"; Status = " PAC: "+P.name; dlgRedisplay();
}
}
}
void OutputSymbols (UL_LIBRARY LBR)
{
string symname;
LBR.symbols(S) {
if (multiple_symbols)
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);
}
else {
logf += " not used SYM: "+symname+"\n"; Status = " SYM: "+S.name; dlgRedisplay();
}
}
}
void OutputDevices (UL_LIBRARY LBR)
{
LBR.devicesets(D) {
n++;
x[n] = D.name;
if (is_new()) {
logf += " DEV: "+D.name+"\n"; Status = " DEV: "+D.name; dlgRedisplay();
NameIndex = 0;
h = ""; sprintf(h, "Edit %s.DEV;\n", D.name); cmd += h;
DrawDevice(D, LBR);
}
else {
logf += " not used DEV: "+D.name+"\n"; Status = " DEV: "+D.name; dlgRedisplay();
}
}
}
// ------------
void make_one_lbr(void)
{
if (board) board(B) {
B.libraries(LBR) {
CurrentLbrName = filesetext(EditName, "");
logf += "LIBRARY: "+CurrentLbrName+".lbr\n";
CreateOneLibHeader(LBR);
break;
}
n = 0;
B.libraries(LBR) {
LBR.packages(PAC) {
OutputPackages(LBR);
}
}
cmd += "WRITE;\n";
CreateTrailer();
}
if (schematic) schematic(SCH) {
SCH.libraries(LBR) {
CurrentLbrName = filesetext(EditName, "");
logf += "LIBRARY: "+CurrentLbrName+".lbr\n";
CreateOneLibHeader(LBR);
break;
}
n = 0;
SCH.libraries(LBR) {
LBR.devices(DEV) {
OutputPackages(LBR);
}
}
n = 0;
SCH.libraries(LBR) {
LBR.devices(DEV) {
OutputSymbols(LBR);
}
}
n = 0;
SCH.libraries(LBR) {
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(cm);
}
}
else {
output(WorkPath+PureLogName, "wt") printf(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(cm);
}
}
else {
ScriptName = WorkPath+PureScriptName;
output(ScriptName, "wt") printf(cm);
}
}
//------------ main ----------------------------------------
if (library) {
dlgMessageBox(usage + "ERROR