/* * geda.c - Dump objects in the gEDA PCB board/module format * * Written 2009, 2011 by Werner Almesberger, and 2016 by Erich Heinzle * Copyright 2009, 2011 by Werner Almesberger * Copyright 2016, Erich Heinzle * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include "coord.h" #include "inst.h" #include "geda.h" static void geda_centric(struct coord a, struct coord b, struct coord *center, struct coord *size) { struct coord min, max; min.x = units_to_geda(a.x); min.y = units_to_geda(a.y); max.x = units_to_geda(b.x); max.y = units_to_geda(b.y); sort_coord(&min, &max); size->x = max.x-min.x; size->y = max.y-min.y; center->x = (min.x+max.x)/2; center->y = -(min.y+max.y)/2; } static unit_type geda_pad_width(struct coord size) { if (size.x >= size.y) { return size.y; } else { return size.x; } } static void geda_pad_start_finish(struct coord a, struct coord b, struct coord *start, struct coord *finish) { struct coord size, center, min, max; min.x = units_to_geda(a.x); min.y = units_to_geda(a.y); max.x = units_to_geda(b.x); max.y = units_to_geda(b.y); sort_coord(&min, &max); size.x = max.x-min.x; size.y = max.y-min.y; center.x = (min.x+max.x)/2; center.y = -(min.y+max.y)/2; /* gEDA pads are drawn as a line, of a certain thickness */ if (size.x >= size.y) { /* wider than tall, width = size.y */ start->x = min.x + size.y/2; start->y = -center.y; finish->x = max.x - size.y/2; finish->y = -center.y; } else { /* taller than wide, width = size.x */ start->y = (min.y + size.x/2); start->x = center.x; finish->y = (max.y - size.x/2); finish->x = center.x; } } static void do_geda_drill(FILE *file, const struct inst *pad, struct coord *padSize) { const struct inst *hole = pad->u.pad.hole; struct coord center, size; if (!hole) return; geda_centric(hole->base, hole->u.hole.other, ¢er, &size); fprintf(file, "%d %d ", center.x, -center.y); /* x,y position of hole */ if (padSize->x <= padSize->y) { /* sort out diameter of copper annulus, remembering obrounds*/ fprintf(file, "%d ", padSize->x); } else { fprintf(file, "%d ", padSize->y); } fprintf(file, "100 100 %d", size.x); /* default copper clearance, mask, then drill size */ } static void geda_pad(FILE *file, const struct inst *inst) { struct coord center, size, start, finish; geda_centric(inst->base, inst->u.pad.other, ¢er, &size); if (inst->u.pad.hole) { /* pin */ /* Pin[X Y Thickness Clearance Mask Drill Name Number SFlags] */ fprintf(file, "\tPin["); do_geda_drill(file, inst, &size); /* need pad size to figure out annulus */ fprintf(file, " \"%s\" \"%s\"", inst->u.pad.name, inst->u.pad.name); if (inst->obj->u.pad.rounded) { /* round pin */ fprintf(file, " \"\"]\n"); } else { /* square pad, ignore octagonal for now */ fprintf(file, " \"square\"]\n"); } } else { /* SMD */ /* Pad[X1 Y1 X2 Y2 Thickness Clearance Mask Name Number SFlags] */ geda_pad_start_finish(inst->base, inst->u.pad.other, &start, &finish); fprintf(file, "\tPad[%d %d %d %d %d 100 100 \"%s\" \"%s\" \"square\"]\n", start.x, -start.y, finish.x, -finish.y, geda_pad_width(size), inst->u.pad.name, inst->u.pad.name); } } static void geda_hole(FILE *file, const struct inst *inst) { struct coord center, size; if (inst->u.hole.pad) return; geda_centric(inst->base, inst->u.hole.other, ¢er, &size); /* Pin[X Y Thickness Clearance Mask Drill Name Number SFlags] */ fprintf(file, "\tPin[%d %d", center.x, center.y); if (size.x <= size.y) { /* see which obround dimension is smallest */ fprintf(file, " %d 100 100 %d", size.x, size.x); /* obround hole turned into round hole of diameter size.x */ } else { fprintf(file, " %d 100 100 %d", size.y, size.y); /* obround hole turned into round hole of diameter size.y */ } fprintf(file, " \"\" \"\" \"hole\"]\n"); } static void geda_line(FILE *file, const struct inst *inst) { /* * Xstart, Ystart, Xend, Yend, Width */ fprintf(file, "\tElementLine[%d %d %d %d %d]\n", units_to_geda(inst->base.x), -units_to_geda(inst->base.y), units_to_geda(inst->u.rect.end.x), -units_to_geda(inst->u.rect.end.y), units_to_geda(inst->u.rect.width)); } static void geda_rect(FILE *file, const struct inst *inst) { unit_type xa, ya, xb, yb; unit_type width; xa = units_to_geda(inst->base.x); ya = units_to_geda(inst->base.y); xb = units_to_geda(inst->u.rect.end.x); yb = units_to_geda(inst->u.rect.end.y); width = units_to_geda(inst->u.rect.width); fprintf(file, "\tElementLine[%d %d %d %d %d]\n", xa, -ya, xa, -yb, width); fprintf(file, "\tElementLine[%d %d %d %d %d]\n", xa, -yb, xb, -yb, width); fprintf(file, "\tElementLine[%d %d %d %d %d]\n", xb, -yb, xb, -ya, width); fprintf(file, "\tElementLine[%d %d %d %d %d]\n", xb, -ya, xa, -ya, width); } static void geda_circ(FILE *file, const struct inst *inst) { /* * Xcenter, Ycenter, Width, Height, startAngle, stopAngle, Width */ fprintf(file, "\tElementArc[ %d %d %d %d 0 360 %d]\n", units_to_geda(inst->base.x), -units_to_geda(inst->base.y), units_to_geda(inst->u.arc.r), units_to_geda(inst->u.arc.r), units_to_geda(inst->u.arc.width)); } static void geda_arc(FILE *file, const struct inst *inst) { double b; /* * Xcenter, Ycenter, Width, Height, startAngle, stopAngle, Width */ b = inst->u.arc.a1 - 180; while (b <= 0) b += 360; while (b > 360) b -= 360; fprintf(file, "\tElementArc[%d %d %d %d %d %d %d]\n", units_to_geda(inst->base.x), -units_to_geda(inst->base.y), units_to_geda(inst->u.arc.r), units_to_geda(inst->u.arc.r), (int) b, (int) (inst->u.arc.a2-inst->u.arc.a1), units_to_geda(inst->u.arc.width)); } static void geda_layout_header(FILE *file) { fprintf(file, "# release: pcb 20110918\n\n"); fprintf(file, "# To read pcb files, the pcb version (or the git source date) must be >= the file version\n"); fprintf(file, "FileVersion[20070407]\n\n"); fprintf(file, "PCB[\"\" 600000 500000]\n\n"); fprintf(file, "Grid[2500.0 0 0 1]\n"); fprintf(file, "Cursor[2500 62500 0.000000]\n"); fprintf(file, "PolyArea[3100.006200]\n"); fprintf(file, "Thermal[0.500000]\n"); fprintf(file, "DRC[1200 900 1000 700 1500 1000]\n"); fprintf(file, "Flags(\"nameonpcb,clearnew,snappin\")\n"); fprintf(file, "Groups(\"1,3,4,c:2,5,6,s:7:8\")\n"); fprintf(file, "Styles[\"Signal,1000,7874,3150,2000:Power,2000,8661,3937,2000:Fat,8000,13780,4724,2500:Sig-tight,1000,6400,3150,1200\"]\n\n"); fprintf(file, "Attribute(\"PCB::grid::unit\" \"mil\")"); } static void geda_layout_footer(FILE *file) { fprintf(file, "Layer(1 \"component\")\n(\n)\n"); fprintf(file, "Layer(2 \"solder\")\n(\n)\n"); fprintf(file, "Layer(3 \"comp-GND\")\n(\n)\n"); fprintf(file, "Layer(4 \"comp-power\")\n(\n)\n"); fprintf(file, "Layer(5 \"sold-GND\")\n(\n)\n"); fprintf(file, "Layer(6 \"sold-power\")\n(\n)\n"); fprintf(file, "Layer(7 \"signal3\")\n(\n)\n"); fprintf(file, "Layer(8 \"outline\")\n(\n)\n"); fprintf(file, "Layer(9 \"silk\")\n(\n)\n"); fprintf(file, "Layer(10 \"silk\")\n(\n)\n"); } static void geda_inst(FILE *file, enum inst_prio prio, const struct inst *inst) { switch (prio) { case ip_pad_copper: case ip_pad_special: geda_pad(file, inst); break; case ip_hole: geda_hole(file, inst); /* obround is exported as a round circle */ break; case ip_line: geda_line(file, inst); break; case ip_rect: geda_rect(file, inst); break; case ip_circ: geda_circ(file, inst); break; case ip_arc: geda_arc(file, inst); break; default: /* * Don't try to export vectors, frame references, or * measurements. */ break; } } static void geda_module(FILE *file, const struct pkg *pkg, time_t now) { enum inst_prio prio; const struct inst *inst; fprintf(file, "# Footprint generated by FPED utility\n"); fprintf(file, "Element[\"\" \"%s\" \"\" \"\" 0 0 -25590 -14874 0 100 \"\"]\n", pkg->name); fprintf(file, "(\n"); FOR_INST_PRIOS_UP(prio) { for (inst = pkgs->insts[prio]; inst; inst = inst->next) geda_inst(file, prio, inst); for (inst = pkg->insts[prio]; inst; inst = inst->next) geda_inst(file, prio, inst); } fprintf(file, ")\n\n"); /* extra newline between elements */ } int geda(FILE *file, const char *one) { const struct pkg *pkg; time_t now = time(NULL); assert(!one); geda_layout_header(file); /* we place one or more elements in a layout file */ for (pkg = pkgs; pkg; pkg = pkg->next) if (pkg->name) fprintf(file, "# %s\n", pkg->name); for (pkg = pkgs; pkg; pkg = pkg->next) if (pkg->name) geda_module(file, pkg, now); geda_layout_footer(file); fflush(file); return !ferror(file); }