Add ccdump
[fw/altos] / 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_READ             16
34 #define CC_BUF                  1024
35 #define DEFAULT_TTY             "/dev/ttyACM0"
36
37 struct cc_read {
38         uint8_t *buf;
39         int     len;
40 };
41
42 struct cc_usb {
43         int             fd;
44         uint8_t         in_buf[CC_BUF];
45         int             in_count;
46         uint8_t         out_buf[CC_BUF];
47         int             out_count;
48         struct cc_read  read_buf[CC_NUM_READ];
49         int             read_count;
50 };
51
52 #define NOT_HEX 0xff
53
54 static uint8_t
55 cc_hex_nibble(uint8_t c)
56 {
57         if ('0' <= c && c <= '9')
58                 return c - '0';
59         if ('a' <= c && c <= 'f')
60                 return c - 'a' + 10;
61         if ('A' <= c && c <= 'F')
62                 return c - 'A' + 10;
63         return NOT_HEX;
64 }
65
66 /*
67  * Take raw input bytes, parse them as hex
68  * and write them to the waiting buffer
69  */
70 static void
71 cc_handle_in(struct cc_usb *cc)
72 {
73         uint8_t h, l;
74         int     in_pos;
75         int     read_pos;
76         
77         in_pos = 0;
78         read_pos = 0;
79         while (read_pos < cc->read_count && in_pos < cc->in_count) {
80                 /*
81                  * Skip to next hex character
82                  */
83                 while (in_pos < cc->in_count && 
84                        cc_hex_nibble(cc->in_buf[in_pos]) == NOT_HEX)
85                         in_pos++;
86                 /*
87                  * Make sure we have two characters left
88                  */
89                 if (cc->in_count - in_pos < 2)
90                         break;
91                 /*
92                  * Parse hex number
93                  */
94                 h = cc_hex_nibble(cc->in_buf[in_pos]);
95                 l = cc_hex_nibble(cc->in_buf[in_pos+1]);
96                 if (h == NOT_HEX || l == NOT_HEX) {
97                         fprintf(stderr, "hex read error\n");
98                         break;
99                 }
100                 in_pos += 2;
101                 /*
102                  * Store hex number
103                  */
104                 *cc->read_buf[read_pos].buf++ = (h << 4) | l;
105                 if (--cc->read_buf[read_pos].len <= 0)
106                         read_pos++;
107         }
108         
109         /* Move remaining bytes to the start of the input buffer */
110         if (in_pos) {
111                 memmove(cc->in_buf, cc->in_buf + in_pos,
112                         cc->in_count - in_pos);
113                 cc->in_count -= in_pos;
114         }
115
116         /* Move pending reads to the start of the array */
117         if (read_pos) {
118                 memmove(cc->read_buf, cc->read_buf + read_pos,
119                         (cc->read_count - read_pos) * sizeof (cc->read_buf[0]));
120                 cc->read_count -= read_pos;
121         }
122
123         /* Once we're done reading, flush any pending input */
124         if (cc->read_count == 0)
125                 cc->in_count = 0;
126 }
127
128 static void
129 cc_usb_dbg(int indent, uint8_t *bytes, int len)
130 {
131         int     eol = 1;
132         int     i;
133         uint8_t c;
134         while (len--) {
135                 c = *bytes++;
136                 if (eol) {
137                         for (i = 0; i < indent; i++)
138                                 ccdbg_debug(CC_DEBUG_BITBANG, " ");
139                         eol = 0;
140                 }
141                 switch (c) {
142                 case '\r':
143                         ccdbg_debug(CC_DEBUG_BITBANG, "^M");
144                         break;
145                 case '\n':
146                         eol = 1;
147                 default:
148                         ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
149                 }
150         }
151 }
152
153 /*
154  * Flush pending writes, fill pending reads
155  */
156 void
157 cc_usb_sync(struct cc_usb *cc)
158 {
159         int             ret;
160         struct pollfd   fds;
161         int             timeout;
162
163         fds.fd = cc->fd;
164         for (;;) {
165                 if (cc->read_count || cc->out_count)
166                         timeout = -1;
167                 else
168                         timeout = 0;
169                 fds.events = 0;
170                 if (cc->in_count < CC_BUF)
171                         fds.events |= POLLIN;
172                 if (cc->out_count)
173                         fds.events |= POLLOUT;
174                 ret = poll(&fds, 1, timeout);
175                 if (ret == 0)
176                         break;
177                 if (ret < 0) {
178                         perror("poll");
179                         break;
180                 }
181                 if (fds.revents & POLLIN) {
182                         ret = read(cc->fd, cc->in_buf + cc->in_count,
183                                    CC_BUF - cc->in_count);
184                         if (ret > 0) {
185                                 cc_usb_dbg(24, cc->in_buf + cc->in_count, ret);
186                                 cc->in_count += ret;
187                                 cc_handle_in(cc);
188                         }
189                 }
190                 if (fds.revents & POLLOUT) {
191                         ret = write(cc->fd, cc->out_buf,
192                                     cc->out_count);
193                         if (ret > 0) {
194                                 cc_usb_dbg(0, cc->out_buf, ret);
195                                 memmove(cc->out_buf,
196                                         cc->out_buf + ret,
197                                         cc->out_count - ret);
198                                 cc->out_count -= ret;
199                         }
200                 }
201         }
202 }
203
204 void
205 cc_usb_printf(struct cc_usb *cc, char *format, ...)
206 {
207         char    buf[1024], *b;
208         va_list ap;
209         int     ret, this_time;
210         
211         /* sprintf to a local buffer */
212         va_start(ap, format);
213         ret = vsnprintf(buf, sizeof(buf), format, ap);
214         va_end(ap);
215         if (ret > sizeof(buf)) {
216                 fprintf(stderr, "printf overflow for format %s\n",
217                         format);
218         }
219
220         /* flush local buffer to the wire */
221         b = buf;
222         while (ret > 0) {
223                 this_time = ret;
224                 if (this_time > CC_BUF - cc->out_count)
225                         this_time = CC_BUF - cc->out_count;
226                 memcpy(cc->out_buf + cc->out_count, b, this_time);
227                 cc->out_count += this_time;
228                 ret -= this_time;
229                 b += this_time;
230                 while (cc->out_count >= CC_BUF)
231                         cc_usb_sync(cc);
232         }
233 }
234
235 int
236 cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len)
237 {
238         int     this_len;
239         int     ret = len;
240         
241         while (len) {
242                 this_len = len;
243                 if (this_len > 8)
244                         this_len = 8;
245                 len -= this_len;
246                 cc_usb_printf(cc, "P");
247                 while (this_len--)
248                         cc_usb_printf (cc, " %02x", (*bytes++) & 0xff);
249                 cc_usb_printf(cc, "\n");
250         }
251         return ret;
252 }
253
254 void
255 cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len)
256 {
257         struct cc_read  *read_buf;
258         while (cc->read_count >= CC_NUM_READ)
259                 cc_usb_sync(cc);
260         read_buf = &cc->read_buf[cc->read_count++];
261         read_buf->buf = buf;
262         read_buf->len = len;
263 }
264
265 int
266 cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *buf, int len)
267 {
268         cc_queue_read(cc, buf, len);
269         cc_usb_printf(cc, "G %x\n", len);
270         return len;
271 }
272
273 int
274 cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len)
275 {
276         cc_usb_printf(cc, "O %x %x\n", len, addr);
277         while (len--)
278                 cc_usb_printf(cc, "%02x", *bytes++);
279         return 0;
280 }
281
282 int
283 cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len)
284 {
285         int     i;
286         cc_queue_read(cc, bytes, len);
287         cc_usb_printf(cc, "I %x %x\n", len, addr);
288         cc_usb_sync(cc);
289         for (i = 0; i < len; i++) {
290                 if ((i & 15) == 0) {
291                         if (i)
292                                 ccdbg_debug(CC_DEBUG_MEMORY, "\n");
293                         ccdbg_debug(CC_DEBUG_MEMORY, "\t%04x", addr + i);
294                 }
295                 ccdbg_debug(CC_DEBUG_MEMORY, " %02x", bytes[i]);
296         }
297         ccdbg_debug(CC_DEBUG_MEMORY, "\n");
298         return 0;
299 }
300
301 int
302 cc_usb_debug_mode(struct cc_usb *cc)
303 {
304         cc_usb_sync(cc);
305         cc_usb_printf(cc, "D\n");
306         return 1;
307 }
308
309 int
310 cc_usb_reset(struct cc_usb *cc)
311 {
312         cc_usb_sync(cc);
313         cc_usb_printf(cc, "R\n");
314         return 1;
315 }
316
317 static struct termios   save_termios;
318
319 struct cc_usb *
320 cc_usb_open(void)
321 {
322         struct cc_usb   *cc;
323         char            *tty;
324         struct termios  termios;
325         
326         tty = getenv("CCDBG_TTY");
327         if (!tty)
328                 tty = DEFAULT_TTY;
329         cc = calloc (sizeof (struct cc_usb), 1);
330         if (!cc)
331                 return NULL;
332         cc->fd = open(tty, O_RDWR | O_NONBLOCK);
333         if (cc->fd < 0) {
334                 perror(tty);
335                 free (cc);
336                 return NULL;
337         }
338         tcgetattr(cc->fd, &termios);
339         save_termios = termios;
340         cfmakeraw(&termios);
341         tcsetattr(cc->fd, TCSAFLUSH, &termios);
342         cc_usb_printf(cc, "E 0\n");
343         cc_usb_sync(cc);
344         sleep(1);
345         cc_usb_sync(cc);
346         return cc;
347 }
348
349 void
350 cc_usb_close(struct cc_usb *cc)
351 {
352         tcsetattr(cc->fd, TCSAFLUSH, &save_termios);
353         close (cc->fd);
354         free (cc);
355 }
356