#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.");