#usage "en: Find single-ended wires (wire stubs)" "

" "Find single-ended wires that don't start or end at another wire, via or pad.
" "Starting the ulp without parameter generates a list. " "The temporary list (file) will be deleted as soon as you quit EAGLE.
" "After running this ULP the MOVE command will be active. Now you should move this wire at a position where you can
" "select it easily with the RIPUP command." "
" "RUN find-single-ended-wire [+] [-] [M] [=]" "" "" "" "" "" "
+ shows the next entry of the list (trace).
- shows the previous entry of the list (trace)
= shows this message again
M defines a 0.1 micron group around this coordinate and activates the MOVE command
" "When using the parameters + and - for purposes of clarity only the layer that contains " "the wire is displayed. Possibly plus the layer(s) Pads and/or Vias.
" "For recognizing the wire stubs it is necessary to set the fill style of the respective layer " "to not filled (dotted or hatched).

" "NOTE: WIREs or VIAs that end in a polygon's area, are recognized as single-ended!
" "To avoid mistake use RATSNEST to calculate the polygons before. Now you can start the ULP!
" "

" "Autor: support@cadsoft.de" , "de: Find single ended wire." "

" "Findet WIREs die nicht an einem Pad, Via oder einem anderen Wire beginnen bzw. enden (Stummel).
" "Der Start des ULP ohne Parameter erzeugt eine Liste (Datei) der Wire, die zum einzeln durchschalten benutzt werden kann.
" "Die Liste (Datei) wird nur temporär erzeugt und beim Beenden von Eagle gelöscht." "
" "RUN find-single-ended-wire [+] [-] [M] [=]" "" "" "" "" "" "
+ zeigt den nächsten Eintrag in der Liste der gefundenen Elemente
- zeigt den vorhergehenden Eintrag in der Liste der gefundenen Elmente
= zeige den aktuellen Eintrag nochmal
M Definiert einen Bereich von 0.1 Mircon als Gruppe um die Koordinate und aktiviert den MOVE-Befehl
" "Nach dem Beenden des ULP ist der MOVE-Befehl aktiv. Damit kann der Wire zuerst aus dem " "Bereich herausgezogen werden um ihn eindeutig mit dem RIPUP-Befehl zu selektieren.
" "Um die Übersichtlichkeit zu erhöhen wird bei der Weiterschaltung mit + oder - nur der " "Layer in dem sich der Wire-Stummel befindet, plus eventuell der Pad-Layer und/oder " "Via-Layer eingeblendet.
" "Um die Wire-Stummel innerhalb eines Pad oder Via zu erkennen ist es nötig das Füllmuster der " "entsprechenden Layer auf nicht füllend (gepunktet oder schraffiert) einzustellen.

" "ACHTUNG: WIREs oder VIAs, die in einer Polygonfläche enden, werden ebenfalls als Single-Ended erkannt!
" "Um Verwechslungen auszuschliessen lassen Sie mit RATSNEST zuerst die Polygonflächen berechnen und starten dann das ULP!
" "

