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

" "Author: horsky@semi.mff.cuni.cz
" "Version 0.92 (Jul 2003)

" "See also http://www.formica.cz" string title = "FORMICA 4.30 / 4.2 PCB layout and library export"; string version = "Version 0.92 (Jul 2003)"; string copyright = "Copyright (c) 2001-2003 Petr Horský"; /* 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) */ // ------------------------------------------------- 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; } } // ----------------------------------------------- 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, 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 (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 fmWire(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 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)); } 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 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) | 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.layer == LAYER_TOP)); } printf (" )\n"); printf (" Lines (\n"); P.wires(W) fmWire(W, " "); P.rectangles(R) fmRectangle(R, " "); P.arcs(A) fmApproxArc(A, " "); printf (" )\n"); printf (" Arcs (\n"); P.circles(C) fmCircle(C, " "); P.arcs(A) fmArc(A, " "); 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, "", " "); printf (" )\n"); } // fmPackage void fmComponent(UL_ELEMENT E) { int noName = 1, noValue = 1; printf (" (%d 0\n", fmAngle(E.angle) | 4 * E.mirror); E.texts(T) if (E.name == T.value) { fmText(T, "", " "); noName = 0; // component name found break; } if (noName) fmDefault(E, E.name, " "); E.texts(T) if (E.value == T.value) { fmText(T, "", " "); noValue = 0; // component value found break; } if (noValue) fmDefault(E, E.value, " "); fmDefault (E, E.package.name, " "); 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); printf ("Layout (\n"); printf (" Text (\n"); B.texts(T) fmText(T, "", " "); printf (" )\n"); printf (" Lines (\n"); B.wires(W) fmWire(W, " "); B.rectangles(R) fmRectangle(R, " "); B.arcs(A) fmApproxArc(A, " "); B.signals(S) S.wires(W) fmWire(W, " "); printf (" )\n"); printf (" Arcs (\n"); B.circles(C) fmCircle(C, " "); B.arcs(A) fmArc(A, " "); 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); 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.");