#usage "Renumber the parts of a schematic

" "1 step:
This version checks of empty prefix in deviceset, and check if the deviceset prefix even used prefix.
" "2 step:
If not set a prefix in used deviceset, you can select a device to open the device of library to correct the prefix.
" "3 step:
Option to update the library
" "4 step:
Renumber
" "Please follow the instructions.

" "This version use the defined prefix of deviceset to renumber parts.
" "This version renumbers devices with and without packages (no supply) " "sorted by sheets and coordinates (vertical/descending, horizontal/ascending).
" "Optional: The starting point for the numeration of parts on the first sheet " "defines an offset value for the following pages.
" "Example:
" " - 0 = R1 ... Rn
" " - 100 sheet 1: R101..R199 sheet 2: R201..R299 ...
" " - 500 sheet 1: R501..R999 sheet 2: R1001..R1499 ...
" " - 1000 sheet 1: R1001..R1999 sheet 2: R2001..R2999 ...
" "

" "Author: support@cadsoft.de" // THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED #require 6.0500 string Version = "ULP Version 5.0.2"; // 2006.08.23 alf@cadsoft.de // correct counter if crossing page by same prefix // 2008.01.30 alf@cadsoft.de // renumber only the current sheet by start sheet-number * numerical_order // 2012-06-21 - corrected sort by Weighting of emphasis in Y-direction // alf@cadsoft.de // 2013-03-19 - do not use devicesets without prefix od parts with prefix "U$" // 1. check PREFIX of Parts in used deviceset // 2. update librarie // 3. flag for renumber also symbol without package // 2013-08-19 - Rename by old-name new-name, if more gates on same origin // 2013-09-09 - now more Prefixes allowed for "do not renumber with prefix", separated by ";" // 2016-03-07 - the ULP no longer switches off the grid in the schematic, support@cadsoft.de string Info = "ATTENTION

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

" + "Otherwise back-/forward-annotation will not work afterwards."; string Infoplus = " You can change the following sorting parameters:

