altos: Use flash loader on all STM products
[fw/altos] / src / core / 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 #include "ao_task.h"
20
21 __pdata uint16_t ao_cmd_lex_i;
22 __pdata uint32_t ao_cmd_lex_u32;
23 __pdata char    ao_cmd_lex_c;
24 __pdata enum ao_cmd_status ao_cmd_status;
25
26 #define CMD_LEN 48
27
28 static __xdata char     cmd_line[CMD_LEN];
29 static __pdata uint8_t  cmd_len;
30 static __pdata uint8_t  cmd_i;
31
32 void
33 ao_put_string(__code char *s)
34 {
35         char    c;
36         while ((c = *s++))
37                 putchar(c);
38 }
39
40 static void
41 backspace(void)
42 {
43         ao_put_string ("\010 \010");
44 }
45
46 static void
47 readline(void)
48 {
49         char c;
50         if (ao_echo())
51                 ao_put_string("> ");
52         cmd_len = 0;
53         for (;;) {
54                 flush();
55                 c = getchar();
56                 /* backspace/delete */
57                 if (c == '\010' || c == '\177') {
58                         if (cmd_len != 0) {
59                                 if (ao_echo())
60                                         backspace();
61                                 --cmd_len;
62                         }
63                         continue;
64                 }
65
66                 /* ^U */
67                 if (c == '\025') {
68                         while (cmd_len != 0) {
69                                 if (ao_echo())
70                                         backspace();
71                                 --cmd_len;
72                         }
73                         continue;
74                 }
75
76                 /* map CR to NL */
77                 if (c == '\r')
78                         c = '\n';
79
80                 if (c == '\n') {
81                         if (ao_echo())
82                                 putchar('\n');
83                         break;
84                 }
85
86                 if (cmd_len >= CMD_LEN - 2)
87                         continue;
88                 cmd_line[cmd_len++] = c;
89                 if (ao_echo())
90                         putchar(c);
91         }
92         cmd_line[cmd_len++] = '\n';
93         cmd_line[cmd_len++] = '\0';
94         cmd_i = 0;
95 }
96
97 void
98 ao_cmd_lex(void)
99 {
100         ao_cmd_lex_c = '\n';
101         if (cmd_i < cmd_len)
102                 ao_cmd_lex_c = cmd_line[cmd_i++];
103 }
104
105 static void
106 putnibble(uint8_t v)
107 {
108         if (v < 10)
109                 putchar(v + '0');
110         else
111                 putchar(v + ('a' - 10));
112 }
113
114 uint8_t
115 ao_getnibble(void)
116 {
117         char    c;
118
119         c = getchar();
120         if ('0' <= c && c <= '9')
121                 return c - '0';
122         if ('a' <= c && c <= 'f')
123                 return c - ('a' - 10);
124         if ('A' <= c && c <= 'F')
125                 return c - ('A' - 10);
126         ao_cmd_status = ao_cmd_lex_error;
127         return 0;
128 }
129
130 void
131 ao_cmd_put16(uint16_t v)
132 {
133         ao_cmd_put8(v >> 8);
134         ao_cmd_put8(v);
135 }
136
137 void
138 ao_cmd_put8(uint8_t v)
139 {
140         putnibble((v >> 4) & 0xf);
141         putnibble(v & 0xf);
142 }
143
144 uint8_t
145 ao_cmd_is_white(void)
146 {
147         return ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t';
148 }
149
150 void
151 ao_cmd_white(void)
152 {
153         while (ao_cmd_is_white())
154                 ao_cmd_lex();
155 }
156
157 int8_t
158 ao_cmd_hexchar(char c)
159 {
160         if ('0' <= c && c <= '9')
161                 return (c - '0');
162         if ('a' <= c && c <= 'f')
163                 return (c - 'a' + 10);
164         if ('A' <= c && c <= 'F')
165                 return (c - 'A' + 10);
166         return -1;
167 }
168
169 void
170 ao_cmd_hexbyte(void)
171 {
172         uint8_t i;
173         int8_t  n;
174
175         ao_cmd_lex_i = 0;
176         ao_cmd_white();
177         for (i = 0; i < 2; i++) {
178                 n = ao_cmd_hexchar(ao_cmd_lex_c);
179                 if (n < 0) {
180                         ao_cmd_status = ao_cmd_syntax_error;
181                         break;
182                 }
183                 ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
184                 ao_cmd_lex();
185         }
186 }
187
188 void
189 ao_cmd_hex(void)
190 {
191         __pdata uint8_t r = ao_cmd_lex_error;
192         int8_t  n;
193
194         ao_cmd_lex_i = 0;
195         ao_cmd_white();
196         for(;;) {
197                 n = ao_cmd_hexchar(ao_cmd_lex_c);
198                 if (n < 0)
199                         break;
200                 ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
201                 r = ao_cmd_success;
202                 ao_cmd_lex();
203         }
204         if (r != ao_cmd_success)
205                 ao_cmd_status = r;
206 }
207
208 void
209 ao_cmd_decimal(void)
210 {
211         __pdata uint8_t r = ao_cmd_lex_error;
212
213         ao_cmd_lex_u32 = 0;
214         ao_cmd_white();
215         for(;;) {
216                 if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
217                         ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0');
218                 else
219                         break;
220                 r = ao_cmd_success;
221                 ao_cmd_lex();
222         }
223         if (r != ao_cmd_success)
224                 ao_cmd_status = r;
225         ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32;
226 }
227
228 uint8_t
229 ao_match_word(__code char *word)
230 {
231         while (*word) {
232                 if (ao_cmd_lex_c != *word) {
233                         ao_cmd_status = ao_cmd_syntax_error;
234                         return 0;
235                 }
236                 word++;
237                 ao_cmd_lex();
238         }
239         return 1;
240 }
241
242 static void
243 echo(void)
244 {
245         ao_cmd_hex();
246         if (ao_cmd_status == ao_cmd_success)
247                 ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0;
248 }
249
250 static void
251 ao_reboot(void)
252 {
253         ao_cmd_white();
254         if (!ao_match_word("eboot"))
255                 return;
256         /* Delay waiting for the packet master to be turned off
257          * so that we don't end up back in idle mode because we
258          * received a packet after boot.
259          */
260         flush();
261         ao_delay(AO_SEC_TO_TICKS(1));
262         ao_arch_reboot();
263         ao_panic(AO_PANIC_REBOOT);
264 }
265
266 #ifndef HAS_VERSION
267 #define HAS_VERSION 1
268 #endif
269
270 #if HAS_VERSION
271 static void
272 version(void)
273 {
274         printf("manufacturer     %s\n"
275                "product          %s\n"
276                "serial-number    %u\n"
277 #if HAS_FLIGHT
278                "current-flight   %u\n"
279 #endif
280 #if HAS_LOG
281                "log-format       %u\n"
282 #endif
283                , ao_manufacturer
284                , ao_product
285                , ao_serial_number
286 #if HAS_FLIGHT
287                , ao_flight_number
288 #endif
289 #if HAS_LOG
290                , ao_log_format
291 #endif
292                 );
293 #if HAS_MS5607
294         ao_ms5607_info();
295 #endif
296         printf("software-version %s\n", ao_version);
297 }
298 #endif
299
300 #ifndef NUM_CMDS
301 #define NUM_CMDS        11
302 #endif
303
304 static __code struct ao_cmds    *__xdata (ao_cmds[NUM_CMDS]);
305 static __pdata uint8_t          ao_ncmds;
306
307 static void
308 help(void)
309 {
310         __pdata uint8_t cmds;
311         __pdata uint8_t cmd;
312         __code struct ao_cmds * __pdata cs;
313         __code const char *h;
314         uint8_t e;
315
316         for (cmds = 0; cmds < ao_ncmds; cmds++) {
317                 cs = ao_cmds[cmds];
318                 for (cmd = 0; cs[cmd].func; cmd++) {
319                         h = cs[cmd].help;
320                         ao_put_string(h);
321                         e = strlen(h);
322                         h += e + 1;
323                         e = 45 - e;
324                         while (e--)
325                                 putchar(' ');
326                         ao_put_string(h);
327                         putchar('\n');
328                 }
329         }
330 }
331
332 static void
333 report(void)
334 {
335         switch(ao_cmd_status) {
336         case ao_cmd_lex_error:
337         case ao_cmd_syntax_error:
338                 puts("Syntax error");
339                 ao_cmd_status = 0;
340         default:
341                 break;
342         }
343 }
344
345 void
346 ao_cmd_register(__code struct ao_cmds *cmds)
347 {
348         if (ao_ncmds >= NUM_CMDS)
349                 ao_panic(AO_PANIC_CMD);
350         ao_cmds[ao_ncmds++] = cmds;
351 }
352
353 void
354 ao_cmd(void)
355 {
356         __pdata char    c;
357         uint8_t cmd, cmds;
358         __code struct ao_cmds * __xdata cs;
359         void (*__xdata func)(void);
360
361         for (;;) {
362                 readline();
363                 ao_cmd_lex();
364                 ao_cmd_white();
365                 c = ao_cmd_lex_c;
366                 ao_cmd_lex();
367                 if (c == '\r' || c == '\n')
368                         continue;
369                 func = (void (*)(void)) NULL;
370                 for (cmds = 0; cmds < ao_ncmds; cmds++) {
371                         cs = ao_cmds[cmds];
372                         for (cmd = 0; cs[cmd].func; cmd++)
373                                 if (cs[cmd].help[0] == c) {
374                                         func = cs[cmd].func;
375                                         break;
376                                 }
377                         if (func)
378                                 break;
379                 }
380                 if (func)
381                         (*func)();
382                 else
383                         ao_cmd_status = ao_cmd_syntax_error;
384                 report();
385         }
386 }
387
388 #if HAS_BOOT_LOADER
389
390 #include <ao_boot.h>
391
392 static void
393 ao_loader(void)
394 {
395         flush();
396         ao_boot_loader();
397 }
398 #endif
399
400 __xdata struct ao_task ao_cmd_task;
401
402 __code struct ao_cmds   ao_base_cmds[] = {
403         { help,         "?\0Help" },
404 #if HAS_TASK_INFO
405         { ao_task_info, "T\0Tasks" },
406 #endif
407         { echo,         "E <0 off, 1 on>\0Echo" },
408         { ao_reboot,    "r eboot\0Reboot" },
409 #if HAS_VERSION
410         { version,      "v\0Version" },
411 #endif
412 #if HAS_BOOT_LOADER
413         { ao_loader,    "X\0Switch to boot loader" },
414 #endif
415         { 0,    NULL },
416 };
417
418 void
419 ao_cmd_init(void)
420 {
421         ao_cmd_register(&ao_base_cmds[0]);
422         ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
423 }