/* * This EAGLE User Language Program performs several checks on the * nets of a schematic. These checks have been implemented as an * addition to the builtin ERC, and shall later be incorporated in * the editor itself. * * Error messages and warnings are written into a file named after * the schematic, with the extension ".AEC" (Additional Electrical Checks). * * Please send comments to kls@cadsoft.de. */ // Add further "known supply names" to this array if necessary: string SupplyNames[] = { "GND", "GNDA", "VCC", "VDD", "VSS", "0V", "+5V", "-5V", "+12V", "-12V", "+18V", "-18V", "+24V", "-24V" }; int NetWireAt(UL_SHEET Sheet, int x, int y) { Sheet.nets(N) { N.segments(S) { S.wires(W) { if (W.x1 == x && W.y1 == y || W.x2 == x && W.y2 == y) return 1; } } } return 0; } schematic(SCH) { output(filesetext(SCH.name, ".AEC")) { // Check for segments that have a known supply name, but are // not connected to any supply pin: SCH.sheets(SH) { SH.nets(N) { // Check if we have a known supply net: int i = 0, IsSupply = 0; do { if (N.name == SupplyNames[i]) { IsSupply = 1; break; } } while (SupplyNames[i++]); N.segments(S) { if (IsSupply) { int ConnectedToSupply = 0; S.pinrefs(PR) { if (PR.pin.direction == PIN_DIRECTION_SUP) { ConnectedToSupply = 1; break; } } if (!ConnectedToSupply) { // Let's find some point to identify this segment: int x, y, FoundWire = 0; S.wires(W) { x = (W.x1 + W.x2) / 2; y = (W.y1 + W.y2) / 2; FoundWire = 1; break; // the first wire will do } if (!FoundWire) { S.pinrefs(PR) { x = PR.pin.x; y = PR.pin.y; break; } } printf("WARNING: Sheet %d, Net '%s', Segment at (%f,%f) has no supply pin!\n", SH.number, N.name, u2inch(x), u2inch(y)); } } } } } // Check for junctions that only appear to connect wires: SCH.sheets(SH) { string NetName[]; int jx[], jy[], jd[], NumJunctions = 0; // Collect all junctions: SH.nets(N) { N.segments(S) { S.junctions(J) { NetName[NumJunctions] = N.name; jx[NumJunctions] = J.x; jy[NumJunctions] = J.y; jd[NumJunctions] = J.diameter; NumJunctions++; } } } // Check all wires against the junctions: // This assumes that all wires are orthogonal, which appears to // be a reasonable assumption for a schematic. Otherwise it would // be more complicated to calculate the distance between a junction // and a wire. SH.nets(N) { N.segments(S) { S.wires(W) { int dx = W.x2 - W.x1; int dy = W.y2 - W.y1; for (int i = 0; i < NumJunctions; i++) { if (NetName[i] != N.name) { int d = jd[i] / 2; int error = 0; if (dx == 0) { // vertical wire if (abs(W.x1 - jx[i]) < d && jy[i] < max(W.y1, W.y2) + d && jy[i] > min(W.y1, W.y2) - d) error = 1; } else if (dy == 0) { // horizontal wire if (abs(W.y1 - jy[i]) < d && jx[i] < max(W.x1, W.x2) + d && jx[i] > min(W.x1, W.x2) - d) error = 1; } // else WARNING? if (error) printf("ERROR: Junction at (%f,%f) appears to connect nets '%s' and '%s'\n", u2inch(jx[i]), u2inch(jy[i]), N.name, NetName[i]); } } } } } } // Check for multiple (>2) wires of the same net segment that end at the // same point, but are not visibly connected through a junction: SCH.sheets(SH) { SH.nets(N) { N.segments(S) { int jx[], jy[], NumJunctions = 0; S.junctions(J) { jx[NumJunctions] = J.x; jy[NumJunctions] = J.y; NumJunctions++; } int wx[], wy[], wn[], NumPoints = 0; S.wires(W) { int NewPoint1 = 1, NewPoint2 = 1; for (int i = 0; i < NumPoints; i++) { if (W.x1 == wx[i] && W.y1 == wy[i]) { NewPoint1 = 0; wn[i]++; } if (W.x2 == wx[i] && W.y2 == wy[i]) { NewPoint2 = 0; wn[i]++; } } if (NewPoint1) { wx[NumPoints] = W.x1; wy[NumPoints] = W.y1; wn[NumPoints] = 1; NumPoints++; } if (NewPoint2) { wx[NumPoints] = W.x2; wy[NumPoints] = W.y2; wn[NumPoints] = 1; NumPoints++; } } for (int i = 0; i < NumPoints; i++) { if (wn[i] > 2) { int FoundJunction = 0; for (int j = 0; j < NumJunctions; j++) { if (jx[j] == wx[i] && jy[j] == wy[i]) { FoundJunction = 1; break; } } if (!FoundJunction) printf("ERROR: Sheet %d, Net '%s': missing junction at (%f,%f)\n", SH.number, N.name, u2inch(wx[i]), u2inch(wy[i])); } } } } } // Check for pins that only appear to be connected: SCH.sheets(SH) { // Count the number of pins at each point where pins are located: int px[], py[], pn[], NumPoints = 0; SH.parts(PA) { PA.instances(IN) { IN.gate.symbol.pins(P) { int NewPoint = 1; for (int i = 0; i < NumPoints; i++) { if (P.x == px[i] && P.y == py[i]) { pn[i]++; NewPoint = 0; break; } } if (NewPoint) { px[NumPoints] = P.x; py[NumPoints] = P.y; pn[NumPoints] = 1; NumPoints++; } } } } // Screen out single pin locations: for (int si = 0; si < NumPoints; si++) { if (pn[si] == 1 && !NetWireAt(SH, px[si], py[si])) pn[si] = 0; } // Check if there are exactly that many pinrefs: SH.nets(N) { N.segments(S) { S.pinrefs(PR) { UL_PIN pin = PR.pin; for (int i = 0; i < NumPoints; i++) { if (pin.x == px[i] && pin.y == py[i]) { pn[i]--; break; } } } } } for (int i = 0; i < NumPoints; i++) { if (pn[i] > 0) { printf("ERROR: Sheet %d: unconnected pins at (%f,%f)\n", SH.number, u2inch(px[i]), u2inch(py[i])); } } } } }