" + " descx = 0 (X ascending [left >> right])
" + " descx = 1 (X descending [right >> left])
" + " descy = 0 (Y ascending [bottom >> top])
" + " descy = 1 (Y descending [top >> bottom])
"; int descy = 1; // set to 0 sorting ascending int descx = 0; // set to 1 sorting descending int numerical_order = 0; // sort from sheet 1, or sort by start counter for sheet int emphases = 0; // weighting of emphases first X second Y or first Y second X int actual_sheet = 0; // 2008.01.30 int only_actual_sheet = 0; // 2008.01.30 string sheet_info = ""; numeric string OldNames[], NewNames[], Prefix[]; int x[], y[], Index[], Sheet[]; int nrNames = 0; numeric string SymNames[]; // Device-Name of Symbol int symsh[]; int SymX[], SymY[]; int Snr = 0; int Dnr = 0; string Error = ""; string SymPrefix[]; string DevPrefix[]; string DevName[]; string SymDevName[]; int RenumWithoutPackage = 1; // 2013-03-19 string NoPrefixRenumber = "TP"; // Prefix do not renumber Testpoints int ckx[], cky[], cksh[]; string ckname[]; string Cmd; string c; real Grid = 100; // in 100 Mil string lbr[], dev[], sym[]; /* first check PREFIX 2013-03-19 **/ string UndefinedPrefix = "U$"; // all parts without prefix in deviceset, get a name U$ by ADD numeric string RealPartName[], RealRrefix[]; int CntRN = 0; string PartName[], PartDeviceSet[], PartLib[], PartPrefix[]; int PartSheet[]; int PartX[], PartY[], X, Y; int CntP = 0; string List[]; string PrefixError[]; int CntNoDevPrefix = 0; int CntNoPartPrefix = 0; /* first check PREFIX 2013-03-19 */ /****************** Functions **********************/ /******** first check PREFIX 2013-03-19 ************/ int getnum(string name, string prefix) { int len = strlen(prefix); return strtol(strsub(name, len)); } int getlastnum(string prefix) { int foundstart = 0; int foundlast = 0; for (int n = 0; n < CntRN; n++){ if (RealRrefix[Index[n]] == prefix) { foundstart = n; } else { if (foundstart) { foundlast = foundstart; } else { if (foundlast) { return getnum(RealPartName[Index[foundstart]], RealRrefix[Index[foundstart]]); } } } } return 0; } int checksheet(UL_PART P) { P.instances(I) { if (I.sheet) { X = I.x; Y = I.y; return I.sheet; } } dlgMessageBox("!Das darf nicht vorkommen, Instance auf keinem Sheet.", "OK"); exit(-99); } void opendev(int sel) { string s[]; int cnt = strsplit(s, PrefixError[sel], '\t'); string cmd; sprintf(cmd, "OPEN '%s';EDIT '%s.DEV';PREFIX", s[1], s[2]); exit(cmd); } void updatedev(int sel) { string s[]; int cnt = strsplit(s, PrefixError[sel], '\t'); string cmd; sprintf(cmd, "UPDATE '%s'; RUN '%s'", s[1],argv[0]); exit(cmd); } /******** first check PREFIX 2013-03-19 ************/ 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 Index = l; Index >= 0; --Index) { if (!isdigit(Name[Index])) return Index < l ? Index + 1 : -1; } return 0; } string GetPrefix(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]; } return; } void DescendingX(void) { for (int nx = 0; nx < nrNames ; nx++) { x[nx] = 0 - x[nx]; } return; } 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 Index[] must contain the new sequence // in which to renumber the elements. // 2008-07-24 alf, weighting of emphases first X second Y or first Y second X if (descy) DescendingY(); if (descx) DescendingX(); if(!numerical_order) { if (!emphases) sort(nrNames, Index, NewNames, Sheet, x, y); else sort(nrNames, Index, NewNames, Sheet, y, x); } else { if (!emphases) sort(nrNames, Index, Sheet, NewNames, x, y); if (emphases) sort(nrNames, Index, Sheet, NewNames, y, x); // 2012-06-21 correct sort on emphases } if (descy) DescendingY(); if (descx) DescendingX(); return; } /********** in V6 not more used while new option NAME Oldname Newname 2013-08-19 void CheckSameOrigin(int chk) { // eagle can not rename an element // if another element is on the same coordinate int index[]; string checklist, h; sort(chk, index, cksh, ckx, cky); for (int n = 0; n < nrNames; n++) { if(ckx[index[n]] == ckx[index[n+1]] && cky[index[n]] == cky[index[n+1]] && cksh[index[n]] == cksh[index[n+1]]) { sprintf(h, "%s & %s on same coordinate (%d %d) mil in sheet %d\n", ckname[index[n]], ckname[index[n+1]], ckx[index[n]], cky[index[n]], cksh[index[n]]); checklist += h; } } if (checklist) { dlgDialog("Check coordinates") { dlgLabel("Eagle can not rename elements that are placed at the same position!"); dlgHBoxLayout { dlgSpacing(300); } dlgTextView(checklist); dlgHBoxLayout { dlgPushButton("Break") dlgAccept(); dlgStretch(1); } }; exit(0); } return; } ********/ void GenerateNames(void) { string memprefix = ""; int mem_sh = 0; if(!numerical_order) { // Generates new numeric parts to the element names in NewNames int k; for (int n = 0; n <= nrNames - 1; ++n) { if (memprefix != NewNames[Index[n]]) { memprefix = NewNames[Index[n]]; k = 0; } sprintf(NewNames[Index[n]], "%s%d", NewNames[Index[n]], ++k); } } else { // renumber sheets by 100.. 200.. 300.. string h; int newdevnr; for(int n = 0; n < nrNames ; ++n) { if (memprefix != NewNames[Index[n]]) { memprefix = NewNames[Index[n]]; newdevnr = numerical_order * Sheet[Index[n]] +1; } if (mem_sh != Sheet[Index[n]]) { // a new Sheet is starting by old prefix *** 2006.08.23 alf@cadsoft.de mem_sh = Sheet[Index[n]]; newdevnr = numerical_order * Sheet[Index[n]] +1; } sprintf(NewNames[Index[n]], "%s%d", NewNames[Index[n]], newdevnr); newdevnr++; if (newdevnr-(Sheet[Index[n]]*numerical_order) >= numerical_order) { sprintf(h, "More parts with prefix '%s' than starting point %d on sheet %d
Start the ulp with numerical order >= %d
", memprefix, numerical_order, Sheet[Index[n]], numerical_order*10); dlgMessageBox(h, "Break"); exit(0); } } } return; } void Rename(int x, int y, string Old, string New) { // Generates the EAGLE command necessary to change element name Old to New //sprintf(c, "Name '%s' (%d %d);#297\n", New, x, y); sprintf(c, "NAME '%s' '%s';#298\n", Old, New); // 2013-08-19 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. string ScratchName[]; int sch = 0; int n; int t = time(); for ( n = 0; n < nrNames; ++n) { if (Sheet[Index[n]] != sch) { sch = Sheet[Index[n]]; // *** change sheet sprintf(c, "Edit .s%d;\n", sch); Cmd += c; } sprintf( ScratchName[Index[n]], "$%d_%d_$_%s", sch, n, t2string(t, "Uyyyy-MM-dd_hh-mm-ss")); // 2013-03-19 verhindert Problem für temporäre umbenenung falls früherer Durchlauf abgebrochen Rename(x[Index[n]],y[Index[n]], OldNames[Index[n]], ScratchName[Index[n]]); } for ( n = 0; n < nrNames; ++n) { if (Sheet[Index[n]] != sch) { sch = Sheet[Index[n]]; // *** change sheet sprintf(c, "Edit .s%d;\n", sch); Cmd += c; } Rename(x[Index[n]],y[Index[n]], ScratchName[Index[n]], NewNames[Index[n]]); } return; } // *** check collision before 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 is a $ on Symbolname Error += "# Do not use $ character at first position in device names\n"; sprintf(h, "# RENAME %s at (%.4f %.4f) - sheet %d before running this ULP again' (%.4f %.4f)\n", SymNames[xx], SymX[xx] / 1000.0, SymY[xx] / 1000.0, symsh[xx], SymX[xx] / 1000.0, SymY[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 of symbol name and device name (eg. Frames, Supply ...)\n"; sprintf(h, "# Rename PREFIX of Device %s at (%.4f %.4f) - sheet %d before renaming %s at (%.4f %.4f) - sheet %d';\n", SymNames[xx], SymX[xx] / 1000.0, SymY[xx] / 1000.0, symsh[xx], OldNames[s], x[s] / 1000.0, y[s] / 1000.0, Sheet[s] ); Error += h; } } return Error; } void setgridmil (void) { sprintf(c, "GRID MIL 100;\n"); Cmd += c; // ## only display layer 94 (symbol) if placed a text // ## at symbol origin. 15.06.2004 alf@cadsoft.de //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); } dlgGroup("Weighting of emphases") { dlgRadioButton("X-direction", emphases); dlgRadioButton("Y-direction", emphases); } dlgStretch(1); } dlgHBoxLayout { dlgLabel("Do not renumber parts with &Prefixes (separated by ';')"); dlgStringEdit(NoPrefixRenumber); dlgStretch(1); } dlgHBoxLayout { dlgCheckBox("Renumber parts without package ", RenumWithoutPackage); // 2013-03-19 dlgStretch(1); } dlgHBoxLayout { dlgVBoxLayout dlgSpacing(180); dlgGroup("Sheet") { dlgLabel("Start numbering for sheet at:"); dlgLabel(" - 0 numeration R1...Rn"); dlgLabel(" - 100 sheet 1: R101..R199, sheet 2: R201..R299, ..."); dlgLabel(" - 1000 sheet 1: R1001..R1999, sheet 2: R2001..R2999, ..."); dlgSpacing(10); dlgHBoxLayout { dlgLabel("&Numerical order "); dlgIntEdit(numerical_order, 0, 10000); dlgStretch(1); } dlgVBoxLayout dlgSpacing(10); dlgCheckBox("Sort in numerical order on the ¤t sheet only", only_actual_sheet) { if (only_actual_sheet) { if (numerical_order) { sprintf(sheet_info, "The starting number of current sheet is %d", actual_sheet * numerical_order); } else { sprintf(sheet_info, "Please check the numerical order!"); } } else { if (!numerical_order) sprintf(sheet_info, "The starting number is 1"); else sprintf(sheet_info, "The starting number on sheet is X * %d", numerical_order); } } dlgVBoxLayout dlgSpacing(10); dlgLabel(sheet_info, 1); dlgStretch(1); } } dlgHBoxLayout { dlgPushButton("+&OK") { if (only_actual_sheet && !numerical_order) { sprintf(sheet_info, "Please check the numerical order!"); dlgMessageBox(sheet_info, "OK"); } else dlgAccept(); } dlgSpacing(15); dlgPushButton("-Cancel") dlgReject(); dlgSpacing(15); dlgLabel(Version); dlgStretch(1); dlgPushButton("&Help") dlgMessageBox(usage, "OK"); } }; if (!Result) exit (0); return ; } if (schematic) { /******** 1 step: check empty and uneven prefix 2013-03-19 ************/ schematic(SCH) { SCH.parts(P) { if (!P.deviceset.prefix || strstr(P.name, UndefinedPrefix) == 0 || strstr(P.name, "$") == 0 || strstr(P.name, P.deviceset.prefix) < 0 ) { PartName[CntP] = P.name; PartDeviceSet[CntP] = P.deviceset.name; PartLib[CntP] = P.deviceset.library ; PartPrefix[CntP] = P.deviceset.prefix; PartSheet[CntP] = checksheet(P); PartX[CntP] = X; PartY[CntP] = Y; sprintf(List[CntP], "%s\t%s\t%s\t%s\t%d", PartName[CntP], PartLib[CntP], PartDeviceSet[CntP], PartPrefix[CntP], PartSheet[CntP] ); if (!PartPrefix[CntP] || PartPrefix[CntP] == UndefinedPrefix ) { PrefixError[CntNoDevPrefix] = List[CntP]; CntNoDevPrefix++; } if (strstr(PartName[CntP], UndefinedPrefix) == 0 || strstr(PartName[CntP], "$") == 0 || strstr(P.name, P.deviceset.prefix) < 0) { RealPartName[CntRN] = P.deviceset.prefix; RealRrefix[CntRN] = P.name; CntRN++; } CntP++; } } } /******** 1 step: check device prefix (library) ********/ int sel = -1; if (CntNoDevPrefix) { string Status; sprintf(Status, "Step 1: Found %d PARTS without PREFIX in deviceset", CntNoDevPrefix+1); dlgDialog("Prefix check") { dlgLabel(Status); dlgHBoxLayout dlgSpacing(550); dlgHBoxLayout { dlgVBoxLayout dlgSpacing(500); dlgListView("Name\tLib\tDevideset\tPrefix\tSheet", PrefixError, sel) opendev(sel); } dlgLabel("Do not use empty PREFIX in deviceset or 'U$' as part prefix!"); dlgLabel("First check and set PREFIX in library (deviceset) and then UPDATE library."); dlgHBoxLayout { dlgPushButton("OK") { if (sel < 0) { dlgMessageBox("First select a part, to set prefix in library.", "OK"); } else opendev(sel); } dlgPushButton("UPDATE") { if (sel < 0) { dlgMessageBox("First select a part, to UPDATE this library.", "OK"); } else updatedev(sel); } dlgPushButton("UPDATE ALL") { dlgReject(); exit("UPDATE; RUN '"+argv[0]+"'"); } dlgPushButton("CANCEL") { dlgReject(); exit(-2); } } }; exit("UPDATE"); } /******** 2 step: rename uneven part prefix by deviceset prefix ********/ sort(CntRN, Index, RealPartName); int i[]; sort(CntP, i, PartPrefix); // nach dem Prefix der LBR sortiert string actprefix = ""; int cntnumber; string s, cmd; for (int n; n < CntRN; n++) { if (actprefix != PartPrefix[i[n]]) { cntnumber = getlastnum(PartPrefix[i[n]]); actprefix = PartPrefix[i[n]]; sprintf(s, "EDIT .s%d; NAME '%s%d' (%.6fmil %.6fmil);\n", PartSheet[i[n]], PartPrefix[i[n]], ++cntnumber, u2mil(PartX[i[n]]), u2mil(PartY[i[n]]) ); cmd+=s; } else { sprintf(s, "EDIT .s%d; NAME '%s%d' (%.6fmil %.6fmil);\n", PartSheet[i[n]], PartPrefix[i[n]], ++cntnumber, u2mil(PartX[i[n]]), u2mil(PartY[i[n]]) ); cmd+=s; } } /* if (CntRN) { dlgDialog("Step 2: Rename Part by Device-PREFIX") { dlgHBoxLayout dlgSpacing(450); dlgHBoxLayout { dlgVBoxLayout dlgSpacing(450); dlgTextEdit(cmd); } dlgHBoxLayout { // wenn der Origin des Symbol auf einem Kontaktpunkt liegt, wird das NET umbenannt, nicht das PART! dlgPushButton("RUN SCRIPT") { dlgAccept(); exit("DISPLAY NONE 94;" + cmd + "DISPLAY LAST; RUN '"+argv[0]+"'"); } dlgStretch(1); dlgPushButton("CANCEL") { dlgReject(); exit(-2); } } }; } */ /******** end check PREFIX 2013-03-19 ************/ /******** 4 step: renumber ********/ if (sheet) { sheet(S) actual_sheet = S.number; sprintf(sheet_info, "The current sheet is %d", actual_sheet); } schematic(S) { menue(); int l = 1; int chk; string NoRenumPrefixes[]; // 2013-09-09 int nPrefixes = strsplit(NoRenumPrefixes,NoPrefixRenumber,';'); S.sheets(SH) { if (only_actual_sheet) { ; // do not change the actual sheet number } else { actual_sheet = SH.number; // set the numer to actuel sheet number } if (actual_sheet == SH.number) { // 2008.01.30 SH.parts(P) { // 2013-03-19 int n = GetNumberIndex(P.name); // 2013-03-19if (n > 0) { if (P.device.package || RenumWithoutPackage) { // **** only Devices with Packages // **** without Supply symbol Frames ect... // **** DO NOT RENUMBER Elements with this PREFIXES // 2013-03-19 if (GetPrefix(P.name) == NoPrefixRenumber); old verison //if (P.deviceset.prefix == NoPrefixRenumber); int skipRenumber = 0; // 2013-09-09 for (int i = 0; i < nPrefixes && !skipRenumber; ++i) { if (GetPrefix(P.name) == NoRenumPrefixes[i]) skipRenumber = 1; } if (skipRenumber || GetPrefix(P.name) == NoPrefixRenumber); else { // 2013-03-19 DevPrefix[Dnr] = GetPrefix(P.name); old version DevPrefix[Dnr] = P.deviceset.prefix; 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] = P.deviceset.prefix;; // 2013-03-19 strsub(P.name, 0, n); Sheet[nrNames] = I.sheet; Prefix[nrNames] = P.deviceset.prefix; // 2013-03-19 GetPrefix(P.name); ++nrNames; } else { if (Sheet[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] = GetPrefix(P.name); SymDevName[Snr] = P.name; P.instances(I) { SymNames[Snr] = P.name; // Device-Name of Symbol SymX[Snr] = u2mil(I.x); // cannot use E.x/y directly because of SymY[Snr] = u2mil(I.y); // sort() problem with integers > 32767 symsh[Snr] = I.sheet; ++Snr; break; } } // 2013-03-19 } P.instances(I) { ckx[chk] = u2mil(I.x); // cannot use E.x/y directly because of cky[chk] = u2mil(I.y); // sort() problem with integers > 32767 ckname[chk] = I.name; cksh[chk] = I.sheet; chk++; } } } // 2008.01.30 } //CheckSameOrigin(chk); 2013-08-19 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 .S%d;\n", actual_sheet); Cmd += c; visible(S); string fname = filesetext(S.name, "~renumsch.scr"); output(fname, "wtD") printf("%s", Cmd); exit ("SCRIPT '" + fname + "';"); } } else { dlgMessageBox("\nStart this ULP in a Schematic\n"); exit (0); }