Switch from GPLv2 to GPLv2+
[fw/altos] / ao-tools / ao-cal-accel / ao-cal-accel.c
1 /*
2  * Copyright © 2014 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <err.h>
20 #include <fcntl.h>
21 #include <gelf.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <sysexits.h>
26 #include <unistd.h>
27 #include <getopt.h>
28 #include <string.h>
29 #include <stdbool.h>
30 #include <termios.h>
31 #include "ao-elf.h"
32 #include "ccdbg.h"
33 #include "cc-usb.h"
34 #include "cc.h"
35 #include "ao-verbose.h"
36
37 static const struct option options[] = {
38         { .name = "tty", .has_arg = 1, .val = 'T' },
39         { .name = "device", .has_arg = 1, .val = 'D' },
40         { .name = "raw", .has_arg = 0, .val = 'r' },
41         { .name = "verbose", .has_arg = 1, .val = 'v' },
42         { 0, 0, 0, 0},
43 };
44
45 static void usage(char *program)
46 {
47         fprintf(stderr, "usage: %s [--verbose=<verbose>] [--device=<device>] [-tty=<tty>]\n", program);
48         exit(1);
49 }
50
51 void
52 done(struct cc_usb *cc, int code)
53 {
54         cc_usb_close(cc);
55         exit (code);
56 }
57
58 static int
59 ends_with(char *whole, char *suffix)
60 {
61         int whole_len = strlen(whole);
62         int suffix_len = strlen(suffix);
63
64         if (suffix_len > whole_len)
65                 return 0;
66         return strcmp(whole + whole_len - suffix_len, suffix) == 0;
67 }
68
69 static int
70 starts_with(char *whole, char *prefix)
71 {
72         int whole_len = strlen(whole);
73         int prefix_len = strlen(prefix);
74
75         if (prefix_len > whole_len)
76                 return 0;
77         return strncmp(whole, prefix, prefix_len) == 0;
78 }
79
80 static char **
81 tok(char *line) {
82         char    **strs = malloc (sizeof (char *)), *str;
83         int     n = 0;
84
85         while ((str = strtok(line, " \t"))) {
86                 line = NULL;
87                 strs = realloc(strs, (n + 2) * sizeof (char *));
88                 strs[n] = strdup(str);
89                 n++;
90         }
91         strs[n] = '\0';
92         return strs;
93 }
94
95 static void
96 free_strs(char **strs) {
97         char    *str;
98         int     i;
99
100         for (i = 0; (str = strs[i]) != NULL; i++)
101                 free(str);
102         free(strs);
103 }
104
105 struct flash {
106         struct flash    *next;
107         char            line[512];
108         char            **strs;
109 };
110
111 static struct flash *
112 flash(struct cc_usb *usb)
113 {
114         struct flash    *head = NULL, **tail = &head;
115         cc_usb_printf(usb, "c s\nv\n");
116         for (;;) {
117                 char    line[512];
118                 struct flash    *b;
119
120                 cc_usb_getline(usb, line, sizeof (line));
121                 b = malloc (sizeof (struct flash));
122                 strcpy(b->line, line);
123                 b->strs = tok(line);
124                 b->next = NULL;
125                 *tail = b;
126                 tail = &b->next;
127                 if (strstr(line, "software-version"))
128                         break;
129         }
130         return head;
131 }
132
133 static void
134 free_flash(struct flash *b) {
135         struct flash *n;
136
137         while (b) {
138                 n = b->next;
139                 free_strs(b->strs);
140                 free(b);
141                 b = n;
142         }
143 }
144
145 char **
146 find_flash(struct flash *b, char *word0) {
147         int i;
148         for (;b; b = b->next) {
149                 if (strstr(b->line, word0))
150                         return b->strs;
151         }
152         return NULL;
153 }
154
155 void
156 await_key(void)
157 {
158         struct termios  termios, termios_save;
159         char    buf[512];
160
161         tcgetattr(0, &termios);
162         termios_save = termios;
163         cfmakeraw(&termios);
164         tcsetattr(0, TCSAFLUSH, &termios);
165         read(0, buf, sizeof (buf));
166         tcsetattr(0, TCSAFLUSH, &termios_save);
167 }
168
169 int
170 do_cal(struct cc_usb *usb) {
171         struct flash    *b;
172         char    **accel;
173         char    line[1024];
174         int     l;
175         int     running = 0;
176         int     worked = 1;
177
178         cc_usb_printf(usb, "E 1\nc a 0\n");
179
180         for (;;) {
181                 int     c = cc_usb_getchar_timeout(usb, 20*1000);
182
183                 if (c == '\n')
184                         l = 0;
185                 else if (l < sizeof (line) - 1)
186                         line[l++] = c;
187                 line[l] = '\0';
188                 putchar(c); fflush(stdout);
189                 if (strstr(line, "press a key...")) {
190                         await_key();
191                         cc_usb_printf(usb, " ");
192                         l = 0;
193                         running = 1;
194                 }
195                 else if (strstr(line, "Invalid"))
196                         worked = 0;
197                 if (running && strstr(line, ">")) {
198                         printf("\n");
199                         break;
200                 }
201         }
202         cc_usb_printf(usb, "E 0\n");
203
204         if (!worked) {
205                 printf("Calibration failed\n");
206                 return 0;
207         }
208
209         b = flash(usb);
210
211         accel = find_flash(b, "Accel cal");
212         if (!accel) {
213                 printf("no response\n");
214                 return 0;
215         }
216
217         printf ("Accel cal +1g: %s -1g: %s\n",
218                 accel[3], accel[5]);
219
220         printf ("Saving..."); fflush(stdout);
221         cc_usb_printf (usb, "c w\n");
222         cc_usb_sync(usb);
223         b = flash(usb);
224         printf ("done\n");
225
226         return worked;
227 }
228
229 int
230 main (int argc, char **argv)
231 {
232         char                    *device = NULL;
233         char                    *filename;
234         Elf                     *e;
235         unsigned int            s;
236         int                     i;
237         int                     c;
238         int                     tries;
239         struct cc_usb           *cc = NULL;
240         char                    *tty = NULL;
241         int                     success;
242         int                     verbose = 0;
243         int                     ret = 0;
244         int                     expected_size;
245
246         while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
247                 switch (c) {
248                 case 'T':
249                         tty = optarg;
250                         break;
251                 case 'D':
252                         device = optarg;
253                         break;
254                 case 'v':
255                         verbose++;
256                         break;
257                 default:
258                         usage(argv[0]);
259                         break;
260                 }
261         }
262
263         ao_verbose = verbose;
264
265         if (verbose > 1)
266                 ccdbg_add_debug(CC_DEBUG_BITBANG);
267
268         if (!tty)
269                 tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
270         if (!tty)
271                 tty = cc_usbdevs_find_by_arg(device, "TeleMega");
272         if (!tty)
273                 tty = getenv("ALTOS_TTY");
274         if (!tty)
275                 tty="/dev/ttyACM0";
276
277         cc = cc_usb_open(tty);
278
279         if (!cc)
280                 exit(1);
281
282         if (!do_cal(cc))
283                 ret = 1;
284         done(cc, ret);
285 }