#usage "Renumber the parts of a schematic\n" "

" "Author: support@cadsoft.de" // THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED string Info = "ATTENTION

\n" + "Please verify that your corresponding layout file (if already existing) " + "has been loaded with the schematic file.

\n" + "Otherwise back-/forward-annotation will not work afterwards.

\n" + "This version renumbers only devices with package (no supply) " + "sorted by sheets and coordinates (vertical/descending, horizontal/ascending).

\n" + " You can change the following sorting parameters:

\n" + " descx = 0 (X ascending [left >> right])

\n" + " descx = 1 (X descending [right >> left])

\n" + " descy = 0 (Y ascending)

\n" + " descy = 1 (Y descending)

\n"; string Version = "4.2.0"; int descy = 1; // set to 0 sorting ascending int descx = 0; // set to 1 sorting descending numeric string OldNames[], NewNames[]; int x[], y[], i[], sh[]; int nrNames = 0; numeric string SymNames[]; // Device-Name of Symbol int symsh[]; int sx[], sy[]; int Snr = 0; int Dnr = 0; string error = ""; string SymPrefix[]; string DevPrefix[]; string DevName[]; string SymDevName[]; string cmd; string c; real Grid = 100; // in 100 Mil string lbr[], dev[], sym[]; int GetNumberIndex(string Name) { // Returns the index of the first digit of the numeric part of Name // -1 indicates there is no numeric part in Name int l = strlen(Name) - 1; for (int i = l; i >= 0; --i) { if (!isdigit(Name[i])) return i < l ? i + 1 : -1; } return 0; } string prefix(string name) // Prefix of Device { int num = GetNumberIndex(name); if (num < 1) return name; else { string pfx = name; pfx[num] = 0; return pfx; } } void DescendingY(void) { for (int ny = 0; ny < nrNames ; ny++) { y[ny] = 0 - y[ny]; } } void DescendingX(void) { for (int nx = 0; nx < nrNames ; nx++) { x[nx] = 0 - x[nx]; } } void SortElements(void) { // Sorts the elements according to their location, first by ascending // x coordinates, then by ascending y coordinates. // If you prefer a different kind of sorting, you can implement this here. // As a result, the integer array i[] must contain the new sequence // in which to renumber the elements. if (descy) DescendingY(); if (descx) DescendingX(); sort(nrNames,i, sh, y, x); if (descy) DescendingY(); if (descx) DescendingX(); return; } void GenerateNames(void) { // Generates new numeric parts to the element names in NewNames for (int n = 0; n < nrNames - 1; ++n) { int k = 0; string s = NewNames[i[n]]; if (!isdigit(s[strlen(s) - 1])) { for (int j = n; j < nrNames; ++j) { if (NewNames[i[j]] == s) { sprintf(NewNames[i[j]], "%s%d", NewNames[i[j]], ++k); } } } } return; } void Rename(int x, int y, string New) { // Generates the EAGLE command necessary to change element name Old to New sprintf(c, "Name '%s' (%d %d);\n", New, x, y); cmd += c; return; } void GenerateScript(void) { // Generates an EAGLE script file that does the whole renumbering. // The tricky part here is that we cannot rename an element to a name // that already exists in the schematic (which, e.g. might be necessary if // we had to swap the names of two elements). Therefore we have to // use a ScratchName wherever this is necessary. // If there is nothing to do, the resulting script file will be empty. int ScratchIndex = 0; string ScratchName; int sch = 0; for (int n = 0; n < nrNames; ++n) { if (sh[i[n]] != sch) { sch = sh[i[n]]; // *** change sheet sprintf(c, "Edit .s%d;\n", sch); cmd += c; } if (OldNames[i[n]] != NewNames[i[n]]) { for (int k = n + 1; k < nrNames; ++k) { if (OldNames[i[k]] == NewNames[i[n]]) { sprintf(ScratchName, "$%0*d", ELEMENT_NAME_LENGTH - 1, ++ScratchIndex); if (sh[i[k]] != sch) { sch = sh[i[k]]; // *** change sheet sprintf(c, "Edit .s%d;\n", sch); cmd += c; } Rename(x[i[k]],y[i[k]], ScratchName); if (sh[i[n]] != sch) { sch = sh[i[n]]; // *** change sheet sprintf(c, "Edit .s%d;\n", sch); cmd += c; } OldNames[i[k]] = ScratchName; break; } } if (sh[i[n]] != sch) { sch = sh[i[n]]; // *** change sheet } Rename(x[i[n]],y[i[n]], NewNames[i[n]]); } } return; } // *** check collision befor rename *** string CheckNames(void) { string new_name = ";"; string h; for (int Dn = 0; Dn < Dnr; Dn++ ) { for (int Sn = 0; Sn < Snr; Sn++) { if (DevPrefix[Dn] == SymPrefix[Sn]) { sprintf(h, "# Do not use Prefix %s on Device with Package (%s) and Device without Package (%s)\n", SymPrefix[Sn], DevName[Dn], SymDevName[Sn]); error += h; break; } } } for (int n = 0; n < nrNames - 1; ++n) { // make a long string new_name += NewNames[n] + ";"; } for (int xx = 0; xx < Snr - 1; xx++) { string sd = SymNames[xx]; if(sd[0] == '$') { // if first character a $ on Symbolname error += "# Do not use $ character on first position in device name\n"; sprintf(h, "# RENAME %s on (%.2f %.2f) - sheet %d befor run this ULP again' (%.2f %.2f)\n", SymNames[xx], sx[xx] / 1000.0, sy[xx] / 1000.0, symsh[xx], sx[xx] / 1000.0, sy[xx] / 1000.0); error += h; } int s; int pos = strrstr(new_name, ";" + SymNames[xx] + ";"); if (pos > 0 ) { for (s = 0; s < nrNames - 1; s++) { if(NewNames[s] == SymNames[xx]) { break; } } error += "# Collision by symbol name and device name (eg. Frames, Supply ...)\n"; sprintf(h, "# Rename PREFIX of Device %s on (%.2f %.2f) - sheet %d befor rename %s on (%.2f %.2f) - sheet %d';\n", SymNames[xx], sx[xx] / 1000.0, sy[xx] / 1000.0, symsh[xx], OldNames[s], x[s] / 1000.0, y[s] / 1000.0, sh[s] ); error += h; } } return error; } void setgridmil (void) { sprintf(c, "GRID MIL 100 OFF;\n"); cmd += c; sprintf(c, "DISPLAY NONE 94 95 -96;\n"); cmd += c; return; } void visible(UL_SCHEMATIC S) { sprintf(c, "DISP NONE "); cmd += c; S.layers(L) { if (L.visible) { sprintf(c, "%d ", L.number); cmd += c; } } cmd += ";\n"; return; } void menue(void) { int Result = dlgDialog("Renumber Schematic") { dlgLabel(Info); dlgHBoxLayout { dlgGroup("Sort X") { dlgRadioButton("&Ascending", descx); dlgRadioButton("&Descending", descx); } dlgGroup("Sort Y") { dlgRadioButton("A&scending", descy); dlgRadioButton("D&escending", descy); } } dlgHBoxLayout { dlgPushButton("+&OK") dlgAccept(); dlgStretch(1); dlgPushButton("-&Cancel") dlgReject(); } }; if (!Result) exit (0); return ; } if (schematic) { schematic(S) { menue(); int l = 1; S.sheets(SH) { SH.parts(P) { int n = GetNumberIndex(P.name); if (n > 0) { if (P.device.package) { // **** only Devices with Package // **** without Supply symbol Frames ect... DevPrefix[Dnr] = prefix(P.name); DevName[Dnr] = P.name; ++Dnr; P.instances(I) { int found = -1; for (int fn = 0; fn < nrNames; fn++) { if (OldNames[fn] == P.name) { found = fn; break; } } if (found < 0) { x[nrNames] = u2mil(I.x); // cannot use E.x/y directly because of y[nrNames] = u2mil(I.y); // sort() problem with integers > 32767 OldNames[nrNames] = P.name; // in version 3.50 NewNames[nrNames] = strsub(P.name, 0, n); sh[nrNames] = I.sheet; ++nrNames; } else { if (sh[fn] == I.sheet) { if ( u2mil(I.x) < x[fn] || u2mil(I.y) > y[fn] ) { // tausche wenn x kleiner oder y groesser x[fn] > u2mil(I.x); y[fn] > u2mil(I.y); } } } } } // Only Symbol (Supply, Port, Frame...) else { // *** check PartName on Symbols Supply, Port, Frame ... *** SymPrefix[Snr] = prefix(P.name); SymDevName[Snr] = P.name; P.instances(I) { SymNames[Snr] = P.name; // Device-Name of Symbol sx[Snr] = u2mil(I.x); // cannot use E.x/y directly because of sy[Snr] = u2mil(I.y); // sort() problem with integers > 32767 symsh[Snr] = I.sheet; ++Snr; break; } } } } } SortElements(); GenerateNames(); setgridmil (); GenerateScript(); if (CheckNames()) { int select; dlgDialog("Symbol ref Device Names") { dlgVBoxLayout { dlgLabel("Warnings for renumber!"); dlgTextView(error); } dlgHBoxLayout { dlgSpacing(450); } dlgHBoxLayout { dlgPushButton("+&OK") dlgAccept(); dlgStretch(1); } }; exit (-1); } sprintf(c, "GRID INCH 0.1;\n"); cmd += c; sprintf(c, "EDIT .S1;\n"); cmd += c; visible(S); exit (cmd); } } else { dlgMessageBox("\n Start this ULP in a Schematic \n"); exit (0); }