diff --git a/drl2gp/Makefile b/drl2gp/Makefile new file mode 100644 index 0000000..e89cccd --- /dev/null +++ b/drl2gp/Makefile @@ -0,0 +1,77 @@ +# +# Makefile - Makefile of drl2gp +# +# Written 2010 by Werner Almesberger +# Copyright 2010 by Werner Almesberger +# +# 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. +# + +PREFIX ?= /usr/local + +SHELL=/bin/bash + +MAIN=drl2gp +OBJS=drl2gp.o + +CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \ + -Wmissing-declarations -Wno-format-zero-length +CFLAGS=$(CFLAGS_WARN) -g +LDFLAGS=-lm + +# ----- Verbosity control ----------------------------------------------------- + +CC_normal := $(CC) +DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG + +CC_quiet = @echo " CC " $@ && $(CC_normal) +DEPEND_quiet = @$(DEPEND_normal) + +ifeq ($(V),1) + CC = $(CC_normal) + DEPEND = $(DEPEND_normal) +else + CC = $(CC_quiet) + DEPEND = $(DEPEND_quiet) +endif + +# ----- Rules ----------------------------------------------------------------- + +.PHONY: all clean spotless + +all: $(MAIN) + +$(MAIN): $(OBJS) + +clean: + rm -f $(OBJS) $(OBJS:.o=.d) + +spotless: clean + rm -f $(MAIN) + +# ----- Install / uninstall --------------------------------------------------- + +install: all + mkdir -p $(DESTDIR)/$(PREFIX)/bin/ + install -m 755 $(MAIN) $(DESTDIR)/$(PREFIX)/bin/ + +uninstall: + rm -f $(DESTDIR)/$(PREFIX)/bin/$(MAIN) + +# ----- Dependencies ---------------------------------------------------------- + +# compile and generate dependencies, from fped, based on +# http://scottmcpeak.com/autodepend/autodepend.html + +%.o: %.c + $(CC) -c $(CFLAGS) $*.c -o $*.o + $(DEPEND) $*.c | \ + sed -e \ + '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \ + -e '$${g;p;}' -e d >$*.d; \ + [ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; } + +-include $(OBJS:.o=.d) diff --git a/drl2gp/drl2gp.c b/drl2gp/drl2gp.c new file mode 100644 index 0000000..4e910f2 --- /dev/null +++ b/drl2gp/drl2gp.c @@ -0,0 +1,360 @@ +/* + * drl2gp.c - KiCad drill file to gnuplot converter + * + * Written 2010 by Werner Almesberger + * Copyright 2010 Werner Almesberger + * + * 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. + */ + +/* + * KiCad drill files are in the Excellon format. The format is described + * here: + * + * http://web.archive.org/web/20071030075236/http://www.excellon.com/manuals/program.htm + * + * Note that drl2gp currently only implements the subset necessary to process + * the KiCad drill files encountered in a few projects, may not work correctly + * for drill files from other projects, and will almost certainly fail in + * tool-shattering ways when fed excellon files from other sources. + */ + + +#include +#include +#include +#include + + +#define MAX_ARGS 3 +#define MAX_TOOL 10 + + +static double tool_d[MAX_TOOL+1]; +static FILE *out = NULL; +static int lineno = 1; + +static int mill; +static double depth, d0, d1; + + +#define IN2MM(in) ((in)*25.4) +#define MIL2MM(mil) IN2MM((mil)/1000) + + +/* + * @@@ should at least detect INCH/METRIC + */ + +static void header(void) +{ + enum { + ts_nl, /* at beginning of line */ + ts_t, /* seen a ^T */ + ts_tc, /* seen ^T\d+C */ + ts_skip, /* skip to next \n */ + } state = ts_nl; + int c, tool; + double f = 1; + + while ((c = getchar()) != EOF) { + if (out) { + if (fputc(c, out) == EOF) { + perror("write"); + exit(1); + } + } + switch (state) { + case ts_nl: + switch (c) { + case 'T': + state = ts_t; + tool = 0; + break; + case '%': + return; + case '\n': + lineno++; + break; + default: + state = ts_skip; + break; + } + break; + case ts_t: + if (isdigit(c)) + tool = tool*10+c-'0'; + else if (c != 'C') + state = ts_skip; + else { + assert(c != '\n'); + if (tool > MAX_TOOL) { + fprintf(stderr, + "tool index %d too large (> %d)\n", + tool, MAX_TOOL); + exit(1); + } + tool_d[tool] = 0; + f = 1; + state = ts_tc; + } + break; + case ts_tc: + if (isdigit(c)) { + if (f == 1) + tool_d[tool] = tool_d[tool]*10+c-'0'; + else { + tool_d[tool] += f*(c-'0'); + f /= 10; + } + } else if (c == '.') { + f = 0.1; + } else if (c == '\n') { + lineno++; + state = ts_nl; + } else { + state = ts_skip; + } + break; + default: + if (c == '\n') { + lineno++; + state = ts_nl; + } else { + state = ts_skip; + } + } + } +} + + +static void slot(double xa, double ya, double xb, double yb, double d) +{ + assert(mill); +} + + +static void circle(double cx, double cy, double d) +{ + assert(mill); +} + + +static void drill(double x, double y) +{ +} + + +static void do_cmd(char cmd, double v, int nl) +{ + static int active = 0; + static int metric = 1; + static int slotting = 0; + double x = 0, y = 0, x0 = 0, d = 0; + int n = v; + + switch (cmd) { + case 'M': + switch (n) { + case 30: /* end of program */ + exit(0); + case 47: /* operator message */ + break; + case 71: /* metric measuring mode */ + metric = 1; + break; + case 72: /* inch measuring mode */ + metric = 0; + break; + default: + fprintf(stderr, + "unrecognized command M%d at line %d\n", + n, lineno); + exit(1); + } + break; + case 'G': + switch (n) { + case 5: /* drill mode */ + break; + case 85: /* slot */ + x0 = x; + slotting = 1; + break; + default: + fprintf(stderr, + "unrecognized command G%d at line %d\n", + n, lineno); + exit(1); + } + break; + case 'T': + if (!n) { + active = 0; + break; + } + if (n < 1 || n > MAX_TOOL || !tool_d[n]) { + fprintf(stderr, "invalid tool T%d at line %d\n", + n, lineno); + exit(1); + } + d = tool_d[n]; + if (mill) + active = d <= d0; + else + active = d >= d0 && d <= d1; + break; + case 'X': + x = metric ? v : IN2MM(v); + break; + case 'Y': + if (!active) { + slotting = 0; + break; + } + if (slotting) { + slot(x0, y, x, v, d); + slotting = 0; + break; + } + if (nl) { + assert(d); + if (d > d1) + circle(x, v, d); + else + drill(x, v); + break; + } + y = metric ? v : IN2MM(v); + break; + default: + fprintf(stderr, "unrecognized command \"%c\" at line %d\n", + cmd, lineno); + exit(1); + } +} + + +static void body(void) +{ + char cmd = 0; + double v = 0, f = 1; + int c, s = 0; + + while ((c = getchar()) != EOF) { + if (c == '\n') { + lineno++; + if (cmd) + do_cmd(cmd, s ? -v : v, 1); + cmd = 0; + } else if (isdigit(c)) { + if (f == 1) + v = v*10+c-'0'; + else { + v += f*(c-'0'); + f /= 10; + } + } else if (c == '.') { + f = 0.1; + } else if (c == '-') { + s = !s; + } else { + if (cmd) + do_cmd(cmd, s ? -v : v, 0); + cmd = c; + v = 0; + f = 1; + s = 0; + } + } +} + + +static void usage(const char *name) +{ + fprintf(stderr, +"usage: %s depth drill_d_min drill_d_max\n" +"usage: %s depth mill_d\n\n" +" options can be placed anywhere. -i and -m can be repeated.\n\n" +" -i set units to imperial (mil)\n" +" -m set units to metric (mm, default)\n" +" -f out-file write filtered output to out-file\n" + , name, name); + exit(1); +} + + +int main(int argc, char **argv) +{ + const char *filtered = NULL; + int metric = 1; + double arg[MAX_ARGS]; + int n_arg = 0; + char *end; + double tmp; + int i; + + for (i = 1; i != argc; i++) { + if (*argv[i] != '-') { + if (n_arg == MAX_ARGS) + usage(*argv); + tmp = strtod(argv[i], &end); + if (*end) + usage(*argv); + if (!metric) + tmp = MIL2MM(tmp); + arg[n_arg++] = tmp; + continue; + } + switch (argv[i][1]) { + case 'i': + if (argv[i][2]) + usage(*argv); + metric = 0; + break; + case 'm': + if (argv[i][2]) + usage(*argv); + metric = 1; + break; + case 'f': + if (filtered) + usage(*argv); + if (argv[i][2]) + filtered = argv[i]+2; + else { + i++; + if (i == argc) + usage(*argv); + filtered = argv[i]; + } + break; + default: + usage(*argv); + } + } + + depth = arg[0]; + d0 = arg[1]; + d1 = arg[2]; + + switch (n_arg) { + case 2: + d1 = d0; + mill = 0; + break; + case 3: + mill = 1; + break; + default: + usage(*argv); + } + + header(); + body(); + + return 0; +}