49efb05e7cae26e192de529d54c34eb65e5958dc
[fw/altos] / ao_cmd.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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 #define LEX_ERROR       1
21 #define SYNTAX_ERROR    2
22 #define SUCCESS         0
23
24 static __xdata uint16_t lex_i;
25 static __xdata uint8_t  lex_c;
26 static __xdata uint8_t  lex_status;
27 static __xdata uint8_t  lex_echo;
28
29 #define CMD_LEN 32
30
31 static __xdata uint8_t  cmd_line[CMD_LEN];
32 static __xdata uint8_t  cmd_len;
33 static __xdata uint8_t  cmd_i;
34
35 void
36 putchar(char c)
37 {
38         if (c == '\n')
39                 ao_usb_putchar('\r');
40         ao_usb_putchar((uint8_t) c);
41 }
42
43 void
44 flush(void)
45 {
46         ao_usb_flush();
47 }
48
49 char
50 getchar(void)
51 {
52         return (char) ao_usb_getchar();
53 }
54
55 static void
56 put_string(char *s)
57 {
58         __xdata uint8_t c;
59         while (c = *s++)
60                 putchar(c);
61 }
62
63 static void
64 readline(void)
65 {
66         __xdata uint8_t c;
67         if (lex_echo)
68                 put_string("> ");
69         cmd_len = 0;
70         for (;;) {
71                 flush();
72                 c = getchar();
73                 /* backspace/delete */
74                 if (c == '\010' || c == '\177') {
75                         if (cmd_len != 0) {
76                                 if (lex_echo)
77                                         put_string("\010 \010");
78                                 --cmd_len;
79                         }
80                         continue;
81                 }
82
83                 /* ^U */
84                 if (c == '\025') {
85                         while (cmd_len != 0) {
86                                 if (lex_echo)
87                                         put_string("\010 \010");
88                                 --cmd_len;
89                         }
90                         continue;
91                 }
92
93                 /* map CR to NL */
94                 if (c == '\r')
95                         c = '\n';
96                 
97                 if (c == '\n') {
98                         if (lex_echo)
99                                 put_string ("\n");
100                         break;
101                 }
102
103                 if (cmd_len >= CMD_LEN - 2) {
104                         if (lex_echo)
105                                 putchar('\007');
106                         continue;
107                 }
108                 cmd_line[cmd_len++] = c;
109                 if (lex_echo)
110                         putchar(c);
111         }
112         cmd_line[cmd_len++] = '\n';
113         cmd_line[cmd_len++] = '\0';
114         cmd_i = 0;
115 }
116
117 static void
118 lex(void)
119 {
120         lex_c = '\n';
121         if (cmd_i < cmd_len)
122                 lex_c = cmd_line[cmd_i++];
123 }
124
125 static void
126 putnibble(uint8_t v)
127 {
128         if (v < 10)
129                 putchar(v + '0');
130         else
131                 putchar(v + ('a' - 10));
132 }
133
134 void
135 put16(uint16_t v)
136 {
137         int8_t i;
138         for (i = 3; i >= 0; i--)
139                 putnibble((v >> (i << 2)) & 0xf);
140 }
141
142 void
143 put8(uint8_t v)
144 {
145         putnibble((v >> 4) & 0xf);
146         putnibble(v & 0xf);
147 }
148
149 #define NUM_LEN 7
150
151 void
152 puti(int i)
153 {
154         static uint8_t __xdata  num_buffer[NUM_LEN];
155         uint8_t __xdata * __xdata num_ptr = num_buffer + NUM_LEN;
156         uint8_t __xdata neg = 0;
157         
158         *--num_ptr = '\0';
159         if (i < 0) {
160                 i = -i;
161                 neg = 1;
162         }
163         do {
164                 *--num_ptr = '0' + i % 10;
165                 i /= 10;
166         } while (i);
167         if (neg)
168                 *--num_ptr = '-';
169         while (num_ptr != num_buffer)
170                 *--num_ptr = ' ';
171         put_string(num_buffer);
172 }
173
174
175 static void
176 white(void)
177 {
178         while (lex_c == ' ' || lex_c == '\t')
179                 lex();
180 }
181
182 static void
183 hex(void)
184 {
185         __xdata uint8_t r = LEX_ERROR;
186         
187         lex_i = 0;
188         white();
189         for(;;) {
190                 if ('0' <= lex_c && lex_c <= '9')
191                         lex_i = (lex_i << 4) | (lex_c - '0');
192                 else if ('a' <= lex_c && lex_c <= 'f')
193                         lex_i = (lex_i << 4) | (lex_c - 'a' + 10);
194                 else if ('A' <= lex_c && lex_c <= 'F')
195                         lex_i = (lex_i << 4) | (lex_c - 'A' + 10);
196                 else
197                         break;
198                 r = SUCCESS;
199                 lex();
200         }
201         if (r != SUCCESS)
202                 lex_status = r;
203 }
204
205 #if 0
206 static void
207 decimal(void)
208 {
209         __xdata uint8_t r = LEX_ERROR;
210         
211         lex_i = 0;
212         white();
213         for(;;) {
214                 if ('0' <= lex_c && lex_c <= '9')
215                         lex_i = (lex_i * 10 ) | (lex_c - '0');
216                 else
217                         break;
218                 r = SUCCESS;
219                 lex();
220         }
221         if (r != SUCCESS)
222                 lex_status = r;
223 }
224 #endif
225
226 static void
227 eol(void)
228 {
229         while (lex_c != '\n')
230                 lex();
231 }
232
233 static void
234 adc_dump(void)
235 {
236         __xdata struct ao_adc   packet;
237         ao_adc_get(&packet);
238         put_string("tick: ");
239         puti(packet.tick);
240         put_string(" accel: ");
241         puti(packet.accel >> 4);
242         put_string(" pres: ");
243         puti(packet.pres >> 4);
244         put_string(" temp: ");
245         puti(packet.temp >> 4);
246         put_string(" batt: ");
247         puti(packet.v_batt >> 4);
248         put_string(" drogue: ");
249         puti(packet.sense_d >> 4);
250         put_string(" main: ");
251         puti(packet.sense_m >> 4);
252         put_string("\n");
253 }
254
255 static void
256 dump(void)
257 {
258         __xdata uint16_t c;
259         __xdata uint8_t * __xdata start, * __xdata end;
260
261         hex();
262         start = (uint8_t __xdata *) lex_i;
263         hex();
264         end = (uint8_t __xdata *) lex_i;
265         if (lex_status != SUCCESS)
266                 return;
267         c = 0;
268         while (start <= end) {
269                 if ((c & 7) == 0) {
270                         if (c)
271                                 put_string("\n");
272                         put16((uint16_t) start);
273                 }
274                 putchar(' ');
275                 put8(*start);
276                 ++c;
277                 start++;
278         }
279         put_string("\n");
280 }
281
282 static void
283 ee_dump(void)
284 {
285         __xdata uint8_t b;
286         __xdata uint16_t block;
287         __xdata uint8_t i;
288         
289         hex();
290         block = lex_i;
291         if (lex_status != SUCCESS)
292                 return;
293         i = 0;
294         do {
295                 if ((i & 7) == 0) {
296                         if (i)
297                                 put_string("\n");
298                         put16((uint16_t) i);
299                 }
300                 putchar(' ');
301                 ao_ee_read(((uint32_t) block << 8) | i, &b, 1);
302                 put8(b);
303                 ++i;
304         } while (i != 0);
305         put_string("\n");
306 }
307
308 static void
309 ee_store(void)
310 {
311         __xdata uint16_t block;
312         __xdata uint8_t i;
313         __xdata uint16_t len;
314         __xdata uint8_t b;
315         __xdata uint32_t addr;
316
317         hex();
318         block = lex_i;
319         hex();
320         i = lex_i;
321         addr = ((uint32_t) block << 8) | i;
322         hex();
323         len = lex_i;
324         if (lex_status != SUCCESS)
325                 return;
326         while (len--) {
327                 hex();
328                 if (lex_status != SUCCESS)
329                         return;
330                 b = lex_i;
331                 ao_ee_write(addr, &b, 1);
332                 addr++;
333         }
334         ao_ee_flush();  
335 }
336
337 static void
338 echo(void)
339 {
340         hex();
341         lex_echo = lex_i != 0;
342 }
343
344 static void
345 debug_enable(void)
346 {
347         ao_dbg_debug_mode();
348 }
349
350 static void
351 debug_reset(void)
352 {
353         ao_dbg_reset();
354 }
355
356 static void
357 debug_put(void)
358 {
359         for (;;) {
360                 white ();
361                 if (lex_c == '\n')
362                         break;
363                 hex();
364                 if (lex_status != SUCCESS)
365                         break;
366                 ao_dbg_send_byte(lex_i);
367         }
368 }
369
370 static void
371 debug_get(void)
372 {
373         __xdata uint16_t count;
374         __xdata uint16_t i;
375         __xdata uint8_t byte;
376         hex();
377         if (lex_status != SUCCESS)
378                 return;
379         count = lex_i;
380         if (count > 256) {
381                 lex_status = SYNTAX_ERROR;
382                 return;
383         }
384         for (i = 0; i < count; i++) {
385                 if (i && (i & 7) == 0)
386                         put_string("\n");
387                 byte = ao_dbg_recv_byte();
388                 put8(byte);
389                 putchar(' ');
390         }
391         put_string("\n");
392 }
393
394 static uint8_t
395 getnibble(void)
396 {
397         __xdata uint8_t c;
398
399         c = getchar();
400         if ('0' <= c && c <= '9')
401                 return c - '0';
402         if ('a' <= c && c <= 'f')
403                 return c - ('a' - 10);
404         if ('A' <= c && c <= 'F')
405                 return c - ('A' - 10);
406         lex_status = LEX_ERROR;
407         return 0;
408 }
409
410 static void
411 debug_input(void)
412 {
413         __xdata uint16_t count;
414         __xdata uint16_t addr;
415         __xdata uint8_t b;
416         __xdata uint8_t i;
417
418         hex();
419         count = lex_i;
420         hex();
421         addr = lex_i;
422         if (lex_status != SUCCESS)
423                 return;
424         ao_dbg_start_transfer(addr);
425         i = 0;
426         while (count--) {
427                 if (!(i++ & 7))
428                         put_string("\n");
429                 b = ao_dbg_read_byte();
430                 put8(b);
431         }
432         ao_dbg_end_transfer();
433         put_string("\n");
434 }
435
436 static void
437 debug_output(void)
438 {
439         __xdata uint16_t count;
440         __xdata uint16_t addr;
441         __xdata uint8_t b;
442
443         hex();
444         count = lex_i;
445         hex();
446         addr = lex_i;
447         if (lex_status != SUCCESS)
448                 return;
449         ao_dbg_start_transfer(addr);
450         while (count--) {
451                 b = getnibble() << 4;
452                 b |= getnibble();
453                 if (lex_status != SUCCESS)
454                         return;
455                 ao_dbg_write_byte(b);
456         }
457         ao_dbg_end_transfer();
458 }
459
460 static void
461 dump_log(void)
462 {
463         __xdata uint8_t more;
464
465         for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
466                 putchar(ao_log_dump.type);
467                 putchar(' ');
468                 put16(ao_log_dump.tick);
469                 putchar(' ');
470                 put16(ao_log_dump.u.anon.d0);
471                 putchar(' ');
472                 put16(ao_log_dump.u.anon.d1);
473                 putchar('\n');
474         }
475 }
476
477 static void
478 send_serial(void)
479 {
480         white();
481         while (lex_c != '\n') {
482                 ao_serial_putchar(lex_c);
483                 lex();
484         }
485 }
486
487 static const uint8_t help_txt[] = 
488         "All numbers are in hex\n"
489         "?                                  Print this message\n"
490         "a                                  Display current ADC values\n"
491         "d <start> <end>                    Dump memory\n"
492         "e <block>                          Dump a block of EEPROM data\n"
493         "w <block> <start> <len> <data> ... Write data to EEPROM\n"
494         "l                                  Dump last flight log\n"
495         "E <0 off, 1 on>                    Set command echo mode\n"
496         "S<data>                            Send data to serial line\n"
497         "\n"
498         "Target debug commands:\n"
499         "D                                  Enable debug mode\n"
500         "R                                  Reset target\n"
501         "P <byte> ...                       Put data to debug port\n"
502         "G <count>                          Get data from debug port\n"
503         "O <count> <addr>                   Output <count> bytes to target at <addr>\n"
504         "I <count> <addr>                   Input <count> bytes to target at <addr>\n"
505 ;
506
507 static void
508 help(void)
509 {
510         put_string(help_txt);
511 }
512
513 static void
514 report(void)
515 {
516         switch(lex_status) {
517         case LEX_ERROR:
518         case SYNTAX_ERROR:
519                 put_string("Syntax error\n");
520                 lex_status = 0;
521                 break;
522         }
523 }
524
525 void
526 ao_cmd(void *parameters)
527 {
528         __xdata uint8_t c;
529         (void) parameters;
530
531         lex_echo = 1;
532         for (;;) {
533                 readline();
534                 lex();
535                 white();
536                 c = lex_c;
537                 lex();
538                 switch (c) {
539                 case '?':
540                         help();
541                         break;
542                 case 'd':
543                         dump();
544                         break;
545                 case 'a':
546                         adc_dump();
547                         break;
548                 case 'e':
549                         ee_dump();
550                         break;
551                 case 'w':
552                         ee_store();
553                         break;
554                 case 'l':
555                         dump_log();
556                         break;
557                 case 'S':
558                         send_serial();
559                         break;
560                 case 'E':
561                         echo();
562                         break;
563                 case 'D':
564                         debug_enable();
565                         break;
566                 case 'R':
567                         debug_reset();
568                         break;
569                 case 'P':
570                         debug_put();
571                         break;
572                 case 'G':
573                         debug_get();
574                         break;
575                 case 'I':
576                         debug_input();
577                         break;
578                 case 'O':
579                         debug_output();
580                         break;
581                 case '\r':
582                 case '\n':
583                         break;
584                 default:
585                         lex_status = SYNTAX_ERROR;
586                         break;
587                 }
588                 report();
589         }
590                 
591 }
592
593 __xdata struct ao_task ao_cmd_task;
594
595 void
596 ao_cmd_init(void)
597 {
598         ao_add_task(&ao_cmd_task, ao_cmd);
599 }