#usage "FORMICA 4.30 / 4.2 PCB layout and library export

" "Author: horsky@semi.mff.cuni.cz
" "Version 0.94 (Feb 2004)

" "See also http://www.formica.cz" string title = "FORMICA 4.30 / 4.2 PCB layout and library export"; string version = "Version 0.94 (Feb 2004)"; string copyright = "Copyright (c) 2001-2004 Petr Horský"; /* ============================================================================= --- ZMĚNY OPROTI VERZI 0.92: --------------------------------------------------- 1) upraveno pro Eagle 4.11 (arc pouze jako součást wire) 2) ošetřen obdélník rotovaný o obecný úhel 3) do výstupního souboru doplněna sekce Setup (uvádějící mj. soubor verze 4.30) 4) opravena rotace pájecích bodů SMD (ver. 0.94) 5) texty vystupují vždy v čitelné orientaci (ver. 0.94) 6) ošetřeny polygony (ver. 0.94) -------------------------------------------------------------------------------- --- ZBÝVAJÍCÍ PROBLÉMY --------------------------------------------------------- 1) generování tabulky Dimensions (spíše než mapování na defaultní tabulku) 2) nečíslované piny (vedou také k neúplnému netlistu - nutno užívat Add Tracks) 3) pájecí body otočené o obecný úhel 4) vyplněné obdélníky ============================================================================= */ // ------------------------------------------------- konverze souřadnic a vrstev int ofsx = 1000, ofsy = 2000; int fmUnit(int u) { return max(u2mil(u), 0); } int mapx(int u) { return u2mil(u) + ofsx; } int mapy(int u) { return u2mil(u) + ofsy; } int mapt(int u) { return (u > 1) ? max(u2mil(u / 6), 1) : 0; } int fmAngle(real a) { int i = round(a / 90.0); return i & 3; } int fmLayer(int l) { switch (l) { case LAYER_TOP: return 10; case LAYER_BOTTOM: return 5; case LAYER_TSTOP: return 11; case LAYER_BSTOP: return 4; case LAYER_TGLUE: case LAYER_TNAMES: return 13; case LAYER_TVALUES: return 14; case LAYER_BGLUE: case LAYER_BNAMES: return 2; case LAYER_BVALUES: return 1; case LAYER_TDOCU: case LAYER_TPLACE: // component contours are in this layer case LAYER_TTEST: case LAYER_TFINISH: return 15; case LAYER_BDOCU: case LAYER_BPLACE: // component contours are in this layer case LAYER_BTEST: case LAYER_BFINISH: return 0; default: return 0; } } // ------------------------------------------------------------ hlavička souboru void fmSetup(int x1, int y1, int x2, int y2) { printf ("Setup (\n" " (4 30)\n" " (20 1000 1000 0 0 %d %d %d %d %d %d %d %d %d 25 4 2 4 1 108 0 50)\n" " ((50 1 1 1 100 1 1 0 1 1)\n" " (10 30 32 30 10 32 40 0 0 2 20)\n" " (10 10 15 10 10 15 50 0 0 0 20)\n" " )\n" ")\n", x1, y1, x2, y2, fmLayer(LAYER_BOTTOM), fmLayer(LAYER_TOP), fmLayer(LAYER_BOTTOM), fmLayer(LAYER_TOP), fmLayer(LAYER_BOTTOM)); } // ----------------------------------------------- mapování logických typů prvků int fmLineWidths[] = {4, 6, 8, 10, 12, 16, 20, 24, 32, 40, 52, 60, 80, 100, 120, 200}; int fmLineType(int w) { int i, j, d, m = INT_MAX; for (i=0; i<16; i++) { d = abs(fmLineWidths[i] - fmUnit(w)); if (d < m) {j = i; m = d;} } return j; } int fmPadDiams[] = {32, 40, 48, 52, 60, 60, 72, 80, 96, 120, 152, 152, 200}; // type 0..12 int fmPadHoles[] = {16, 24, 28, 36, 36, 40, 44, 52, 60, 72, 88, 128, 128}; int fmRoundPadType(int diam, int hole) { int i, t, d, m = INT_MAX; for (i=0; i<13; i++) { d = 100 * abs(fmPadDiams[i] - fmUnit(diam)) + abs(fmPadHoles[i] - fmUnit(hole)); if (d < m) {t = i; m = d;} } return t; } int fmSmdT[] = {14, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 82, 84, 86, 88}; int fmSmdW[] = {40, 40, 40, 64, 64, 72, 72, 80, 80, 88, 88, 96, 96, 120, 60, 88, 36, 64, 36, 64}; int fmSmdH[] = {40, 56, 212, 56, 104, 200, 264, 96, 128, 12, 16, 104, 152, 112, 400, 24, 16, 16, 20, 20}; int fmSmdPadType(int w, int h, real a, int top) { int i, t, d, m = INT_MAX; for (i=0; i<20; i++) { d = abs(fmSmdW[i] - fmUnit(w)) + abs(fmSmdH[i] - fmUnit(h)); if (d < m) {t = fmSmdT[i]; m = d;} d = abs(fmSmdW[i] - fmUnit(h)) + abs(fmSmdH[i] - fmUnit(w)); if (d < m) {t = fmSmdT[i] | 0x80; m = d;} } if (fmAngle(a) & 1) t ^= 0x80; if (top) t--; return ((t < 0x40) || (t >= 0xC0)) ? t : t ^ 0xC0; } int fmHoleT[] = {47, 48, 100, 49, 50, 51}; int fmHoleD[] = {24, 36, 70, 88, 112, 128}; int fmHoleType(int diam) { int i, t, d, m = INT_MAX; for (i=0; i<6; i++) { d = abs(fmHoleD[i] - fmUnit(diam)); if (d < m) {t = fmHoleT[i]; m = d;} } return t; } // ---------------------------------------------------------------- výstup prvků void fmLineSeg(UL_WIRE W, string indent) { printf( "%s(%d %d %d %d %d %d)\n", indent, mapx(W.x1), mapy(W.y1), mapx(W.x2), mapy(W.y2), fmLineType(W.width), fmLayer(W.layer)); } void fmRectangle(UL_RECTANGLE R, string indent) { //// neumi jej vyplnit if (!R.angle) printf( "%s(%d %d %d %d %d %d)\n" "%s(%d %d)\n" "%s(%d %d)\n" "%s(%d %d)\n", indent, mapx(R.x1), mapy(R.y1), mapx(R.x2), mapy(R.y1), fmLineType(0), fmLayer(R.layer), indent, mapx(R.x2), mapy(R.y2), indent, mapx(R.x1), mapy(R.y2), indent, mapx(R.x1), mapy(R.y1)); else { real a = R.angle / 180.0 * PI, sina = sin(a), cosa = cos(a); int xc = (R.x1 + R.x2) / 2, yc = (R.y1 + R.y2) / 2, w = (R.x2 - R.x1) / 2, h = (R.y2 - R.y1) / 2; printf( "%s(%d %d %d %d %d %d)\n" "%s(%d %d)\n" "%s(%d %d)\n" "%s(%d %d)\n", indent, mapx(xc - w * cosa + h * sina), mapy(yc - w * sina - h * cosa), // -w, -h mapx(xc + w * cosa + h * sina), mapy(yc + w * sina - h * cosa), // +w, -h fmLineType(0), fmLayer(R.layer), indent, mapx(xc + w * cosa - h * sina), mapy(yc + w * sina + h * cosa), // +w, +h indent, mapx(xc - w * cosa - h * sina), mapy(yc - w * sina + h * cosa), // -w, +h indent, mapx(xc - w * cosa + h * sina), mapy(yc - w * sina - h * cosa)); // -w, -h } } // fmRectangle void fmArc(UL_ARC A, string indent) { for (int i=0; i<8; i++) if ((A.angle1 <= i * 90) && (A.angle2 >= (i+1) * 90)) printf( "%s(%d %d %d %d %d %d)\n", indent, i & 3, mapx(A.xc), mapy(A.yc), fmUnit(A.radius), fmLineType(A.width), fmLayer(A.layer)); } void fmApprox(UL_ARC A, real a1, real a2, string indent) { int n = max (ceil((a2 - a1) / 15.0), 1); real a = a1 / 180.0 * PI; real b = (a2 - a1) / n / 180.0 * PI; int x1, y1, x2, y2; for (int i=0; i<=n; i++) { x2 = A.xc + A.radius * cos (a); y2 = A.yc + A.radius * sin (a); if (i > 0) printf( "%s(%d %d %d %d %d %d)\n", indent, mapx(x1), mapy(y1), mapx(x2), mapy(y2), fmLineType(A.width), fmLayer(A.layer)); x1 = x2; y1 = y2; a += b; } } void fmApproxArc(UL_ARC A, string indent) { for (int i=0; i<4; i++) if ((A.angle1 > i * 90) && (A.angle1 < (i+1) * 90)) if (A.angle2 < (i+1) * 90) { fmApprox(A, A.angle1, A.angle2, indent); return; } else { fmApprox(A, A.angle1, (i+1) * 90, indent); break; } for (i=0; i<8; i++) if ((A.angle2 > i * 90) && (A.angle2 < (i+1) * 90)) { fmApprox(A, max(A.angle1, i * 90), A.angle2, indent); return; } } void fmWire(UL_WIRE W, string indent) { if (!W.arc) fmLineSeg(W, indent); else fmApproxArc(W.arc, indent); } void fmPolygon(UL_POLYGON P, string indent) { P.contours(W) fmWire(W, indent); P.fillings(W) fmWire(W, indent); } void fmCircle(UL_CIRCLE C, string indent) { printf( "%s(0 %d %d %d %d %d)(1)(2)(3)\n", indent, mapx(C.x), mapy(C.y), fmUnit(C.radius), fmLineType(C.width), fmLayer(C.layer)); } void fmText(UL_TEXT T, string s, string indent) { string str = (s == "") ? T.value : s; real a = T.angle / 180.0 * PI; int size = mapt(T.size); int ofsw = (6 * strlen(str) - 2) * size / 2; int ofsh = 6 * size / 2; int lw; T.wires(W) { lw = fmLineType(W.width); break; } if ((s != "") || (T.value != ">NAME") && (T.value != ">VALUE")) printf( "%s(\"%s\" %5.0f %5.0f %d %d %d %d)\n", indent, str, mapx(T.x) + ((T.mirror) ? -1 : 1) * (ofsw * cos(a) - ofsh * sin(a)), mapy(T.y) + (ofsw * sin(a) + ofsh * cos(a)), size, fmAngle(T.angle) & 1 | 4 * T.mirror, lw, fmLayer(T.layer)); } // ------------------------------------------------------------ výstup součástek void fmDefault(UL_ELEMENT E, string s, string indent) { printf( "%s(\"%s\" %d %d %d %d %d %d)\n", indent, s, mapx(E.x), mapy(E.y), // toto je origin, ne stred !!!! fmUnit(0), fmAngle(0), fmLineType(0), fmLayer(LAYER_TNAMES)); } void fmDefault2(UL_PACKAGE P, string s, string indent) { printf( "%s(\"%s\" %d %d %d %d %d %d)\n", indent, s, mapx((P.area.x1 + P.area.x2) / 2), mapy((P.area.y1 + P.area.y2) / 2), fmUnit(0), fmAngle(0), fmLineType(0), fmLayer(LAYER_TNAMES)); } void fmPackage(UL_PACKAGE P) { printf( " Pins (\n"); int pin = 300; // undefined pin numbers P.contacts(C) { int n = strtol(C.name); string name = ""; if (n == 0) { n = ++pin; name = "{" + C.name + "} "; } if (C.pad) printf( " (%d %s%d %d %d)\n", n, name, mapx(C.x), mapy(C.y), fmRoundPadType(C.pad.diameter[LAYER_BOTTOM], C.pad.drill)); else if (C.smd) printf( " (%d %s%d %d %d)\n", n, name, mapx(C.x), mapy(C.y), fmSmdPadType(C.smd.dx, C.smd.dy, C.smd.angle, C.smd.layer == LAYER_TOP)); } printf( " )\n"); string indent = " "; printf( " Lines (\n"); P.wires(W) fmWire(W, indent); P.polygons(Q) fmPolygon(Q, indent); P.rectangles(R) fmRectangle(R, indent); printf( " )\n"); printf( " Arcs (\n"); P.circles(C) fmCircle(C, indent); P.wires(W) if (W.arc) fmArc(W.arc, indent); printf( " )\n"); printf( " Pads (\n"); P.holes(H) printf( " (%d %d %d)\n", mapx(H.x), mapy(H.y), fmHoleType(H.drill)); printf( " )\n"); printf( " Text (\n"); P.texts(T) fmText(T, "", indent); printf( " )\n"); } // fmPackage void fmComponent(UL_ELEMENT E) { int noName = 1, noValue = 1; printf( " (%d 0\n", fmAngle(E.angle) | 4 * E.mirror); string indent = " "; E.texts(T) if (E.name == T.value) { fmText(T, "", indent); noName = 0; // component name found break; } if (noName) fmDefault(E, E.name, indent); E.texts(T) if (E.value == T.value) { fmText(T, "", indent); noValue = 0; // component value found break; } if (noValue) fmDefault(E, E.value, indent); fmDefault (E, E.package.name, indent); fmPackage(E.package); printf( " )\n"); } void fmNetlist(UL_SIGNAL S) { printf(" ( {Signal %s}\n", S.name); S.contactrefs(C) { if (strtol(C.contact.name)) printf(" \"%s\" %s\n", C.element.name, C.contact.name); else printf(" { %s %s (can't convert to pin number) }\n", C.element.name, C.contact.name); } printf(" )\n"); } // --------------------------------------------------------------- hlavní funkce string dlgTitle = "EAGLE to FORMICA 4.30 conversion - enter target file name:"; if (board) board(B) { string fileName = filesetext (B.name, ".PCB"); fileName = dlgFileSave(dlgTitle, fileName, "*.PCB"); if (fileName != "") output(fileName, "wt") { ofsx += 200 * ceil((400 - mapx(B.area.x1) + 199) / 200); ofsy += 200 * ceil((400 - mapy(B.area.y1) + 199) / 200); printf( "{%s}\n" "{%s}\n\n" "{Source file = \"%s\"}\n" "{Source format = \"%s\"}\n\n", title, version, B.name, EAGLE_SIGNATURE); fmSetup(mapx(B.area.x1), mapy(B.area.y1), mapx(B.area.x2), mapy(B.area.y2)); printf( "Dimensions (0)\n"); printf( "Layout (\n"); string indent = " "; printf( " Text (\n"); B.texts(T) fmText(T, "", indent); printf( " )\n"); printf( " Lines (\n"); B.wires(W) fmWire(W, indent); B.polygons(P) fmPolygon(P, indent); B.rectangles(R) fmRectangle(R, indent); B.signals(S) { S.wires(W) fmWire(W, indent); S.polygons(P) fmPolygon(P, indent); } printf( " )\n"); printf( " Arcs (\n"); B.circles(C) fmCircle(C, indent); B.wires(W) if (W.arc) fmArc(W.arc, indent); B.signals(S) S.wires(W) if (W.arc) fmArc(W.arc, indent); printf( " )\n"); printf( " Pads (\n"); B.signals(S) S.vias(V) printf( " (%d %d %d)\n", mapx(V.x), mapy(V.y), fmRoundPadType(V.diameter[LAYER_TOP], V.drill)); //// odlisit ctvercove!!! B.holes(H) printf( " (%d %d %d)\n", mapx(H.x), mapy(H.y), fmHoleType(H.drill)); printf( " )\n"); printf( ")\n"); printf( "Components (\n"); B.elements(E) fmComponent(E); printf( ")\n"); printf( "Netlist (\n"); B.signals(S) fmNetlist(S); printf( ")\n"); } // output } // board else if (library) library(L) { string fileName = filesetext (L.name, ".PCB"); fileName = dlgFileSave(dlgTitle, fileName, "*.PCB"); if (fileName != "") output(fileName, "wt") { printf( "{%s}\n" "{%s}\n\n" "{Source file = \"%s\"}\n" "{%s}\n" "{Source format = \"%s\"}\n\n", title, version, L.name, L.headline, EAGLE_SIGNATURE); fmSetup(0, 0, 32000, 32000); printf( "Dimensions (0)\n"); printf( "Components (\n"); int maxx = 400, maxy = 400, newy = 0; L.packages(P) { while (1) { ofsx += 200 * ceil((maxx - mapx(P.area.x1) + 199) / 200); ofsy += 200 * ceil((maxy - mapy(P.area.y1) + 199) / 200); if (mapx(P.area.x2) > 32000) { maxx = 200; maxy = newy; } else break; } printf( " (0 0 {%s}\n", P.headline); int noName = 1, noValue = 1; P.texts(T) if (T.value == ">NAME") { fmText(T, P.name, " "); noName = 0; // component name found break; } if (noName) fmDefault2(P, P.name, " "); P.texts(T) if (T.value == ">VALUE") { fmText(T, "VALUE", " "); noValue = 0; // component value found break; } if (noValue) printf( " (\"\")\n"); printf( " (\"%s\" %d %d %d %d %d %d)\n", "PACKAGE", mapx(0), mapy(0), // toto je origin, ne stred !!!! fmUnit(0), fmAngle(0), fmLineType(0), fmLayer(LAYER_TNAMES)); fmPackage(P); printf( " )\n"); maxx = mapx(P.area.x2) + 100; newy = max(mapy(P.area.y2) + 100, newy); } printf( ")\n"); } // output } // library else dlgMessageBox("To convert schematics, please use the Formica4-S.ulp.");