Root/cameo/excellon.c

1/*
2 * excellon.c - KiCad drill file input
3 *
4 * Written 2010-2012 by Werner Almesberger
5 * Copyright 2010-2012 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * KiCad drill files are in the Excellon format. The format is described here:
15 *
16 * http://www.excellon.com/manuals/program.htm
17 *
18 * Note that drl2gp currently only implements the subset necessary to process
19 * the KiCad drill files encountered in a few projects, may not work correctly
20 * for drill files from other projects, and will almost certainly fail in
21 * tool-shattering ways when fed excellon files from other sources.
22 */
23
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <ctype.h>
28#include <assert.h>
29
30#include "excellon.h"
31
32
33#define MAX_TOOL 20
34
35
36static double tool_d[MAX_TOOL+1];
37static int lineno = 1;
38static struct path *paths, **anchor;
39
40
41#define IN2MM(in) ((in)*25.4)
42#define MIL2MM(mil) IN2MM((mil)/1000)
43
44
45/* ----- header parsing ---------------------------------------------------- */
46
47
48static void header(FILE *file)
49{
50    enum {
51        ts_nl, /* at beginning of line */
52        ts_t, /* seen a ^T */
53        ts_metric, /* parsing METRIC,... */
54        ts_inch, /* parsing INCH,... */
55        ts_tc, /* seen ^T\d+C */
56        ts_skip, /* skip to next \n */
57    } state = ts_nl;
58    int c, tool;
59    double f = 1;
60    double tmp;
61    const char *next = NULL;
62    int metric = 1;
63
64    while ((c = fgetc(file)) != EOF) {
65        switch (state) {
66        case ts_nl:
67            switch (c) {
68            case 'T':
69                state = ts_t;
70                tool = 0;
71                break;
72            case 'I':
73                state = ts_inch;
74                next = "NCH";
75                break;
76            case 'M':
77                state = ts_metric;
78                next = "ETRIC";
79                break;
80            case '%':
81                return;
82            case '\n':
83                lineno++;
84                break;
85            default:
86                state = ts_skip;
87                break;
88            }
89            break;
90        case ts_inch:
91            if (c == ',')
92                metric = 0;
93            else {
94                if (c == *next++)
95                    break;
96            }
97            state = ts_skip;
98            break;
99        case ts_metric:
100            if (c == ',')
101                metric = 1;
102            else {
103                if (c == *next++)
104                    break;
105            }
106            state = ts_skip;
107            break;
108        case ts_t:
109            if (isdigit(c))
110                tool = tool*10+c-'0';
111            else if (c != 'C')
112                state = ts_skip;
113            else {
114                assert(c != '\n');
115                if (tool > MAX_TOOL) {
116                    fprintf(stderr,
117                        "tool index %d too large (> %d)\n",
118                        tool, MAX_TOOL);
119                    exit(1);
120                }
121                tool_d[tool] = 0;
122                f = 1;
123                state = ts_tc;
124            }
125            break;
126        case ts_tc:
127            if (isdigit(c)) {
128                tmp = c-'0';
129                if (!metric)
130                    tmp = IN2MM(tmp);
131                if (f == 1)
132                    tool_d[tool] =
133                        tool_d[tool]*10+tmp;
134                else {
135                    tool_d[tool] += f*tmp;
136                    f /= 10;
137                }
138            } else if (c == '.') {
139                f = 0.1;
140            } else if (c == '\n') {
141                lineno++;
142                state = ts_nl;
143            } else {
144                state = ts_skip;
145            }
146            break;
147        default:
148            if (c == '\n') {
149                lineno++;
150                state = ts_nl;
151            } else {
152                state = ts_skip;
153            }
154        }
155    }
156}
157
158
159/* ----- body parsing ------------------------------------------------------ */
160
161
162static int do_cmd(char cmd, double v, int nl, const char *name)
163{
164    static int metric = 1;
165    static int slotting = 0;
166    static double x = 0, y = 0, x0 = 0, d = 0;
167    int n = v;
168
169    switch (cmd) {
170    case 'M':
171        switch (n) {
172        case 30: /* end of program */
173            return 0;
174        case 47: /* operator message */
175            break;
176        case 71: /* metric measuring mode */
177            metric = 1;
178            break;
179        case 72: /* inch measuring mode */
180            metric = 0;
181            break;
182        default:
183            fprintf(stderr,
184                "unrecognized command M%d at line %d\n",
185                n, lineno);
186            exit(1);
187        }
188        break;
189    case 'G':
190        switch (n) {
191        case 5: /* drill mode */
192            break;
193        case 85: /* slot */
194            x0 = x;
195            slotting = 1;
196            break;
197        case 90: /* absolute mode */
198            break;
199        default:
200            fprintf(stderr,
201                "unrecognized command G%d at line %d\n",
202                n, lineno);
203            exit(1);
204        }
205        break;
206    case 'T':
207        if (!n) {
208            d = 0;
209            break;
210        }
211        if (n < 1 || n > MAX_TOOL || !tool_d[n]) {
212            fprintf(stderr, "invalid tool T%d at line %d\n",
213                n, lineno);
214            exit(1);
215        }
216        d = tool_d[n];
217        break;
218    case 'X':
219        x = metric ? v : IN2MM(v);
220        break;
221    case 'Y':
222        if (!metric)
223            v = IN2MM(v);
224        if (slotting) {
225            *anchor = path_new(d/2, name);
226            path_add(*anchor, x0, y, 0);
227            path_add(*anchor, x, v, 0);
228            anchor = &(*anchor)->next;
229            slotting = 0;
230            break;
231        }
232        if (nl) {
233            assert(d);
234            *anchor = path_new(d/2, name);
235            path_add(*anchor, x, v, 0);
236            anchor = &(*anchor)->next;
237            break;
238        }
239        y = v;
240        break;
241    default:
242        fprintf(stderr, "unrecognized command \"%c\" at line %d\n",
243            cmd, lineno);
244        exit(1);
245    }
246    return 1;
247}
248
249
250static void body(FILE *file, const char *name)
251{
252    char cmd = 0;
253    double v = 0, f = 1;
254    int c, s = 0;
255
256    while ((c = fgetc(file)) != EOF) {
257        if (c == '\n') {
258            lineno++;
259            if (cmd)
260                do_cmd(cmd, s ? -v : v, 1, name);
261            cmd = 0;
262        } else if (isdigit(c)) {
263            if (f == 1)
264                v = v*10+c-'0';
265            else {
266                v += f*(c-'0');
267                f /= 10;
268            }
269        } else if (c == '.') {
270            f = 0.1;
271        } else if (c == '-') {
272            s = !s;
273        } else {
274            if (cmd)
275                if (!do_cmd(cmd, s ? -v : v, 0, name))
276                    return;
277            cmd = c;
278            v = 0;
279            f = 1;
280            s = 0;
281        }
282    }
283}
284
285
286struct path *excellon_read(const char *name)
287{
288    FILE *file;
289
290    file = name ? fopen(name, "r") : stdin;
291    if (!file) {
292        perror(name);
293        exit(1);
294    }
295
296    lineno = 1;
297    paths = NULL;
298    anchor = &paths;
299
300    header(file);
301    body(file, name);
302
303    fclose(file);
304    return paths;
305}
306

Archive Download this file

Branches:
master



interactive