" "Autor: support@cadsoft.de" string Version = "1.01"; // 2007-04-03 alf@cadsoft.de // 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de #require 4.1600; int test = 0; enum { typeW, typeS, typeP, typeV }; string Typ[] = { "Wire", "Smd", "Pad", "Via" }; int sameL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int sameS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int padL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int viaL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int viaStackS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int viaStackE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int ncoord = 0; int wx[]; // X coordinate int wy[]; // Y coordinate int wl[]; // Layer int ws[]; // Start Layer for Via & Pad, Smd and Wire int we[]; // End Layer for Via & Pad, Smd and Wire == Start Layer int wt[]; // Type int index[]; string cmd, s; string h; string file, memory; string cmdr[]; // ### ---------------- functions ------------------- ### void set_layer(int lay, int s_lay, int e_lay, int type) { switch(type) { case typeW : // Wire sameL[lay]++; break; case typeS : // Smd sameL[lay]++; sameS[lay]++; break; case typeP : // Pad for (int pl = 1; pl < 18; pl++) { padL[pl]++; } sameL[17]++; break; case typeV : // Via for (int vl = s_lay; vl <= e_lay; vl++) { viaL[vl]++; } viaStackS[viaL[18]] = s_lay; viaStackE[viaL[18]] = e_lay; viaL[18]++; break; } return; } // ### claer counter ### void clear_same_counter(void) { for (int n = 0; n < 19; n++) { viaL[n] = 0; padL[n] = 0; sameS[n] = 0; sameL[n] = 0; viaStackS[n] = 0; viaStackE[n] = 0; } return; } // #*#*#* check via stack and if via routet on more as 1 layer *#*#*# void check_via(int k, string sigName) { int cntViaOverLap[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; string usedWireLayer = ""; int nV = 0; for (nV = 0; nV < viaL[18]; nV++) { // ### Via Stack usedWireLayer = ""; int wire_on_stack_via = 0; for (int n = viaStackS[nV]; n <= viaStackE[nV]; n++) { cntViaOverLap[n]++; if (sameL[n]) { sprintf(s, " %d", n); usedWireLayer += s; wire_on_stack_via++; } } if (wire_on_stack_via < 2) { if (!wire_on_stack_via) { if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 18\tNur VIA von Layer %d - %d, Signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), viaStackS[nV], viaStackE[nV], viaStackS[nV], viaStackE[nV], sigName ); else sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 18\tOnly VIA from layer %d - %d, signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), viaStackS[nV], viaStackE[nV], viaStackS[nV], viaStackE[nV], sigName ); } else { if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tZu wenig WIRE: Nur in Layer %s an VIA von Layer %d - %d geroutet, Signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), usedWireLayer, usedWireLayer, viaStackS[nV], viaStackE[nV], sigName ); else sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tOnly WIRE on layer %s on VIA from layer %d - %d, signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), usedWireLayer, usedWireLayer, viaStackS[nV], viaStackE[nV], sigName ); } cmd += s; } } if (viaL[18]) { // ### check via layer overlap ### string ViaOverlap = ""; int cnt; for (cnt = 1; cnt < 17; cnt++) { if (cntViaOverLap[cnt] > 1) { sprintf(s, " %d", cnt); ViaOverlap += s; } } if (ViaOverlap) { if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tVIAs Stack-Überlappung in Layer %s, Signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), ViaOverlap, ViaOverlap, sigName ); else sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tVIAs stack overlap on layer %s, signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), ViaOverlap, ViaOverlap, sigName ); cmd += s; } } return; } // ### check count of elements on coordinate ### void check_same(int k, string sigName) { if (!sameL[17]) { // ### Pads können kein Single-Ended-Wire sein ### if (viaL[18]) { check_via(k, sigName); } else { for (int n = 1; n <= 16; n++) { if (sameL[n]) { if (sameL[n] + viaL[n] + sameS[n] < 2) { if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d \tNur 1 WIRE im Layer %d von Signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), n, n, sigName); else sprintf(s, "WINDOW (%.4f %.4f);\t %d \tFew WIRE on layer %d at signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), n, n, sigName); cmd += s; } } } } } if (padL[17] && viaL[18]) { if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 17 18\tPAD und VIA an gleicher Koordinate, Signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), ws[index[k]], we[index[k]], sigName); else sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 17 18\tPAD and VIA on same coordinate, signal %s\n", u2mm(wx[index[k]]), u2mm(wy[index[k]]), ws[index[k]], we[index[k]], sigName); cmd += s; } return; } // check multiple coordinates or one coordinate on this Signal void checkcoord(string sigName) { int n = 0; h = ""; sort(ncoord, index, wx, wy, wl, wt); // in Order - Coordinates - Layer - Type n = 0; clear_same_counter(); if (ncoord > 1) { // ### loop ### do { set_layer(wl[index[n]], ws[index[n]], we[index[n]], wt[index[n]]); if (wx[index[n+1]] == wx[index[n]] && wy[index[n+1]] == wy[index[n]] ) { n++; } else { check_same(n, sigName); clear_same_counter(); n++; } } while (n < ncoord); check_same(n, sigName); } else check_same(n, sigName); return; } // collect coordinates void add(int x, int y, int lay, int l_start, int l_end, int type) { wx[ncoord] = x; wy[ncoord] = y; wl[ncoord] = lay; ws[ncoord] = l_start; we[ncoord] = l_end; wt[ncoord] = type; ncoord++; return; } // ### main ### if (board) { board(B) { string trace_file = filesetext(B.name, "~~.sew"); // single endet wire string memory_file = filesetext(B.name, "~~.mlc"); // memory line counter if (!argv[1]) { dlgMessageBox(usage, "OK"); B.signals(S) { status(" check "+S.name); ncoord = 0; S.wires(W) { if (W.layer < 17) { add(W.x1, W.y1, W.layer, W.layer, W.layer, typeW); add(W.x2, W.y2, W.layer, W.layer, W.layer, typeW); } } S.contactrefs(C) { if (C.contact.smd) { add(C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, typeS); } else { add(C.contact.pad.x, C.contact.pad.y, 17, 1, 16, typeP); } } S.vias(V) { add(V.x, V.y, 18, V.start, V.end, typeV); } checkcoord(S.name); } output(trace_file, "wtD") printf("%s", cmd); output(memory_file, "wtD") printf("-1"); exit("RUN '" + argv[0] + "' +\n"); } // ### trace listed points by key "+" "-" else { string m_cmd[]; int n = fileread(m_cmd, memory_file); // memory line counter int cnt = strtol(m_cmd[0]); string lines[]; n = fileread(lines, trace_file); // single endet wire if (!n) { dlgMessageBox("No single ended WIRE found!", "OK"); exit(0); } else if (argv[1] == "+" || argv[1] == "-" || argv[1] == "=" || strupr(argv[1]) == "M") { if (argv[1] == "+") { if (cnt < n-1) cnt++; else { if (language() == "de") dlgMessageBox("Letze Position!", "OK"); else dlgMessageBox("The last position in list!", "OK"); } } else if (argv[1] == "-") { if(cnt) cnt--; else { if (language() == "de") dlgMessageBox("Erste Position!", "OK"); else dlgMessageBox("The first position in list!", "OK"); } } else if (strupr(argv[1]) == "M") { n = strsplit(cmdr, lines[cnt], '('); string Display = ""; n = strsplit(m_cmd, cmdr[1], ')'); n = strsplit(cmdr, m_cmd[0], ' '); real x = strtod(cmdr[0]); real y = strtod(cmdr[1]); sprintf(Display, "GROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (>%.4f %.4f);\nMOVE (>%.4f %.4f)", x-0.0001, y-0.0001, x+0.0001, y-0.0001, x+0.0001, y+0.0001, x-0.0001, y+0.0001, x-0.0001, y-0.0001, x, y ); exit(Display); } else if (argv[1] == "="); } else { if (language() == "de") dlgMessageBox("Unbekannter Parameter!", "OK"); else dlgMessageBox("Unknown parameter!", "OK"); exit(0); } n = strsplit(cmdr, lines[cnt], '\t'); string Display = ""; if (m_cmd[1] != cmdr[1]) { sprintf(Display, "DISPLAY NONE %s ;\n", cmdr[1]); } output(memory_file, "wtD") printf("%d\n%s", cnt, m_cmd[1]); // save the last pointer exit("GRID mm;\n"+Display+cmdr[0]+"RUN ulpmessage '"+cmdr[2]+"';"+"MOVE"); // activate th move command } } } else { if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Board", "OK"); else dlgMessageBox("Start this ULP in a Board", "OK"); }