Use ao_ee_flush_internal while holding mutex
[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 __data uint16_t lex_i;
26 static __data uint8_t   lex_c;
27 static __data uint8_t   lex_status;
28 static __data uint8_t   lex_echo;
29
30 #define CMD_LEN 32
31
32 static __xdata uint8_t  cmd_line[CMD_LEN];
33 static __data uint8_t   cmd_len;
34 static __data 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         uint8_t c;
60         while (c = *s++)
61                 putchar(c);
62 }
63
64 static void
65 readline(void)
66 {
67         static 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 *num_ptr = num_buffer + NUM_LEN;
157         uint8_t 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         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         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         uint16_t c;
260         uint8_t __xdata *start, *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         uint8_t b;
287         uint16_t block;
288         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         uint16_t block;
313         uint8_t i;
314         uint16_t len;
315         uint8_t b;
316         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 #if INCLUDE_REMOTE_DEBUG
346 static void
347 debug_enable(void)
348 {
349         dbg_debug_mode();
350 }
351
352 static void
353 debug_reset(void)
354 {
355         dbg_reset();
356 }
357
358 static void
359 debug_put(void)
360 {
361         for (;;) {
362                 white ();
363                 if (lex_c == '\n')
364                         break;
365                 hex();
366                 if (lex_status != SUCCESS)
367                         break;
368                 dbg_send_byte(lex_i);
369         }
370 }
371
372 static void
373 debug_get(void)
374 {
375         uint16_t count;
376         uint16_t i;
377         uint8_t byte;
378         hex();
379         if (lex_status != SUCCESS)
380                 return;
381         count = lex_i;
382         if (count > 256) {
383                 lex_status = SYNTAX_ERROR;
384                 return;
385         }
386         for (i = 0; i < count; i++) {
387                 if (i && (i & 7) == 0)
388                         put_string("\n");
389                 byte = dbg_recv_byte();
390                 put8(byte);
391                 putchar(' ');
392         }
393         put_string("\n");
394 }
395
396 static uint8_t
397 getnibble(void)
398 {
399         uint8_t c;
400
401         c = getchar();
402         if ('0' <= c && c <= '9')
403                 return c - '0';
404         if ('a' <= c && c <= 'f')
405                 return c - ('a' - 10);
406         if ('A' <= c && c <= 'F')
407                 return c - ('A' - 10);
408         lex_status = LEX_ERROR;
409         return 0;
410 }
411
412 static void
413 debug_input(void)
414 {
415         uint16_t count;
416         uint16_t addr;
417         uint8_t b;
418         uint8_t i;
419
420         hex();
421         count = lex_i;
422         hex();
423         addr = lex_i;
424         if (lex_status != SUCCESS)
425                 return;
426         dbg_start_transfer(addr);
427         i = 0;
428         while (count--) {
429                 if (!(i++ & 7))
430                         put_string("\n");
431                 b = dbg_read_byte();
432                 put8(b);
433         }
434         dbg_end_transfer();
435         put_string("\n");
436 }
437
438 static void
439 debug_output(void)
440 {
441         uint16_t count;
442         uint16_t addr;
443         uint8_t b;
444
445         hex();
446         count = lex_i;
447         hex();
448         addr = lex_i;
449         if (lex_status != SUCCESS)
450                 return;
451         dbg_start_transfer(addr);
452         while (count--) {
453                 b = getnibble() << 4;
454                 b |= getnibble();
455                 if (lex_status != SUCCESS)
456                         return;
457                 dbg_write_byte(b);
458         }
459         dbg_end_transfer();
460 }
461 #endif
462
463 static void
464 dump_log(void)
465 {
466         uint8_t more;
467
468         for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
469                 putchar(ao_log_dump.type);
470                 putchar(' ');
471                 put16(ao_log_dump.tick);
472                 putchar(' ');
473                 put16(ao_log_dump.u.anon.d0);
474                 putchar(' ');
475                 put16(ao_log_dump.u.anon.d1);
476                 putchar('\n');
477         }
478 }
479
480 static const uint8_t help_txt[] = 
481         "All numbers are in hex\n"
482         "?                                  Print this message\n"
483         "a                                  Display current ADC values\n"
484         "d <start> <end>                    Dump memory\n"
485         "e <block>                          Dump a block of EEPROM data\n"
486         "w <block> <start> <len> <data> ... Write data to EEPROM\n"
487         "l                                  Dump last flight log\n"
488         "E <0 off, 1 on>                    Set command echo mode\n"
489 #if INCLUDE_REMOTE_DEBUG
490         "\n"
491         "Target debug commands:\n"
492         "D                                  Enable debug mode\n"
493         "R                                  Reset target\n"
494         "P <byte> ...                       Put data to debug port\n"
495         "G <count>                          Get data from debug port\n"
496         "O <count> <addr>                   Output <count> bytes to target at <addr>\n"
497         "I <count> <addr>                   Input <count> bytes to target at <addr>\n"
498 #endif
499 ;
500
501 static void
502 help(void)
503 {
504         put_string(help_txt);
505 }
506
507 static void
508 report(void)
509 {
510         switch(lex_status) {
511         case LEX_ERROR:
512         case SYNTAX_ERROR:
513                 put_string("Syntax error\n");
514                 lex_status = 0;
515                 break;
516         }
517 }
518
519 void
520 ao_cmd(void *parameters)
521 {
522         uint8_t c;
523         (void) parameters;
524
525         lex_echo = 1;
526         for (;;) {
527                 readline();
528                 lex();
529                 white();
530                 c = lex_c;
531                 lex();
532                 switch (c) {
533                 case '?':
534                         help();
535                         break;
536                 case 'd':
537                         dump();
538                         break;
539                 case 'a':
540                         adc_dump();
541                         break;
542                 case 'e':
543                         ee_dump();
544                         break;
545                 case 'w':
546                         ee_store();
547                         break;
548                 case 'l':
549                         dump_log();
550                         break;
551                 case 'E':
552                         echo();
553                         break;
554 #if INCLUDE_REMOTE_DEBUG
555                 case 'D':
556                         debug_enable();
557                         break;
558                 case 'R':
559                         debug_reset();
560                         break;
561                 case 'P':
562                         debug_put();
563                         break;
564                 case 'G':
565                         debug_get();
566                         break;
567                 case 'I':
568                         debug_input();
569                         break;
570                 case 'O':
571                         debug_output();
572                         break;
573 #endif
574                 case '\r':
575                 case '\n':
576                         break;
577                 default:
578                         lex_status = SYNTAX_ERROR;
579                         break;
580                 }
581                 report();
582         }
583                 
584 }
585
586 struct ao_task __xdata cmd_task;
587
588 void
589 ao_cmd_init(void)
590 {
591         ao_add_task(&cmd_task, ao_cmd);
592 }