Add DSP code to filter data, allowing for integration/differentiation
[fw/altos] / ao-tools / lib / cc-usb.c
1 /*
2  * Copyright © 2009 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 <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <stdarg.h>
23 #include <poll.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <termios.h>
29 #include "ccdbg-debug.h"
30 #include "cc-usb.h"
31
32
33 #define CC_NUM_HEX_READ         64
34 /*
35  * AltOS has different buffer sizes for in/out packets
36  */
37 #define CC_IN_BUF               65536
38 #define CC_OUT_BUF              64
39 #define DEFAULT_TTY             "/dev/ttyACM0"
40
41 struct cc_hex_read {
42         uint8_t *buf;
43         int     len;
44 };
45
46 struct cc_usb {
47         int                     fd;
48         uint8_t                 in_buf[CC_IN_BUF];
49         int                     in_pos;
50         int                     in_count;
51         uint8_t                 out_buf[CC_OUT_BUF];
52         int                     out_count;
53
54         struct cc_hex_read      hex_buf[CC_NUM_HEX_READ];
55         int                     hex_count;
56 };
57
58 #define NOT_HEX 0xff
59
60 static uint8_t
61 cc_hex_nibble(uint8_t c)
62 {
63         if ('0' <= c && c <= '9')
64                 return c - '0';
65         if ('a' <= c && c <= 'f')
66                 return c - 'a' + 10;
67         if ('A' <= c && c <= 'F')
68                 return c - 'A' + 10;
69         return NOT_HEX;
70 }
71
72 /*
73  * Take raw input bytes, parse them as hex
74  * and write them to the waiting buffer
75  */
76 static void
77 cc_handle_hex_read(struct cc_usb *cc)
78 {
79         uint8_t h, l;
80         int     hex_pos;
81
82         hex_pos = 0;
83         while (hex_pos < cc->hex_count && cc->in_pos < cc->in_count) {
84                 /*
85                  * Skip to next hex character
86                  */
87                 while (cc->in_pos < cc->in_count &&
88                        cc_hex_nibble(cc->in_buf[cc->in_pos]) == NOT_HEX)
89                         cc->in_pos++;
90                 /*
91                  * Make sure we have two characters left
92                  */
93                 if (cc->in_count - cc->in_pos < 2)
94                         break;
95                 /*
96                  * Parse hex number
97                  */
98                 h = cc_hex_nibble(cc->in_buf[cc->in_pos]);
99                 l = cc_hex_nibble(cc->in_buf[cc->in_pos+1]);
100                 if (h == NOT_HEX || l == NOT_HEX) {
101                         fprintf(stderr, "hex read error\n");
102                         break;
103                 }
104                 cc->in_pos += 2;
105                 /*
106                  * Store hex number
107                  */
108                 *cc->hex_buf[hex_pos].buf++ = (h << 4) | l;
109                 if (--cc->hex_buf[hex_pos].len <= 0)
110                         hex_pos++;
111         }
112
113         /* Move pending hex reads to the start of the array */
114         if (hex_pos) {
115                 memmove(cc->hex_buf, cc->hex_buf + hex_pos,
116                         (cc->hex_count - hex_pos) * sizeof (cc->hex_buf[0]));
117                 cc->hex_count -= hex_pos;
118         }
119 }
120
121 static void
122 cc_usb_dbg(int indent, uint8_t *bytes, int len)
123 {
124         int     eol = 1;
125         int     i;
126         uint8_t c;
127         while (len--) {
128                 c = *bytes++;
129                 if (eol) {
130                         for (i = 0; i < indent; i++)
131                                 ccdbg_debug(CC_DEBUG_BITBANG, " ");
132                         eol = 0;
133                 }
134                 switch (c) {
135                 case '\r':
136                         ccdbg_debug(CC_DEBUG_BITBANG, "^M");
137                         break;
138                 case '\n':
139                         eol = 1;
140                 default:
141                         ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
142                 }
143         }
144 }
145
146 /*
147  * Flush pending writes, fill pending reads
148  */
149
150 static int
151 _cc_usb_sync(struct cc_usb *cc, int wait_for_input)
152 {
153         int             ret;
154         struct pollfd   fds;
155         int             timeout;
156
157         fds.fd = cc->fd;
158         for (;;) {
159                 if (cc->hex_count || cc->out_count)
160                         timeout = 5000;
161                 else if (wait_for_input && cc->in_pos == cc->in_count)
162                         timeout = wait_for_input;
163                 else
164                         timeout = 0;
165                 fds.events = 0;
166                 /* Move remaining bytes to the start of the input buffer */
167                 if (cc->in_pos) {
168                         memmove(cc->in_buf, cc->in_buf + cc->in_pos,
169                                 cc->in_count - cc->in_pos);
170                         cc->in_count -= cc->in_pos;
171                         cc->in_pos = 0;
172                 }
173                 if (cc->in_count < CC_IN_BUF)
174                         fds.events |= POLLIN;
175                 if (cc->out_count)
176                         fds.events |= POLLOUT;
177                 ret = poll(&fds, 1, timeout);
178                 if (ret == 0) {
179                         if (timeout)
180                                 return -1;
181                         break;
182                 }
183                 if (ret < 0) {
184                         perror("poll");
185                         return -1;
186                 }
187                 if (fds.revents & POLLIN) {
188                         ret = read(cc->fd, cc->in_buf + cc->in_count,
189                                    CC_IN_BUF - cc->in_count);
190                         if (ret > 0) {
191                                 cc_usb_dbg(24, cc->in_buf + cc->in_count, ret);
192                                 cc->in_count += ret;
193                                 if (cc->hex_count)
194                                         cc_handle_hex_read(cc);
195                         } else if (ret < 0)
196                                 perror("read");
197                 }
198                 if (fds.revents & POLLOUT) {
199                         ret = write(cc->fd, cc->out_buf,
200                                     cc->out_count);
201                         if (ret > 0) {
202                                 cc_usb_dbg(0, cc->out_buf, ret);
203                                 memmove(cc->out_buf,
204                                         cc->out_buf + ret,
205                                         cc->out_count - ret);
206                                 cc->out_count -= ret;
207                         } else if (ret < 0)
208                                 perror("write");
209                 }
210         }
211         return 0;
212 }
213
214 void
215 cc_usb_sync(struct cc_usb *cc)
216 {
217         if (_cc_usb_sync(cc, 0) < 0) {
218                 fprintf(stderr, "USB link timeout\n");
219                 exit(1);
220         }
221 }
222
223 void
224 cc_usb_printf(struct cc_usb *cc, char *format, ...)
225 {
226         char    buf[1024], *b;
227         va_list ap;
228         int     ret, this_time;
229
230         /* sprintf to a local buffer */
231         va_start(ap, format);
232         ret = vsnprintf(buf, sizeof(buf), format, ap);
233         va_end(ap);
234         if (ret > sizeof(buf)) {
235                 fprintf(stderr, "printf overflow for format %s\n",
236                         format);
237         }
238
239         /* flush local buffer to the wire */
240         b = buf;
241         while (ret > 0) {
242                 this_time = ret;
243                 if (this_time > CC_OUT_BUF - cc->out_count)
244                         this_time = CC_OUT_BUF - cc->out_count;
245                 memcpy(cc->out_buf + cc->out_count, b, this_time);
246                 cc->out_count += this_time;
247                 ret -= this_time;
248                 b += this_time;
249                 while (cc->out_count >= CC_OUT_BUF)
250                         cc_usb_sync(cc);
251         }
252 }
253
254 int
255 cc_usb_getchar(struct cc_usb *cc)
256 {
257         while (cc->in_pos == cc->in_count) {
258                 if (_cc_usb_sync(cc, 5000) < 0) {
259                         fprintf(stderr, "USB link timeout\n");
260                         exit(1);
261                 }
262         }
263         return cc->in_buf[cc->in_pos++];
264 }
265
266 void
267 cc_usb_getline(struct cc_usb *cc, char *line, int max)
268 {
269         int     c;
270
271         while ((c = cc_usb_getchar(cc)) != '\n') {
272                 switch (c) {
273                 case '\r':
274                         break;
275                 default:
276                         if (max > 1) {
277                                 *line++ = c;
278                                 max--;
279                         }
280                         break;
281                 }
282         }
283         *line++ = '\0';
284 }
285
286 int
287 cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len)
288 {
289         int     this_len;
290         int     ret = len;
291
292         while (len) {
293                 this_len = len;
294                 if (this_len > 8)
295                         this_len = 8;
296                 len -= this_len;
297                 cc_usb_printf(cc, "P");
298                 while (this_len--)
299                         cc_usb_printf (cc, " %02x", (*bytes++) & 0xff);
300                 cc_usb_printf(cc, "\n");
301         }
302         return ret;
303 }
304
305 void
306 cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len)
307 {
308         struct cc_hex_read      *hex_buf;
309
310         /* At the start of a command sequence, flush any pending input */
311         if (cc->hex_count == 0) {
312                 cc_usb_sync(cc);
313                 cc->in_count = 0;
314         }
315         while (cc->hex_count >= CC_NUM_HEX_READ)
316                 cc_usb_sync(cc);
317         hex_buf = &cc->hex_buf[cc->hex_count++];
318         hex_buf->buf = buf;
319         hex_buf->len = len;
320 }
321
322 int
323 cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *buf, int len)
324 {
325         cc_queue_read(cc, buf, len);
326         cc_usb_printf(cc, "G %x\n", len);
327         return len;
328 }
329
330 int
331 cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len)
332 {
333         cc_usb_printf(cc, "O %x %x\n", len, addr);
334         while (len--)
335                 cc_usb_printf(cc, "%02x", *bytes++);
336         cc_usb_sync(cc);
337         return 0;
338 }
339
340 int
341 cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len)
342 {
343         int     i;
344         cc_queue_read(cc, bytes, len);
345         cc_usb_printf(cc, "I %x %x\n", len, addr);
346         cc_usb_sync(cc);
347         for (i = 0; i < len; i++) {
348                 if ((i & 15) == 0) {
349                         if (i)
350                                 ccdbg_debug(CC_DEBUG_MEMORY, "\n");
351                         ccdbg_debug(CC_DEBUG_MEMORY, "\t%04x", addr + i);
352                 }
353                 ccdbg_debug(CC_DEBUG_MEMORY, " %02x", bytes[i]);
354         }
355         ccdbg_debug(CC_DEBUG_MEMORY, "\n");
356         return 0;
357 }
358
359 int
360 cc_usb_debug_mode(struct cc_usb *cc)
361 {
362         cc_usb_sync(cc);
363         cc_usb_printf(cc, "D\n");
364         return 1;
365 }
366
367 int
368 cc_usb_reset(struct cc_usb *cc)
369 {
370         cc_usb_sync(cc);
371         cc_usb_printf(cc, "R\n");
372         return 1;
373 }
374
375 static struct termios   save_termios;
376
377 struct cc_usb *
378 cc_usb_open(char *tty)
379 {
380         struct cc_usb   *cc;
381         struct termios  termios;
382
383         if (!tty)
384                 tty = DEFAULT_TTY;
385         cc = calloc (sizeof (struct cc_usb), 1);
386         if (!cc)
387                 return NULL;
388         cc->fd = open(tty, O_RDWR | O_NONBLOCK);
389         if (cc->fd < 0) {
390                 perror(tty);
391                 free (cc);
392                 return NULL;
393         }
394         tcgetattr(cc->fd, &termios);
395         save_termios = termios;
396         cfmakeraw(&termios);
397         tcsetattr(cc->fd, TCSAFLUSH, &termios);
398         cc_usb_printf(cc, "E 0\nm 0\n");
399         do {
400                 cc->in_count = cc->in_pos = 0;
401                 _cc_usb_sync(cc, 100);
402         } while (cc->in_count > 0);
403         return cc;
404 }
405
406 void
407 cc_usb_close(struct cc_usb *cc)
408 {
409         tcsetattr(cc->fd, TCSAFLUSH, &save_termios);
410         close (cc->fd);
411         free (cc);
412 }