#usage "KiCAD module exporting tool version 0.1a \n"
"
"
"This ULP can exports Eagle CAD Package contents into KiCAD module format."
"
"
"Load any library from the library directory and execute the ULP."
"
"
"Author: sdn@openhardware.ru"
int rect_conv = 1; // many QFP-like packages use rectangles as a pin contour (too much segments in the ki-format)
int poly_conv = 1;
int holes_conv = 1;
int RECT_WIDTH = 80;
// it is very difficult for me to compare this two formats, so pLayers &2lease correct
// this LUT if you find mistakes, and send your corrections to sdn@openhardware.ru.
/*
LAYER_CMP_N 15
CMP_N 15
NB_COPPER_LAYERS (CMP_N+1)
FIRST_NO_COPPER_LAYER 16
ADHESIVE_N_CU 16
ADHESIVE_N_CMP 17
SOLDERPASTE_N_CU 18
SOLDERPASTE_N_CMP 19
SILKSCREEN_N_CU 20
SILKSCREEN_N_CMP 21
SOLDERMASK_N_CU 22
SOLDERMASK_N_CMP 23
DRAW_N 24
COMMENT_N 25
ECO1_N 26
ECO2_N 27
EDGE_N 28
*/
int layer_lut[] =
{
15, //LAYER_TOP
16, //LAYER_BOTTOM
15, //LAYER_PADS
15, //LAYER_VIAS
21, //LAYER_UNROUTED
21, //LAYER_DIMENSION
21, //LAYER_TPLACE
21, //LAYER_BPLACE
21, //LAYER_TORIGINS
21, //LAYER_BORIGINS
21, //LAYER_TNAMES
21, //LAYER_BNAMES
21, //LAYER_TVALUES
21, //LAYER_BVALUES
21, //LAYER_TSTOP
21, //LAYER_BSTOP
21, //LAYER_TCREAM
21, //LAYER_BCREAM
21, //LAYER_TFINISH
21, //LAYER_BFINISH
21, //LAYER_TGLUE
21, //LAYER_BGLUE
21, //LAYER_TTEST
21, //LAYER_BTEST
21, //LAYER_TKEEPOUT
21, //LAYER_BKEEPOUT
21, //LAYER_TRESTRICT
21, //LAYER_BRESTRICT
21, //LAYER_VRESTRICT
21, //LAYER_DRILLS
21, //LAYER_HOLES
21, //LAYER_MILLING
21, //LAYER_MEASURES
21, //LAYER_DOCUMENT
21, //LAYER_REFERENCE
21, //LAYER_TDOCU
20, //LAYER_BDOCU
21, //LAYER_NETS
21, //LAYER_BUSSES
21, //LAYER_PINS
21, //LAYER_SYMBOLS
21, //LAYER_NAMES
21 //LAYER_VALUES
};
//------------------------------------------------------
// utils
//------------------------------------------------------
int layer_lookup(int layer)
{
if(layer > 42) return 21;
return layer_lut[layer+1];
}
//Units conversion routine | 1.0 inch = 10000 Ki-units |
int egl2ki(int units)
{
real inch = u2inch(units);
return int(inch*10000);
}
// check for smd pads in package
int issmd(UL_PACKAGE PAC)
{
int res = 0;
PAC.contacts(C)
{
res |= C.smd?1:0;
}
return res;
}
//------------------------------------------------------
//write index of modules
//------------------------------------------------------
void write_kikad_mod_idx(UL_LIBRARY LIB)
{
// write INDEX start tag
printf("$INDEX\n");
// write index of modules
LIB.packages(PAC) printf("%s\n", strupr(PAC.name));
// write INDEX end tag
printf("$EndINDEX\n");
}
//------------------------------------------------------
// pad conversion
//------------------------------------------------------
void write_kikad_mod_pad(UL_PACKAGE PAC)
{
char shp = 'R';
string signal, type = "STD";
int dx, dy, drill, layset;
PAC.contacts(CN)
{
// write PAD start tag
printf("$PAD\n");
signal = CN.signal;
if(CN.smd)
{
type = "SMD";
if(CN.smd.roundness > 40)
if(CN.smd.dx == CN.smd.dy) shp = 'C';
else shp = 'O';
dx = CN.smd.dx;
dy = CN.smd.dy;
}
if(CN.pad)
{
type = "STD";
if(CN.pad.shape[LAYER_TOP] == PAD_SHAPE_ROUND ) shp = 'C';
if(CN.pad.shape[LAYER_TOP] == PAD_SHAPE_OCTAGON) shp = 'C';
if(CN.pad.shape[LAYER_TOP] == PAD_SHAPE_LONG ) shp = 'O';
dx = CN.pad.diameter[LAYER_TOP];
dy = CN.pad.diameter[LAYER_TOP];
drill = CN.pad.drill;
}
// pad shape
printf("Sh \"%s\" %c %d %d %d %d %d\n",
CN.name, shp, egl2ki(dx), egl2ki(dy), 0, 0, 0);
printf("Dr %d %d %d \n", egl2ki(drill), 0, 0);
printf("At %s N %08X\n", type, layset);
printf("Ne 0 \"%s\"\n", signal);
printf("Po %d %d \n", egl2ki(CN.x), -egl2ki(CN.y));
// write PAD end tag
printf("$EndPAD\n");
}
}
//------------------------------------------------------
// shape conversion
//------------------------------------------------------
void write_kicad_mod_shapes(UL_PACKAGE PAC)
{
//write shapes
//also we must convert inverted y-coordinates (take it with minus)
//
//segments (always from eagle's rectangles,wires and optional polygons)
// rectangles converting -------------------------------------------------------------
int layer;
if(rect_conv)
PAC.rectangles(R)
{
layer = layer_lookup(R.layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(R.x1), -egl2ki(R.y1), egl2ki(R.x2), -egl2ki(R.y1), RECT_WIDTH, layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(R.x2), -egl2ki(R.y1), egl2ki(R.x2), -egl2ki(R.y2), RECT_WIDTH, layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(R.x1), -egl2ki(R.y2), egl2ki(R.x2), -egl2ki(R.y2), RECT_WIDTH, layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(R.x1), -egl2ki(R.y1), egl2ki(R.x1), -egl2ki(R.y2), RECT_WIDTH, layer);
}
// wires converting ---------------------------------------------------------------------
PAC.wires(W)
{
layer = layer_lookup(W.layer);
if(!W.arc)
printf("DS %d %d %d %d %d %d\n",
egl2ki(W.x1), -egl2ki(W.y1), egl2ki(W.x2), -egl2ki(W.y2), egl2ki(W.width), layer);
}
// polygons converting ------------------------------------------------------------------
if(poly_conv)
PAC.polygons(P)
{
P.contours(CONT)
{
layer = layer_lookup(CONT.layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(CONT.x1), -egl2ki(CONT.y1), egl2ki(CONT.x2), -egl2ki(CONT.y2), egl2ki(CONT.width), layer);
}
P.wires(W) {
printf("DS %d %d %d %d %d %d\n",
egl2ki(W.x1), egl2ki(W.y1), egl2ki(W.x2), egl2ki(W.y2), egl2ki(W.width), layer);}
}
//circles (always from eagle's circles and optional from holes)
// circles converting --------------------------------------------------------------------
PAC.circles(C)
{
layer = layer_lookup(C.layer);
printf("DC %d %d %d %d %d %d\n", egl2ki(C.x) , -egl2ki(C.y) ,
egl2ki(C.x) + ((egl2ki(C.x)>0)?1:(-1)) * egl2ki(C.radius/2),
-egl2ki(C.y) - ((egl2ki(C.y)>0)?1:(-1)) * egl2ki(C.radius/2), egl2ki(C.width), layer);
}
if(holes_conv)
PAC.holes(H)
{
layer = 21;
printf("DC %d %d %d %d %d %d\n",
egl2ki(H.x), -egl2ki(H.y),
egl2ki(H.x) + ((egl2ki(H.x)>0)?1:(-1)) * egl2ki(H.drill/4),
-egl2ki(H.y) - ((egl2ki(H.y)>0)?1:(-1)) * egl2ki(H.drill/4),
50, layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(H.x - (H.drill/2)), -egl2ki(H.y),
egl2ki(H.x + (H.drill/2)), -egl2ki(H.y), 50, layer);
printf("DS %d %d %d %d %d %d\n",
egl2ki(H.x), -egl2ki(H.y - (H.drill/2)),
egl2ki(H.x), -egl2ki(H.y + (H.drill/2)), 50, layer);
}
//arcs converting (always from wires) ----------------------------------------------------
PAC.wires(W)
{
if(W.arc)
{
layer = layer_lookup(W.layer);
printf("DA %d %d %d %d %d %d %d \n",
egl2ki(W.arc.xc ), -egl2ki(W.arc.yc),
egl2ki(W.arc.x2), -egl2ki(W.arc.y2),
int((360 + abs(W.curve))*10) ,
egl2ki(W.arc.width), layer);
}
}
}
//------------------------------------------------------
// Text conversion
//------------------------------------------------------
void write_kicad_mod_text(UL_PACKAGE PAC)
{
int textnum = 0;
PAC.texts(T)
{
printf("T%d %d %d %d %d %d %d %d \"%s\"\n",
textnum, egl2ki(T.x), -egl2ki(T.y),
egl2ki(T.size), egl2ki(T.size),
int((360 + abs(T.angle))*10), 50, 21, T.value);
textnum++;
}
}
//------------------------------------------------------
// Mod body conversion
//------------------------------------------------------
void write_kikad_mod_body(UL_LIBRARY LIB)
{
//for all packages in library
LIB.packages(PAC)
{
// write MODULE start tag
printf("$MODULE %s\n", strupr(PAC.name));
//write module position
printf("Po %d %d %d %d 00200000 00000000 ~~\n",
0, // what's it?
0, // and here?
0, // orient
15 // layer
);
//write name & description
printf("Li %s\n", strupr(PAC.name));
printf("Cd %s\n", strupr(PAC.headline));
printf("Kw %s\n", strupr(PAC.headline));
//write timestamp
printf("Sc 00000000\n");
//write orientation
printf("Op 0 0 0\n");
//write attributes
printf("At %s\n", issmd(PAC) ? "SMD" : "VIRTUAL");
write_kicad_mod_shapes(PAC);
write_kicad_mod_text(PAC);
// write module pads
write_kikad_mod_pad(PAC);
// write MODULE end tag
printf("$EndMODULE %s\n", strupr(PAC.name));
}
}
//------------------------------------------------------
//ki-format high-level write functions
//------------------------------------------------------
void write_kicad_mod(string name)
{
output(name, "wt")
{
if (library)
library(L)
{
int t = time();
printf("PCBNEW-LibModule-V1 %02d/%02d/%04d-%02d:%02d:%02d\n",
t2day(t), t2month(t)+1, t2year(t), t2hour(t), t2minute(t), t2second(t));
write_kikad_mod_idx(L);
write_kikad_mod_body(L);
}
}
}
//------------------------------------------------------
// main program
//------------------------------------------------------
string mod_name ;
int result;
string ref;
if (library) library(L) mod_name = strsub(L.name, 0, strlen(L.name) - 3) + "mod";
else
{
dlgMessageBox("Please run from library editor." );
exit(EXIT_FAILURE);
}
result = dlgDialog("Export KiCAD mod") {
dlgTabWidget {
//=====================TAB1=============================================================
dlgTabPage("Output")
{
dlgHBoxLayout dlgSpacing(400);
dlgStretch(0);
dlgLabel("Export to file:");
dlgStretch(0);
dlgStringEdit(mod_name);
dlgVBoxLayout {
dlgStretch(0);
dlgHBoxLayout {
dlgStretch(1);
dlgPushButton("+OK") dlgAccept();
dlgStretch(0);
}
dlgHBoxLayout {
dlgStretch(1);
dlgPushButton("-Cancel") dlgReject();
dlgStretch(0);
}
dlgStretch(10);
};
dlgStretch(1);
}
//======================TAB2============================================================
// dlgTabPage("Layers")
// {
// dlgTextView("Click here: options", ref) dlgDialog(ref){dlgLabel(ref);};
// }
}
};
//dlgMessageBox(" \n" );
if(result)
write_kicad_mod(mod_name);
else
dlgMessageBox("Canceled!" );
exit(EXIT_SUCCESS);