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