df76f478b3807ff4dc8c55c87616cc54175c76e9
[protos/xbee-avr.git] / commands.c
1 /*
2  *  Copyright Droids Corporation (2011)
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,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Revision : $Id: commands.c,v 1.9 2009-11-08 17:24:33 zer0 Exp $
19  *
20  *  Olivier MATZ <zer0@droids-corp.org>
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <aversive.h>
28 #include <aversive/pgmspace.h>
29 #include <aversive/queue.h>
30 #include <aversive/endian.h>
31 #include <aversive/error.h>
32 #include <aversive/wait.h>
33 #include <parse.h>
34 #include <rdline.h>
35 #include <parse_string.h>
36 #include <parse_num.h>
37 #include <uart.h>
38 #include <xbee.h>
39
40 #include "callout.h"
41 #include "parse_atcmd.h"
42 #include "parse_neighbor.h"
43 #include "parse_monitor.h"
44
45 #include "spi_servo.h"
46 #include "rc_proto.h"
47 #include "main.h"
48 #include "cmdline.h"
49 #include "beep.h"
50 #include "eeprom_config.h"
51
52 /* commands_gen.c */
53 extern const parse_inst_t PROGMEM cmd_reset;
54 extern const parse_inst_t PROGMEM cmd_bootloader;
55 extern const parse_inst_t PROGMEM cmd_log;
56 extern const parse_inst_t PROGMEM cmd_log_show;
57 extern const parse_inst_t PROGMEM cmd_log_type;
58 extern const parse_inst_t PROGMEM cmd_stack_space;
59 extern const parse_inst_t PROGMEM cmd_scheduler;
60
61 static int monitor_period_ms = 1000;
62 static int monitor_running = 0;
63 static int monitor_count = 0;
64 static struct callout monitor_event;
65 struct monitor_reg *monitor_current;
66
67 static int range_period_ms = 1000;
68 static int range_powermask = 0x1F;
69 //static uint8_t range_power = 0;
70 static int range_running = 0;
71 static uint64_t range_dstaddr = 0xFFFF; /* broadcast by default */
72 static struct callout range_event;
73 static int range_count = 100;
74 static int range_cur_count = 0;
75
76 static void monitor_cb(struct callout_mgr *cm,
77                        struct callout *clt, void *dummy)
78 {
79         (void)clt;
80         (void)dummy;
81
82         if (monitor_current == NULL)
83                 monitor_current = LIST_FIRST(&xbee_monitor_list);
84
85         xbeeapp_send_atcmd(monitor_current->atcmd, NULL, 0, 0, NULL, NULL);
86         monitor_current = LIST_NEXT(monitor_current, next);
87         callout_reschedule(cm, clt, monitor_period_ms / monitor_count);
88 }
89
90 static void range_cb(struct callout_mgr *cm,
91                      struct callout *clt, void *dummy)
92 {
93         (void)cm;
94         (void)clt;
95         (void)dummy;
96 #if 0
97         uint8_t i, mask;
98         struct rc_proto_range rangepkt;
99
100         (void)clt;
101         (void)dummy;
102
103         range_cur_count--;
104
105         /* get new xmit power */
106         for (i = 1; i <= 8; i++) {
107                 mask = 1 << ((range_power + i) & 0x7);
108                 if (mask & range_powermask)
109                         break;
110         }
111         range_power = ((range_power + i) & 0x7);
112
113         xbeeapp_send_atcmd("PL", &range_power, sizeof(range_power), 0, NULL, NULL);
114
115         rangepkt.type = RC_PROTO_TYPE_RANGE;
116         rangepkt.power_level = range_power;
117
118         xbeeapp_send_msg(range_dstaddr, &rangepkt, sizeof(rangepkt), 0);
119
120         if (range_cur_count == 0) {
121                 range_running = 0;
122                 return;
123         }
124
125         callout_reschedule(cm, clt, range_period_ms);
126 #endif
127 }
128
129 /* this structure is filled when cmd_help is parsed successfully */
130 struct cmd_help_result {
131         fixed_string_t help;
132         struct xbee_atcmd *cmd;
133 };
134
135 /* function called when cmd_help is parsed successfully */
136 static void cmd_help_parsed(void *parsed_result, void *data)
137 {
138         struct cmd_help_result *res = parsed_result;
139         struct xbee_atcmd cmdcopy;
140         int type;
141
142         (void)data;
143
144         memcpy_P(&cmdcopy, res->cmd, sizeof(cmdcopy));
145         type = (cmdcopy.flags & (XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE));
146         switch (type) {
147                 case XBEE_ATCMD_F_READ:
148                         printf_P(PSTR("Read-only\r\n"));
149                         break;
150                 case XBEE_ATCMD_F_WRITE:
151                         printf_P(PSTR("Write-only\r\n"));
152                         break;
153                 default:
154                         printf_P(PSTR("Read-write\r\n"));
155                         break;
156         }
157         if (cmdcopy.flags & XBEE_ATCMD_F_PARAM_NONE)
158                 printf_P(PSTR("No argument\r\n"));
159         else if (cmdcopy.flags & XBEE_ATCMD_F_PARAM_U8)
160                 printf_P(PSTR("Register is unsigned 8 bits\r\n"));
161         else if (cmdcopy.flags & XBEE_ATCMD_F_PARAM_U16)
162                 printf_P(PSTR("Register is unsigned 16 bits\r\n"));
163         else if (cmdcopy.flags & XBEE_ATCMD_F_PARAM_U32)
164                 printf_P(PSTR("Register is unsigned 32 bits\r\n"));
165         else if (cmdcopy.flags & XBEE_ATCMD_F_PARAM_S16)
166                 printf_P(PSTR("Register is signed 16 bits\r\n"));
167         else if (cmdcopy.flags & XBEE_ATCMD_F_PARAM_STRING_20B)
168                 printf_P(PSTR("Register is a 20 bytes string\r\n"));
169         else
170                 printf_P(PSTR("Unknown argument\r\n"));
171
172         printf_P(PSTR("%S\r\n"), cmdcopy.help);
173 }
174 const char PROGMEM str_help_help[] = "help";
175
176 const parse_token_string_t PROGMEM cmd_help_help =
177         TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, str_help_help);
178
179 const parse_token_atcmd_t PROGMEM cmd_help_atcmd =
180         TOKEN_ATCMD_INITIALIZER(struct cmd_help_result, cmd, &xbee_dev,
181                                 0, 0);
182
183 const char PROGMEM help_help[] = "Help a register using an AT command";
184 const parse_inst_t PROGMEM cmd_help = {
185         .f = cmd_help_parsed,  /* function to call */
186         .data = NULL,      /* 2nd arg of func */
187         .help_str = help_help,
188         .tokens = {        /* token list, NULL terminated */
189                 (PGM_P)&cmd_help_help,
190                 (PGM_P)&cmd_help_atcmd,
191                 NULL,
192         },
193 };
194
195 /* ************* */
196
197 struct cmd_neigh_del_result {
198         fixed_string_t cmd;
199         fixed_string_t action;
200         struct xbee_neigh *neigh;
201 };
202
203 static void cmd_neigh_del_parsed(void *parsed_result,
204                                 void *data)
205 {
206         struct cmd_neigh_del_result *res = parsed_result;
207
208         (void)data;
209         xbee_neigh_del(xbee_dev, res->neigh);
210 }
211
212 const char PROGMEM str_neigh_del_neigh[] = "neigh";
213 const parse_token_string_t PROGMEM cmd_neigh_del_cmd =
214         TOKEN_STRING_INITIALIZER(struct cmd_neigh_del_result, cmd,
215                                  str_neigh_del_neigh);
216 const char PROGMEM str_neigh_del_del[] = "del";
217 const parse_token_string_t PROGMEM cmd_neigh_del_action =
218         TOKEN_STRING_INITIALIZER(struct cmd_neigh_del_result, action,
219                                  str_neigh_del_del);
220 const parse_token_neighbor_t PROGMEM cmd_neigh_del_neigh =
221         TOKEN_NEIGHBOR_INITIALIZER(struct cmd_neigh_del_result, neigh,
222                                    &xbee_dev);
223
224 const char PROGMEM help_neigh_del[] = "delete a neighbor";
225 const parse_inst_t PROGMEM cmd_neigh_del = {
226         .f = cmd_neigh_del_parsed,  /* function to call */
227         .data = NULL,      /* 2nd arg of func */
228         .help_str = help_neigh_del,
229         .tokens = {        /* token list, NULL terminated */
230                 (PGM_P)&cmd_neigh_del_cmd,
231                 (PGM_P)&cmd_neigh_del_action,
232                 (PGM_P)&cmd_neigh_del_neigh,
233                 NULL,
234         },
235 };
236
237 /* ************* */
238
239 struct cmd_neigh_add_result {
240         fixed_string_t cmd;
241         fixed_string_t action;
242         fixed_string_t name;
243         uint64_t addr;
244 };
245
246 static void cmd_neigh_add_parsed(void *parsed_result,
247                                  void *data)
248 {
249         struct cmd_neigh_add_result *res = parsed_result;
250
251         (void)data;
252         if (xbee_neigh_add(xbee_dev, res->name, res->addr) == NULL)
253                 printf_P(PSTR("name or addr already exist\r\n"));
254 }
255
256 const char PROGMEM str_neigh_add_neigh[] = "neigh";
257 const parse_token_string_t PROGMEM cmd_neigh_add_cmd =
258         TOKEN_STRING_INITIALIZER(struct cmd_neigh_add_result, cmd,
259                                  str_neigh_add_neigh);
260 const char PROGMEM str_neigh_add_add[] = "add";
261 const parse_token_string_t PROGMEM cmd_neigh_add_action =
262         TOKEN_STRING_INITIALIZER(struct cmd_neigh_add_result, action,
263                                  str_neigh_add_add);
264 const parse_token_string_t PROGMEM cmd_neigh_add_name =
265         TOKEN_STRING_INITIALIZER(struct cmd_neigh_add_result, name, NULL);
266 const parse_token_num_t PROGMEM cmd_neigh_add_addr =
267         TOKEN_NUM_INITIALIZER(struct cmd_neigh_add_result, addr, UINT64);
268
269 const char PROGMEM help_neigh_add[] = "add a neighbor";
270 const parse_inst_t PROGMEM cmd_neigh_add = {
271         .f = cmd_neigh_add_parsed,  /* function to call */
272         .data = NULL,      /* 2nd arg of func */
273         .help_str = help_neigh_add,
274         .tokens = {        /* token list, NULL terminated */
275                 (PGM_P)&cmd_neigh_add_cmd,
276                 (PGM_P)&cmd_neigh_add_action,
277                 (PGM_P)&cmd_neigh_add_name,
278                 (PGM_P)&cmd_neigh_add_addr,
279                 NULL,
280         },
281 };
282
283 /* ************* */
284
285 struct cmd_neigh_list_result {
286         fixed_string_t cmd;
287         fixed_string_t action;
288 };
289
290 static void cmd_neigh_list_parsed(void *parsed_result,
291                                 void *data)
292 {
293         struct xbee_neigh *neigh;
294
295         (void)parsed_result;
296         (void)data;
297         LIST_FOREACH(neigh, &xbee_dev->neigh_list, next) {
298                 printf_P(PSTR(" %s: 0x%.8"PRIx32"%.8"PRIx32"\r\n"),
299                          neigh->name,
300                          (uint32_t)(neigh->addr >> 32ULL),
301                          (uint32_t)(neigh->addr & 0xFFFFFFFF));
302         }
303 }
304
305 const char PROGMEM str_neigh_list_neigh[] = "neigh";
306 const parse_token_string_t PROGMEM cmd_neigh_list_cmd =
307         TOKEN_STRING_INITIALIZER(struct cmd_neigh_list_result, cmd,
308                                  str_neigh_list_neigh);
309 const char PROGMEM str_neigh_list_list[] = "list";
310 const parse_token_string_t PROGMEM cmd_neigh_list_action =
311         TOKEN_STRING_INITIALIZER(struct cmd_neigh_list_result, action,
312                                  str_neigh_list_list);
313
314 const char PROGMEM help_neigh_list[] = "list all knwon neighbors";
315 const parse_inst_t PROGMEM cmd_neigh_list = {
316         .f = cmd_neigh_list_parsed,  /* function to call */
317         .data = NULL,      /* 2nd arg of func */
318         .help_str = help_neigh_list,
319         .tokens = {        /* token list, NULL terminated */
320                 (PGM_P)&cmd_neigh_list_cmd,
321                 (PGM_P)&cmd_neigh_list_action,
322                 NULL,
323         },
324 };
325
326
327
328
329 /* ************* */
330
331 /* this structure is filled when cmd_read is parsed successfully */
332 struct cmd_read_result {
333         fixed_string_t read;
334         struct xbee_atcmd *cmd;
335 };
336
337 /* function called when cmd_read is parsed successfully */
338 static void cmd_read_parsed(void *parsed_result,
339                             void *data)
340 {
341         struct cmd_read_result *res = parsed_result;
342         struct xbee_atcmd copy;
343         char cmd[3];
344
345         (void)data;
346         memcpy_P(&copy, res->cmd, sizeof(copy));
347         memcpy_P(&cmd, copy.name, 2);
348         cmd[2] = '\0';
349         xbeeapp_send_atcmd(cmd, NULL, 0, 1, NULL, NULL);
350 }
351
352 const char PROGMEM str_read_read[] = "read";
353
354 const parse_token_string_t PROGMEM cmd_read_read =
355         TOKEN_STRING_INITIALIZER(struct cmd_read_result, read,
356                                  str_read_read);
357
358 const parse_token_atcmd_t PROGMEM cmd_read_atcmd =
359         TOKEN_ATCMD_INITIALIZER(struct cmd_read_result, cmd, &xbee_dev,
360                                 XBEE_ATCMD_F_READ, XBEE_ATCMD_F_READ);
361
362 const char PROGMEM help_read[] = "Read a register using an AT command";
363 const parse_inst_t PROGMEM cmd_read = {
364         .f = cmd_read_parsed,  /* function to call */
365         .data = NULL,      /* 2nd arg of func */
366         .help_str = help_read,
367         .tokens = {        /* token list, NULL terminated */
368                 (PGM_P)&cmd_read_read,
369                 (PGM_P)&cmd_read_atcmd,
370                 NULL,
371         },
372 };
373
374
375 /* ************* */
376
377 /* this structure is filled when cmd_write is parsed successfully */
378 struct cmd_write_result {
379         fixed_string_t write;
380         struct xbee_atcmd *cmd;
381         union {
382                 uint8_t u8;
383                 uint16_t u16;
384                 uint32_t u32;
385         };
386 };
387
388 /* function called when cmd_write is parsed successfully */
389 static void cmd_write_parsed(void *parsed_result, void *data)
390 {
391         struct cmd_write_result *res = parsed_result;
392         struct xbee_atcmd copy;
393         char cmd[3];
394         int len;
395         void *param;
396
397         (void)data;
398         memcpy_P(&copy, res->cmd, sizeof(copy));
399
400         if (copy.flags & XBEE_ATCMD_F_PARAM_NONE) {
401                 len = 0;
402                 param = NULL;
403         }
404         else if (copy.flags & XBEE_ATCMD_F_PARAM_U8) {
405                 len = sizeof(res->u8);
406                 param = &res->u8;
407         }
408         else if (copy.flags & XBEE_ATCMD_F_PARAM_U16) {
409                 len = sizeof(res->u16);
410                 res->u16 = htons(res->u16);
411                 param = &res->u16;
412         }
413         else if (copy.flags & XBEE_ATCMD_F_PARAM_U32) {
414                 len = sizeof(res->u32);
415                 res->u32 = htonl(res->u32);
416                 param = &res->u32;
417         }
418         else {
419                 printf_P(PSTR("Unknown argument type\r\n"));
420                 return;
421         }
422         memcpy_P(&cmd, copy.name, 2);
423         cmd[2] = '\0';
424         xbeeapp_send_atcmd(cmd, param, len, 1, NULL, NULL);
425 }
426
427 const char PROGMEM str_write_none[] = "write";
428
429 const parse_token_string_t PROGMEM cmd_write_write =
430         TOKEN_STRING_INITIALIZER(struct cmd_write_result, write,
431                                  str_write_none);
432
433 const parse_token_atcmd_t PROGMEM cmd_write_none_atcmd =
434         TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
435                                 &xbee_dev,
436                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_NONE,
437                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_NONE);
438
439 const char PROGMEM help_write_none[] = "Send an AT command (no argument)";
440
441 const parse_inst_t PROGMEM cmd_write_none = {
442         .f = cmd_write_parsed,  /* function to call */
443         .data = NULL,      /* 2nd arg of func */
444         .help_str = help_write_none,
445         .tokens = {        /* token list, NULL terminated */
446                 (PGM_P)&cmd_write_write,
447                 (PGM_P)&cmd_write_none_atcmd,
448                 NULL,
449         },
450 };
451
452 const parse_token_atcmd_t PROGMEM cmd_write_u8_atcmd =
453         TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
454                                 &xbee_dev,
455                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U8,
456                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U8);
457
458 const parse_token_num_t PROGMEM cmd_write_u8_u8 =
459         TOKEN_NUM_INITIALIZER(struct cmd_write_result, u8, UINT8);
460
461 const char PROGMEM help_write_u8[] = "Write a 8 bits register using an AT command";
462
463 const parse_inst_t PROGMEM cmd_write_u8 = {
464         .f = cmd_write_parsed,  /* function to call */
465         .data = NULL,      /* 2nd arg of func */
466         .help_str = help_write_u8,
467         .tokens = {        /* token list, NULL terminated */
468                 (PGM_P)&cmd_write_write,
469                 (PGM_P)&cmd_write_u8_atcmd,
470                 (PGM_P)&cmd_write_u8_u8,
471                 NULL,
472         },
473 };
474
475 const parse_token_atcmd_t PROGMEM cmd_write_u16_atcmd =
476         TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
477                                 &xbee_dev,
478                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U16,
479                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U16);
480
481 const parse_token_num_t PROGMEM cmd_write_u16_u16 =
482         TOKEN_NUM_INITIALIZER(struct cmd_write_result, u16, UINT16);
483
484 const char PROGMEM help_write_u16[] = "Write a 16 bits register using an AT command";
485
486 const parse_inst_t PROGMEM cmd_write_u16 = {
487         .f = cmd_write_parsed,  /* function to call */
488         .data = NULL,      /* 2nd arg of func */
489         .help_str = help_write_u16,
490         .tokens = {        /* token list, NULL terminated */
491                 (PGM_P)&cmd_write_write,
492                 (PGM_P)&cmd_write_u16_atcmd,
493                 (PGM_P)&cmd_write_u16_u16,
494                 NULL,
495         },
496 };
497
498 const parse_token_atcmd_t PROGMEM cmd_write_u32_atcmd =
499         TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
500                                 &xbee_dev,
501                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U32,
502                                 XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U32);
503
504 const parse_token_num_t PROGMEM cmd_write_u32_u32 =
505         TOKEN_NUM_INITIALIZER(struct cmd_write_result, u32, UINT32);
506
507 const char PROGMEM help_write_u32[] = "Write a 32 bits register using an AT command";
508
509 const parse_inst_t PROGMEM cmd_write_u32 = {
510         .f = cmd_write_parsed,  /* function to call */
511         .data = NULL,      /* 2nd arg of func */
512         .help_str = help_write_u32,
513         .tokens = {        /* token list, NULL terminated */
514                 (PGM_P)&cmd_write_write,
515                 (PGM_P)&cmd_write_u32_atcmd,
516                 (PGM_P)&cmd_write_u32_u32,
517                 NULL,
518         },
519 };
520
521
522 /* ************* */
523
524 /* this structure is filled when cmd_sendmsg is parsed successfully */
525 struct cmd_sendmsg_result {
526         fixed_string_t sendmsg;
527         uint64_t addr;
528         fixed_string_t data;
529 };
530
531 /* function called when cmd_sendmsg is parsed successfully */
532 static void cmd_sendmsg_parsed(void *parsed_result, void *data)
533 {
534         struct cmd_sendmsg_result *res = parsed_result;
535
536         (void)data;
537         xbeeapp_send_msg(res->addr, res->data, strlen(res->data), 1);
538 }
539
540 const char PROGMEM str_sendmsg[] = "sendmsg";
541
542 const parse_token_string_t PROGMEM cmd_sendmsg_sendmsg =
543         TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_result, sendmsg,
544                                  str_sendmsg);
545
546 const parse_token_num_t PROGMEM cmd_sendmsg_addr =
547         TOKEN_NUM_INITIALIZER(struct cmd_sendmsg_result, addr, UINT64);
548
549 const parse_token_string_t PROGMEM cmd_sendmsg_data =
550         TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_result, data, NULL);
551
552 const char PROGMEM help_sendmsg[] = "Send data to a node using its address";
553
554 const parse_inst_t PROGMEM cmd_sendmsg = {
555         .f = cmd_sendmsg_parsed,  /* function to call */
556         .data = NULL,      /* 2nd arg of func */
557         .help_str = help_sendmsg,
558         .tokens = {        /* token list, NULL terminated */
559                 (PGM_P)&cmd_sendmsg_sendmsg,
560                 (PGM_P)&cmd_sendmsg_addr,
561                 (PGM_P)&cmd_sendmsg_data,
562                 NULL,
563         },
564 };
565
566 /* ************* */
567
568 /* this structure is filled when cmd_send_hello is parsed successfully */
569 struct cmd_send_hello_result {
570         fixed_string_t send_hello;
571         uint64_t addr;
572         struct xbee_neigh *neigh;
573         uint16_t period;
574         uint16_t count;
575         fixed_string_t data;
576 };
577
578 /* function called when cmd_send_hello is parsed successfully */
579 static void cmd_send_hello_parsed(void *parsed_result, void *use_neigh)
580 {
581         struct cmd_send_hello_result *res = parsed_result;
582         uint16_t now, next, diff;
583         uint8_t flags;
584         uint64_t addr;
585
586         if (use_neigh)
587                 addr = res->neigh->addr;
588         else
589                 addr = res->addr;
590
591         IRQ_LOCK(flags);
592         now = global_ms;
593         IRQ_UNLOCK(flags);
594
595         next = now;
596
597         while (!cmdline_keypressed() && res->count != 0) {
598                 IRQ_LOCK(flags);
599                 now = global_ms;
600                 IRQ_UNLOCK(flags);
601
602                 diff = now - next;
603                 if (diff < res->period)
604                         continue;
605
606                 rc_proto_send_hello(addr, res->data, strlen(res->data));
607                 next += res->period;
608                 res->count--;
609         }
610 }
611
612 const char PROGMEM str_send_hello[] = "send_hello";
613
614 const parse_token_string_t PROGMEM cmd_send_hello_send_hello =
615         TOKEN_STRING_INITIALIZER(struct cmd_send_hello_result, send_hello,
616                                  str_send_hello);
617
618 const parse_token_num_t PROGMEM cmd_send_hello_addr =
619         TOKEN_NUM_INITIALIZER(struct cmd_send_hello_result, addr, UINT64);
620
621 const parse_token_num_t PROGMEM cmd_send_hello_period =
622         TOKEN_NUM_INITIALIZER(struct cmd_send_hello_result, period, UINT16);
623
624 const parse_token_num_t PROGMEM cmd_send_hello_count =
625         TOKEN_NUM_INITIALIZER(struct cmd_send_hello_result, count, UINT16);
626
627 const parse_token_string_t PROGMEM cmd_send_hello_data =
628         TOKEN_STRING_INITIALIZER(struct cmd_send_hello_result, data, NULL);
629
630 const char PROGMEM help_send_hello[] =
631         "Send hello msg to a node: addr, period_ms, count, str";
632
633 const parse_inst_t PROGMEM cmd_send_hello = {
634         .f = cmd_send_hello_parsed,  /* function to call */
635         .data = NULL,      /* 2nd arg of func */
636         .help_str = help_send_hello,
637         .tokens = {        /* token list, NULL terminated */
638                 (PGM_P)&cmd_send_hello_send_hello,
639                 (PGM_P)&cmd_send_hello_addr,
640                 (PGM_P)&cmd_send_hello_period,
641                 (PGM_P)&cmd_send_hello_count,
642                 (PGM_P)&cmd_send_hello_data,
643                 NULL,
644         },
645 };
646
647 const parse_token_neighbor_t PROGMEM cmd_send_hello_neigh =
648         TOKEN_NEIGHBOR_INITIALIZER(struct cmd_send_hello_result, neigh,
649                                    &xbee_dev);
650
651 const parse_inst_t PROGMEM cmd_send_hello_name = {
652         .f = cmd_send_hello_parsed,  /* function to call */
653         .data = (void *)1,      /* 2nd arg of func */
654         .help_str = help_send_hello,
655         .tokens = {        /* token list, NULL terminated */
656                 (PGM_P)&cmd_send_hello_send_hello,
657                 (PGM_P)&cmd_send_hello_neigh,
658                 (PGM_P)&cmd_send_hello_period,
659                 (PGM_P)&cmd_send_hello_count,
660                 (PGM_P)&cmd_send_hello_data,
661                 NULL,
662         },
663 };
664
665 /* ************* */
666
667 /* this structure is filled when cmd_sendmsg_name is parsed successfully */
668 struct cmd_sendmsg_name_result {
669         fixed_string_t sendmsg_name;
670         struct xbee_neigh *neigh;
671         fixed_string_t data;
672 };
673
674 /* function called when cmd_sendmsg_name is parsed successfully */
675 static void cmd_sendmsg_name_parsed(void *parsed_result, void *data)
676 {
677         struct cmd_sendmsg_name_result *res = parsed_result;
678
679         (void)data;
680         xbeeapp_send_msg(res->neigh->addr, res->data, strlen(res->data), 1);
681 }
682
683 const parse_token_string_t PROGMEM cmd_sendmsg_name_sendmsg_name =
684         TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_name_result, sendmsg_name,
685                                  str_sendmsg);
686
687 const parse_token_neighbor_t PROGMEM cmd_sendmsg_name_neigh =
688         TOKEN_NEIGHBOR_INITIALIZER(struct cmd_sendmsg_name_result, neigh,
689                                    &xbee_dev);
690
691 const parse_token_string_t PROGMEM cmd_sendmsg_name_data =
692         TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_name_result, data, NULL);
693
694 const char PROGMEM help_sendmsg_name[] = "Send data to a node using its name";
695
696 const parse_inst_t PROGMEM cmd_sendmsg_name = {
697         .f = cmd_sendmsg_name_parsed,  /* function to call */
698         .data = NULL,      /* 2nd arg of func */
699         .help_str = help_sendmsg_name,
700         .tokens = {        /* token list, NULL terminated */
701                 (PGM_P)&cmd_sendmsg_name_sendmsg_name,
702                 (PGM_P)&cmd_sendmsg_name_neigh,
703                 (PGM_P)&cmd_sendmsg_name_data,
704                 NULL,
705         },
706 };
707
708
709 /* ************* */
710
711 /* this structure is filled when cmd_range is parsed successfully */
712 struct cmd_range_result {
713         fixed_string_t range;
714         fixed_string_t action;
715 };
716
717 /* function called when cmd_range is parsed successfully */
718 static void cmd_range_parsed(void *parsed_result, void *data)
719 {
720         struct cmd_range_result *res = parsed_result;
721
722         (void)data;
723         if (!strcmp_P(res->action, PSTR("show"))) {
724                 printf_P(PSTR("range infos:\r\n"));
725                 printf_P(PSTR("  range period %d\r\n"), range_period_ms);
726                 printf_P(PSTR("  range count %d\r\n"), range_count);
727                 printf_P(PSTR("  range powermask 0x%x\r\n"), range_powermask);
728                 printf_P(PSTR("  range dstaddr 0x%.8"PRIx32"%.8"PRIx32"\r\n"),
729                          (uint32_t)(range_dstaddr >> 32ULL),
730                          (uint32_t)(range_dstaddr & 0xFFFFFFFF));
731
732                 if (range_running)
733                         printf_P(PSTR("  range test is running\r\n"));
734                 else
735                         printf_P(PSTR("  range test is not running\r\n"));
736         }
737         else if (!strcmp(res->action, "start")) {
738                 if (range_running) {
739                         printf_P(PSTR("already running\r\n"));
740                         return;
741                 }
742                 range_cur_count = range_count;
743                 callout_init(&range_event, range_cb, NULL, 0);
744                 callout_schedule(&cm, &range_event, 0); /* immediate */
745                 range_running = 1;
746         }
747         else if (!strcmp(res->action, "end")) {
748                 if (range_running == 0) {
749                         printf_P(PSTR("not running\r\n"));
750                         return;
751                 }
752                 range_running = 0;
753                 callout_stop(&cm, &range_event);
754         }
755 }
756
757 const char PROGMEM str_range[] = "range";
758 const char PROGMEM str_range_tokens[] = "show#start#end";
759
760 const parse_token_string_t PROGMEM cmd_range_range =
761         TOKEN_STRING_INITIALIZER(struct cmd_range_result, range,
762                                  str_range);
763 const parse_token_string_t PROGMEM cmd_range_action =
764         TOKEN_STRING_INITIALIZER(struct cmd_range_result, action,
765                                  str_range_tokens);
766
767 const char PROGMEM help_range[] = "start/stop/show current rangeing";
768
769 const parse_inst_t PROGMEM cmd_range = {
770         .f = cmd_range_parsed,  /* function to call */
771         .data = NULL,      /* 2nd arg of func */
772         .help_str = help_range,
773         .tokens = {        /* token list, NULL terminated */
774                 (PGM_P)&cmd_range_range,
775                 (PGM_P)&cmd_range_action,
776                 NULL,
777         },
778 };
779
780 /* ************* */
781
782 /* this structure is filled when cmd_range_period is parsed successfully */
783 struct cmd_range_period_result {
784         fixed_string_t range;
785         fixed_string_t action;
786         uint32_t period;
787 };
788
789 /* function called when cmd_range_period is parsed successfully */
790 static void cmd_range_period_parsed(void *parsed_result, void *data)
791 {
792         struct cmd_range_period_result *res = parsed_result;
793
794         (void)data;
795         if (res->period < 10) {
796                 printf_P(PSTR("error, minimum period is 10 ms\r\n"));
797                 return;
798         }
799
800         range_period_ms = res->period;
801 }
802
803 const char PROGMEM str_period[] = "period";
804
805 const parse_token_string_t PROGMEM cmd_range_period_range_period =
806         TOKEN_STRING_INITIALIZER(struct cmd_range_period_result, range,
807                                  str_range);
808 const parse_token_string_t PROGMEM cmd_range_period_action =
809         TOKEN_STRING_INITIALIZER(struct cmd_range_period_result, action,
810                                  str_period);
811 const parse_token_num_t PROGMEM cmd_range_period_period =
812         TOKEN_NUM_INITIALIZER(struct cmd_range_period_result, period, UINT32);
813
814 const char PROGMEM help_range_period[] = "set range test period";
815
816 const parse_inst_t PROGMEM cmd_range_period = {
817         .f = cmd_range_period_parsed,  /* function to call */
818         .data = NULL,      /* 2nd arg of func */
819         .help_str = help_range_period,
820         .tokens = {        /* token list, NULL terminated */
821                 (PGM_P)&cmd_range_period_range_period,
822                 (PGM_P)&cmd_range_period_action,
823                 (PGM_P)&cmd_range_period_period,
824                 NULL,
825         },
826 };
827
828 /* ************* */
829
830 /* this structure is filled when cmd_range_count is parsed successfully */
831 struct cmd_range_count_result {
832         fixed_string_t range;
833         fixed_string_t action;
834         uint32_t count;
835 };
836
837 /* function called when cmd_range_count is parsed successfully */
838 static void cmd_range_count_parsed(void *parsed_result, void *data)
839 {
840         struct cmd_range_count_result *res = parsed_result;
841
842         (void)data;
843         range_count = res->count;
844 }
845
846 const char PROGMEM str_count[] = "count";
847
848 const parse_token_string_t PROGMEM cmd_range_count_range_count =
849         TOKEN_STRING_INITIALIZER(struct cmd_range_count_result, range,
850                                  str_range);
851 const parse_token_string_t PROGMEM cmd_range_count_action =
852         TOKEN_STRING_INITIALIZER(struct cmd_range_count_result, action,
853                                  str_count);
854 const parse_token_num_t PROGMEM cmd_range_count_count =
855         TOKEN_NUM_INITIALIZER(struct cmd_range_count_result, count, UINT32);
856
857
858 const char PROGMEM help_range_count[] = "set range test count";
859
860 const parse_inst_t PROGMEM cmd_range_count = {
861         .f = cmd_range_count_parsed,  /* function to call */
862         .data = NULL,      /* 2nd arg of func */
863         .help_str = help_range_count,
864         .tokens = {        /* token list, NULL terminated */
865                 (PGM_P)&cmd_range_count_range_count,
866                 (PGM_P)&cmd_range_count_action,
867                 (PGM_P)&cmd_range_count_count,
868                 NULL,
869         },
870 };
871
872 /* ************* */
873
874 /* this structure is filled when cmd_range_powermask is parsed successfully */
875 struct cmd_range_powermask_result {
876         fixed_string_t range;
877         fixed_string_t action;
878         uint8_t powermask;
879 };
880
881 /* function called when cmd_range_powermask is parsed successfully */
882 static void cmd_range_powermask_parsed(void *parsed_result, void *data)
883 {
884         struct cmd_range_powermask_result *res = parsed_result;
885
886         (void)data;
887         range_powermask = res->powermask;
888 }
889
890 const char PROGMEM str_powermask[] = "powermask";
891
892 const parse_token_string_t PROGMEM cmd_range_powermask_range_powermask =
893         TOKEN_STRING_INITIALIZER(struct cmd_range_powermask_result, range,
894                                  str_range);
895 const parse_token_string_t PROGMEM cmd_range_powermask_action =
896         TOKEN_STRING_INITIALIZER(struct cmd_range_powermask_result, action,
897                                  str_powermask);
898 const parse_token_num_t PROGMEM cmd_range_powermask_powermask =
899         TOKEN_NUM_INITIALIZER(struct cmd_range_powermask_result, powermask,
900                               UINT8);
901
902
903 const char PROGMEM help_range_powermask[] = "set range test powermask";
904
905 const parse_inst_t PROGMEM cmd_range_powermask = {
906         .f = cmd_range_powermask_parsed,  /* function to call */
907         .data = NULL,      /* 2nd arg of func */
908         .help_str = help_range_powermask,
909         .tokens = {        /* token list, NULL terminated */
910                 (PGM_P)&cmd_range_powermask_range_powermask,
911                 (PGM_P)&cmd_range_powermask_action,
912                 (PGM_P)&cmd_range_powermask_powermask,
913                 NULL,
914         },
915 };
916
917 /* ************* */
918
919 /* this structure is filled when cmd_range_dstaddr is parsed successfully */
920 struct cmd_range_dstaddr_result {
921         fixed_string_t range;
922         fixed_string_t action;
923         uint64_t dstaddr;
924 };
925
926 /* function called when cmd_range_dstaddr is parsed successfully */
927 static void cmd_range_dstaddr_parsed(void *parsed_result, void *data)
928 {
929         struct cmd_range_dstaddr_result *res = parsed_result;
930
931         (void)data;
932         range_dstaddr = res->dstaddr;
933 }
934
935 const char PROGMEM str_dstaddr[] = "dstaddr";
936
937 const parse_token_string_t PROGMEM cmd_range_dstaddr_range_dstaddr =
938         TOKEN_STRING_INITIALIZER(struct cmd_range_dstaddr_result, range,
939                                  str_range);
940 const parse_token_string_t PROGMEM cmd_range_dstaddr_action =
941         TOKEN_STRING_INITIALIZER(struct cmd_range_dstaddr_result, action,
942                                  str_dstaddr);
943 const parse_token_num_t PROGMEM cmd_range_dstaddr_dstaddr =
944         TOKEN_NUM_INITIALIZER(struct cmd_range_dstaddr_result, dstaddr, UINT64);
945
946
947 const char PROGMEM help_range_dstaddr[] = "set register rangeing dstaddr";
948
949 const parse_inst_t PROGMEM cmd_range_dstaddr = {
950         .f = cmd_range_dstaddr_parsed,  /* function to call */
951         .data = NULL,      /* 2nd arg of func */
952         .help_str = help_range_dstaddr,
953         .tokens = {        /* token list, NULL terminated */
954                 (PGM_P)&cmd_range_dstaddr_range_dstaddr,
955                 (PGM_P)&cmd_range_dstaddr_action,
956                 (PGM_P)&cmd_range_dstaddr_dstaddr,
957                 NULL,
958         },
959 };
960
961
962 /* ************* */
963
964 /* this structure is filled when cmd_monitor is parsed successfully */
965 struct cmd_monitor_result {
966         fixed_string_t monitor;
967         fixed_string_t action;
968 };
969
970 /* function called when cmd_monitor is parsed successfully */
971 static void cmd_monitor_parsed(void *parsed_result, void *data)
972 {
973         struct cmd_monitor_result *res = parsed_result;
974         struct monitor_reg *m;
975
976         (void)data;
977         if (!strcmp_P(res->action, PSTR("show"))) {
978                 printf_P(PSTR("monitor period is %d ms, %d regs in list\r\n"),
979                        monitor_period_ms, monitor_count);
980                 LIST_FOREACH(m, &xbee_monitor_list, next)
981                         printf_P(PSTR(" %S\r\n"), m->desc);
982         }
983         else if (!strcmp_P(res->action, PSTR("start"))) {
984                 if (monitor_running) {
985                         printf_P(PSTR("already running\r\n"));
986                         return;
987                 }
988                 if (monitor_count == 0) {
989                         printf_P(PSTR("no regs to be monitored\r\n"));
990                         return;
991                 }
992                 callout_init(&monitor_event, monitor_cb, NULL, 0);
993                 callout_schedule(&cm, &monitor_event, 0); /* immediate */
994                 monitor_running = 1;
995                 monitor_current = LIST_FIRST(&xbee_monitor_list);
996                 printf_P(PSTR("monitor cb: %S %s\r\n"),
997                          monitor_current->desc,
998                          monitor_current->atcmd);
999
1000         }
1001         else if (!strcmp_P(res->action, PSTR("end"))) {
1002                 if (monitor_running == 0) {
1003                         printf_P(PSTR("not running\r\n"));
1004                         return;
1005                 }
1006                 monitor_running = 0;
1007                 callout_stop(&cm, &monitor_event);
1008         }
1009 }
1010
1011 const char PROGMEM str_monitor[] = "monitor";
1012 const char PROGMEM str_monitor_tokens[] = "show#start#end";
1013
1014 const parse_token_string_t PROGMEM cmd_monitor_monitor =
1015         TOKEN_STRING_INITIALIZER(struct cmd_monitor_result, monitor,
1016                                  str_monitor);
1017 const parse_token_string_t PROGMEM cmd_monitor_action =
1018         TOKEN_STRING_INITIALIZER(struct cmd_monitor_result, action,
1019                                  str_monitor_tokens);
1020
1021 const char PROGMEM help_monitor[] = "start/stop/show current monitoring";
1022
1023 const parse_inst_t PROGMEM cmd_monitor = {
1024         .f = cmd_monitor_parsed,  /* function to call */
1025         .data = NULL,      /* 2nd arg of func */
1026         .help_str = help_monitor,
1027         .tokens = {        /* token list, NULL terminated */
1028                 (PGM_P)&cmd_monitor_monitor,
1029                 (PGM_P)&cmd_monitor_action,
1030                 NULL,
1031         },
1032 };
1033
1034 /* ************* */
1035
1036 /* this structure is filled when cmd_monitor_add is parsed successfully */
1037 struct cmd_monitor_add_result {
1038         fixed_string_t monitor;
1039         fixed_string_t action;
1040         struct xbee_atcmd *cmd;
1041 };
1042
1043 /* function called when cmd_monitor_add is parsed successfully */
1044 static void cmd_monitor_add_parsed(void *parsed_result, void *data)
1045 {
1046         struct cmd_monitor_add_result *res = parsed_result;
1047         struct monitor_reg *m;
1048         struct xbee_atcmd copy;
1049
1050         (void)data;
1051         memcpy_P(&copy, res->cmd, sizeof(copy));
1052         LIST_FOREACH(m, &xbee_monitor_list, next) {
1053                 if (!strcmp_P(m->atcmd, copy.name))
1054                         break;
1055         }
1056
1057         if (m != NULL) {
1058                 printf_P(PSTR("already exist\r\n"));
1059                 return;
1060         }
1061
1062         m = malloc(sizeof(*m));
1063         if (m == NULL) {
1064                 printf_P(PSTR("no mem\r\n"));
1065                 return;
1066         }
1067         m->desc = copy.desc;
1068         strcpy_P(m->atcmd, copy.name);
1069         LIST_INSERT_HEAD(&xbee_monitor_list, m, next);
1070         monitor_count ++;
1071 }
1072
1073 const char PROGMEM str_monitor_add[] = "add";
1074
1075 const parse_token_string_t PROGMEM cmd_monitor_add_monitor_add =
1076         TOKEN_STRING_INITIALIZER(struct cmd_monitor_add_result, monitor,
1077                                  str_monitor);
1078 const parse_token_string_t PROGMEM cmd_monitor_add_action =
1079         TOKEN_STRING_INITIALIZER(struct cmd_monitor_add_result, action,
1080                                  str_monitor_add);
1081 const parse_token_atcmd_t PROGMEM cmd_monitor_add_atcmd =
1082         TOKEN_ATCMD_INITIALIZER(struct cmd_monitor_add_result, cmd, &xbee_dev,
1083                                 XBEE_ATCMD_F_READ, XBEE_ATCMD_F_READ);
1084
1085
1086 const char PROGMEM help_monitor_add[] = "add a register in monitor list";
1087
1088 const parse_inst_t PROGMEM cmd_monitor_add = {
1089         .f = cmd_monitor_add_parsed,  /* function to call */
1090         .data = NULL,      /* 2nd arg of func */
1091         .help_str = help_monitor_add,
1092         .tokens = {        /* token list, NULL terminated */
1093                 (PGM_P)&cmd_monitor_add_monitor_add,
1094                 (PGM_P)&cmd_monitor_add_action,
1095                 (PGM_P)&cmd_monitor_add_atcmd,
1096                 NULL,
1097         },
1098 };
1099
1100 /* ************* */
1101
1102 /* this structure is filled when cmd_monitor_period is parsed successfully */
1103 struct cmd_monitor_period_result {
1104         fixed_string_t monitor;
1105         fixed_string_t action;
1106         uint32_t period;
1107 };
1108
1109 /* function called when cmd_monitor_period is parsed successfully */
1110 static void cmd_monitor_period_parsed(void *parsed_result, void *data)
1111 {
1112         struct cmd_monitor_period_result *res = parsed_result;
1113
1114         (void)data;
1115         if (res->period < 100) {
1116                 printf_P(PSTR("error, minimum period is 100 ms\r\n"));
1117                 return;
1118         }
1119
1120         monitor_period_ms = res->period;
1121 }
1122
1123 const char PROGMEM str_monitor_period[] = "period";
1124
1125 const parse_token_string_t PROGMEM cmd_monitor_period_monitor_period =
1126         TOKEN_STRING_INITIALIZER(struct cmd_monitor_period_result, monitor,
1127                                  str_monitor);
1128 const parse_token_string_t PROGMEM cmd_monitor_period_action =
1129         TOKEN_STRING_INITIALIZER(struct cmd_monitor_period_result, action,
1130                                  str_monitor_period);
1131 const parse_token_num_t PROGMEM cmd_monitor_period_period =
1132         TOKEN_NUM_INITIALIZER(struct cmd_monitor_period_result, period, UINT32);
1133
1134
1135 const char PROGMEM help_monitor_period[] = "set register monitoring period";
1136
1137 const parse_inst_t PROGMEM cmd_monitor_period = {
1138         .f = cmd_monitor_period_parsed,  /* function to call */
1139         .data = NULL,      /* 2nd arg of func */
1140         .help_str = help_monitor_period,
1141         .tokens = {        /* token list, NULL terminated */
1142                 (PGM_P)&cmd_monitor_period_monitor_period,
1143                 (PGM_P)&cmd_monitor_period_action,
1144                 (PGM_P)&cmd_monitor_period_period,
1145                 NULL,
1146         },
1147 };
1148
1149 /* ************* */
1150
1151 /* this structure is filled when cmd_monitor_del is parsed successfully */
1152 struct cmd_monitor_del_result {
1153         fixed_string_t monitor;
1154         fixed_string_t action;
1155         struct monitor_reg *m;
1156 };
1157
1158 /* function called when cmd_monitor_del is parsed successfully */
1159 static void cmd_monitor_del_parsed(void *parsed_result, void *data)
1160 {
1161         struct cmd_monitor_del_result *res = parsed_result;
1162
1163         (void)data;
1164         monitor_current = LIST_NEXT(res->m, next);
1165         LIST_REMOVE(res->m, next);
1166         free(res->m);
1167         monitor_count --;
1168         if (monitor_count == 0) {
1169                 printf_P(PSTR("Disable monitoring, no more event\r\n"));
1170                 callout_stop(&cm, &monitor_event);
1171                 monitor_running = 0;
1172                 return;
1173         }
1174 }
1175
1176 const char PROGMEM str_monitor_del[] = "del";
1177
1178 const parse_token_string_t PROGMEM cmd_monitor_del_monitor_del =
1179         TOKEN_STRING_INITIALIZER(struct cmd_monitor_del_result, monitor,
1180                                  str_monitor);
1181 const parse_token_string_t PROGMEM cmd_monitor_del_action =
1182         TOKEN_STRING_INITIALIZER(struct cmd_monitor_del_result, action,
1183                                  str_monitor_del);
1184 const parse_token_monitor_t PROGMEM cmd_monitor_del_atcmd =
1185         TOKEN_MONITOR_INITIALIZER(struct cmd_monitor_del_result, m);
1186
1187
1188 const char PROGMEM help_monitor_del[] = "del a register in monitor list";
1189
1190 const parse_inst_t PROGMEM cmd_monitor_del = {
1191         .f = cmd_monitor_del_parsed,  /* function to call */
1192         .data = NULL,      /* 2nd arg of func */
1193         .help_str = help_monitor_del,
1194         .tokens = {        /* token list, NULL terminated */
1195                 (PGM_P)&cmd_monitor_del_monitor_del,
1196                 (PGM_P)&cmd_monitor_del_action,
1197                 (PGM_P)&cmd_monitor_del_atcmd,
1198                 NULL,
1199         },
1200 };
1201
1202
1203 /* ************* */
1204
1205 /* this structure is filled when cmd_ping is parsed successfully */
1206 struct cmd_ping_result {
1207         fixed_string_t ping;
1208 };
1209
1210 /* function called when cmd_ping is parsed successfully */
1211 static void cmd_ping_parsed(void *parsed_result, void *data)
1212 {
1213         (void)parsed_result;
1214         (void)data;
1215         xbeeapp_send_atcmd("VL", NULL, 0, 1, NULL, NULL);
1216 }
1217
1218 const char PROGMEM str_ping[] = "ping";
1219
1220 const parse_token_string_t PROGMEM cmd_ping_ping =
1221         TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping,
1222                                  str_ping);
1223
1224 const char PROGMEM help_ping[] = "Send a ping to the xbee device";
1225
1226 const parse_inst_t PROGMEM cmd_ping = {
1227         .f = cmd_ping_parsed,  /* function to call */
1228         .data = NULL,      /* 2nd arg of func */
1229         .help_str = help_ping,
1230         .tokens = {        /* token list, NULL terminated */
1231                 (PGM_P)&cmd_ping_ping,
1232                 NULL,
1233         },
1234 };
1235
1236 /* ************* */
1237
1238 /* this structure is filled when cmd_raw is parsed successfully */
1239 struct cmd_raw_result {
1240         fixed_string_t raw;
1241 };
1242
1243 /* function called when cmd_raw is parsed successfully */
1244 static void cmd_raw_parsed(void *parsed_result, void *data)
1245 {
1246         (void)parsed_result;
1247         (void)data;
1248         printf_P(PSTR("switched to raw mode, CTRL-D to exit\r\n"));
1249         rdline_stop(&xbeeboard.rdl); /* don't display prompt when return */
1250         xbee_raw = 1;
1251 }
1252
1253 const char PROGMEM str_raw[] = "raw";
1254
1255 const parse_token_string_t PROGMEM cmd_raw_raw =
1256         TOKEN_STRING_INITIALIZER(struct cmd_raw_result, raw,
1257                                  str_raw);
1258
1259 const char PROGMEM help_raw[] = "Switch to raw mode";
1260
1261 const parse_inst_t PROGMEM cmd_raw = {
1262         .f = cmd_raw_parsed,  /* function to call */
1263         .data = NULL,      /* 2nd arg of func */
1264         .help_str = help_raw,
1265         .tokens = {        /* token list, NULL terminated */
1266                 (PGM_P)&cmd_raw_raw,
1267                 NULL,
1268         },
1269 };
1270
1271 /* ************* */
1272
1273 /* this structure is filled when cmd_dump is parsed successfully */
1274 struct cmd_dump_result {
1275         fixed_string_t dump;
1276         fixed_string_t onoff;
1277 };
1278
1279 /* function called when cmd_dump is parsed successfully */
1280 static void cmd_dump_parsed(void *parsed_result, void *data)
1281 {
1282         struct cmd_dump_result *res = parsed_result;
1283
1284         (void)data;
1285         if (!strcmp(res->onoff, "on"))
1286                 xbee_hexdump = 1;
1287         else
1288                 xbee_hexdump = 0;
1289 }
1290
1291 const char PROGMEM str_dump[] = "dump";
1292 const char PROGMEM str_dump_onoff[] = "on#off";
1293
1294 const parse_token_string_t PROGMEM cmd_dump_dump =
1295         TOKEN_STRING_INITIALIZER(struct cmd_dump_result, dump,
1296                                  str_dump);
1297
1298 const parse_token_string_t PROGMEM cmd_dump_onoff =
1299         TOKEN_STRING_INITIALIZER(struct cmd_dump_result, onoff,
1300                                  str_dump_onoff);
1301
1302 const char PROGMEM help_dump[] = "enable/disable hexdump of received packets";
1303
1304 const parse_inst_t PROGMEM cmd_dump = {
1305         .f = cmd_dump_parsed,  /* function to call */
1306         .data = NULL,      /* 2nd arg of func */
1307         .help_str = help_dump,
1308         .tokens = {        /* token list, NULL terminated */
1309                 (PGM_P)&cmd_dump_dump,
1310                 (PGM_P)&cmd_dump_onoff,
1311                 NULL,
1312         },
1313 };
1314
1315 /* ************* */
1316
1317 /* this structure is filled when cmd_debug is parsed successfully */
1318 struct cmd_debug_result {
1319         fixed_string_t debug;
1320         fixed_string_t onoff;
1321 };
1322
1323 /* function called when cmd_debug is parsed successfully */
1324 static void cmd_debug_parsed(void *parsed_result, void *data)
1325 {
1326         struct cmd_debug_result *res = parsed_result;
1327
1328         (void)data;
1329         if (!strcmp(res->onoff, "on"))
1330                 xbee_debug = 1;
1331         else
1332                 xbee_debug = 0;
1333 }
1334
1335 const char PROGMEM str_debug[] = "debug";
1336 const char PROGMEM str_debug_onoff[] = "on#off";
1337
1338 const parse_token_string_t PROGMEM cmd_debug_debug =
1339         TOKEN_STRING_INITIALIZER(struct cmd_debug_result, debug,
1340                                  str_debug);
1341
1342 const parse_token_string_t PROGMEM cmd_debug_onoff =
1343         TOKEN_STRING_INITIALIZER(struct cmd_debug_result, onoff,
1344                                  str_debug_onoff);
1345
1346 const char PROGMEM help_debug[] = "enable/disable additionnal debug";
1347
1348 const parse_inst_t PROGMEM cmd_debug = {
1349         .f = cmd_debug_parsed,  /* function to call */
1350         .data = NULL,      /* 2nd arg of func */
1351         .help_str = help_debug,
1352         .tokens = {        /* token list, NULL terminated */
1353                 (PGM_P)&cmd_debug_debug,
1354                 (PGM_P)&cmd_debug_onoff,
1355                 NULL,
1356         },
1357 };
1358
1359 /**********************************************************/
1360
1361 /* this structure is filled when cmd_baudrate is parsed successfully */
1362 struct cmd_baudrate_result {
1363         fixed_string_t arg0;
1364         uint32_t arg1;
1365 };
1366
1367 /* function called when cmd_baudrate is parsed successfully */
1368 static void cmd_baudrate_parsed(void * parsed_result, __attribute__((unused)) void *data)
1369 {
1370         struct cmd_baudrate_result *res = parsed_result;
1371         struct uart_config c;
1372
1373         uart_getconf(XBEE_UART, &c);
1374         c.baudrate = res->arg1;
1375         uart_setconf(XBEE_UART, &c);
1376 }
1377
1378 const char PROGMEM str_baudrate_arg0[] = "baudrate";
1379 const parse_token_string_t PROGMEM cmd_baudrate_arg0 =
1380         TOKEN_STRING_INITIALIZER(struct cmd_baudrate_result, arg0,
1381                                  str_baudrate_arg0);
1382 const parse_token_num_t PROGMEM cmd_baudrate_arg1 =
1383         TOKEN_NUM_INITIALIZER(struct cmd_baudrate_result, arg1,
1384                               UINT32);
1385
1386 const char PROGMEM help_baudrate[] = "Change xbee baudrate";
1387 const parse_inst_t PROGMEM cmd_baudrate = {
1388         .f = cmd_baudrate_parsed,  /* function to call */
1389         .data = NULL,      /* 2nd arg of func */
1390         .help_str = help_baudrate,
1391         .tokens = {        /* token list, NULL terminated */
1392                 (PGM_P)&cmd_baudrate_arg0,
1393                 (PGM_P)&cmd_baudrate_arg1,
1394                 NULL,
1395         },
1396 };
1397
1398
1399 /**********************************************************/
1400
1401 /* this structure is filled when cmd_beep is parsed successfully */
1402 struct cmd_beep_result {
1403         fixed_string_t beep;
1404 };
1405
1406 /* function called when cmd_beep is parsed successfully */
1407 static void cmd_beep_parsed(void *parsed_result, void *data)
1408 {
1409         (void)parsed_result;
1410         (void)data;
1411
1412         beep(0, 3, 3);
1413         beep(1, 3, 3);
1414         beep(2, 3, 3);
1415         beep(0, 1, 1);
1416         beep(1, 1, 1);
1417         beep(2, 1, 1);
1418 }
1419
1420 const char PROGMEM str_beep[] = "beep";
1421 const parse_token_string_t PROGMEM cmd_beep_beep =
1422         TOKEN_STRING_INITIALIZER(struct cmd_beep_result, beep,
1423                                  str_beep);
1424
1425 const char PROGMEM help_beep[] = "Send a beep";
1426
1427 const parse_inst_t PROGMEM cmd_beep = {
1428         .f = cmd_beep_parsed,  /* function to call */
1429         .data = NULL,      /* 2nd arg of func */
1430         .help_str = help_beep,
1431         .tokens = {        /* token list, NULL terminated */
1432                 (PGM_P)&cmd_beep_beep,
1433                 NULL,
1434         },
1435 };
1436
1437 /**********************************************************/
1438
1439 /* this structure is filled when cmd_servo is parsed successfully */
1440 struct cmd_servo_result {
1441         fixed_string_t arg0;
1442         fixed_string_t arg1;
1443         uint16_t num;
1444         uint16_t val;
1445 };
1446
1447 /* function called when cmd_servo is parsed successfully */
1448 static void cmd_servo_parsed(void * parsed_result, void *data)
1449 {
1450         struct cmd_servo_result *res = parsed_result;
1451
1452         (void)data;
1453
1454         if (!strcmp_P(res->arg1, PSTR("set"))) {
1455                 if (res->num >= N_SERVO) {
1456                         printf_P(PSTR("bad servo num\n"));
1457                         return;
1458                 }
1459                 if (res->val >= 1024) {
1460                         printf_P(PSTR("bad servo val\n"));
1461                         return;
1462                 }
1463                 spi_servo_set(res->num, res->val);
1464         }
1465         else if (!strcmp_P(res->arg1, PSTR("bypass"))) {
1466                 spi_servo_set_bypass(!!res->val);
1467         }
1468         else if (!strcmp_P(res->arg1, PSTR("ppm"))) {
1469                 spi_servo_set_ppm(!!res->val);
1470         }
1471         else if (!strcmp_P(res->arg1, PSTR("show"))) {
1472                 spi_servo_dump();
1473         }
1474 }
1475
1476 const char PROGMEM str_servo_arg0[] = "servo";
1477 const parse_token_string_t PROGMEM cmd_servo_arg0 =
1478         TOKEN_STRING_INITIALIZER(struct cmd_servo_result, arg0,
1479                                  str_servo_arg0);
1480 const char PROGMEM str_servo_arg1_set[] = "set";
1481 const parse_token_string_t PROGMEM cmd_servo_arg1_set =
1482         TOKEN_STRING_INITIALIZER(struct cmd_servo_result, arg1,
1483                                  str_servo_arg1_set);
1484 const parse_token_num_t PROGMEM cmd_servo_num =
1485         TOKEN_NUM_INITIALIZER(struct cmd_servo_result, num,
1486                               UINT16);
1487 const parse_token_num_t PROGMEM cmd_servo_val =
1488         TOKEN_NUM_INITIALIZER(struct cmd_servo_result, val,
1489                               UINT16);
1490
1491 const char PROGMEM help_servo_set[] = "set servo value";
1492 const parse_inst_t PROGMEM cmd_servo_set = {
1493         .f = cmd_servo_parsed,  /* function to call */
1494         .data = NULL,      /* 2nd arg of func */
1495         .help_str = help_servo_set,
1496         .tokens = {        /* token list, NULL terminated */
1497                 (PGM_P)&cmd_servo_arg0,
1498                 (PGM_P)&cmd_servo_arg1_set,
1499                 (PGM_P)&cmd_servo_num,
1500                 (PGM_P)&cmd_servo_val,
1501                 NULL,
1502         },
1503 };
1504
1505 const char PROGMEM str_servo_arg1_show[] = "show";
1506 const parse_token_string_t PROGMEM cmd_servo_arg1_show =
1507         TOKEN_STRING_INITIALIZER(struct cmd_servo_result, arg1,
1508                                  str_servo_arg1_show);
1509
1510 const char PROGMEM help_servo_show[] = "read servo and config";
1511 const parse_inst_t PROGMEM cmd_servo_show = {
1512         .f = cmd_servo_parsed,  /* function to call */
1513         .data = NULL,      /* 2nd arg of func */
1514         .help_str = help_servo_show,
1515         .tokens = {        /* token list, NULL terminated */
1516                 (PGM_P)&cmd_servo_arg0,
1517                 (PGM_P)&cmd_servo_arg1_show,
1518                 NULL,
1519         },
1520 };
1521
1522 const char PROGMEM str_servo_arg1_bypassppm[] = "bypass#ppm";
1523 const parse_token_string_t PROGMEM cmd_servo_arg1_bypassppm =
1524         TOKEN_STRING_INITIALIZER(struct cmd_servo_result, arg1,
1525                                  str_servo_arg1_bypassppm);
1526
1527 const char PROGMEM help_servo_bypassppm[] = "change bypass/ppm";
1528 const parse_inst_t PROGMEM cmd_servo_bypassppm = {
1529         .f = cmd_servo_parsed,  /* function to call */
1530         .data = NULL,      /* 2nd arg of func */
1531         .help_str = help_servo_bypassppm,
1532         .tokens = {        /* token list, NULL terminated */
1533                 (PGM_P)&cmd_servo_arg0,
1534                 (PGM_P)&cmd_servo_arg1_bypassppm,
1535                 (PGM_P)&cmd_servo_val,
1536                 NULL,
1537         },
1538 };
1539
1540 /**********************************************************/
1541
1542 /* this structure is filled when cmd_test_spi is parsed successfully */
1543 struct cmd_test_spi_result {
1544         fixed_string_t arg0;
1545 };
1546
1547 static void cmd_test_spi_parsed(void * parsed_result, void *data)
1548 {
1549         uint8_t i, flags, wait_time = 0;
1550         uint16_t val = 0;
1551
1552         (void)parsed_result;
1553         (void)data;
1554
1555         spi_servo_set_bypass(0);
1556         spi_servo_set_ppm(0);
1557
1558         /* stress test: send many commands, no wait between each servo
1559          * of a series, and a variable delay between series */
1560         printf_P(PSTR("stress test\r\n"));
1561         while (!cmdline_keypressed()) {
1562
1563                 wait_time++;
1564                 if (wait_time > 20)
1565                         wait_time = 0;
1566
1567                 IRQ_LOCK(flags);
1568                 val = global_ms;
1569                 IRQ_UNLOCK(flags);
1570                 val >>= 3;
1571                 val &= 1023;
1572
1573                 for (i = 0; i < 6; i++)
1574                         spi_servo_set(i, val);
1575
1576                 wait_ms(wait_time);
1577                 printf_P(PSTR("%4.4d %4.4d %4.4d %4.4d %4.4d %4.4d\r\n"),
1578                          spi_servo_get(0), spi_servo_get(1), spi_servo_get(2),
1579                          spi_servo_get(3), spi_servo_get(4), spi_servo_get(5));
1580         }
1581
1582         printf_P(PSTR("bypass mode, with spi commands in background\r\n"));
1583         spi_servo_set_bypass(1);
1584
1585         /* test bypass mode */
1586         while (!cmdline_keypressed()) {
1587
1588                 wait_time++;
1589                 if (wait_time > 20)
1590                         wait_time = 0;
1591
1592                 IRQ_LOCK(flags);
1593                 val = global_ms;
1594                 IRQ_UNLOCK(flags);
1595                 val >>= 3;
1596                 val &= 1023;
1597
1598                 for (i = 0; i < 6; i++)
1599                         spi_servo_set(i, val);
1600
1601                 wait_ms(wait_time);
1602                 printf_P(PSTR("%4.4d %4.4d %4.4d %4.4d %4.4d %4.4d\r\n"),
1603                          spi_servo_get(0), spi_servo_get(1), spi_servo_get(2),
1604                          spi_servo_get(3), spi_servo_get(4), spi_servo_get(5));
1605         }
1606
1607         printf_P(PSTR("PPM to servo\r\n"));
1608         spi_servo_set_bypass(0);
1609         spi_servo_set_ppm(0);
1610
1611         /* test PPM to servo (bypass) mode */
1612         while (!cmdline_keypressed()) {
1613                 for (i = 0; i < 6; i++) {
1614                         val = spi_servo_get(i);
1615                         spi_servo_set(i, val);
1616                 }
1617         }
1618
1619         printf_P(PSTR("PPM to (servo + PPM)\r\n"));
1620         spi_servo_set_bypass(0);
1621         spi_servo_set_ppm(1);
1622
1623         /* test PPM to servo (bypass) mode */
1624         while (!cmdline_keypressed()) {
1625                 for (i = 0; i < 6; i++) {
1626                         val = spi_servo_get(i);
1627                         spi_servo_set(i, val);
1628                 }
1629         }
1630 }
1631
1632 const char PROGMEM str_test_spi_arg0[] = "test_spi";
1633 const parse_token_string_t PROGMEM cmd_test_spi_arg0 =
1634         TOKEN_STRING_INITIALIZER(struct cmd_test_spi_result, arg0,
1635                                  str_test_spi_arg0);
1636
1637 const char PROGMEM help_test_spi[] = "Test the spi";
1638 const parse_inst_t PROGMEM cmd_test_spi = {
1639         .f = cmd_test_spi_parsed,  /* function to call */
1640         .data = NULL,      /* 2nd arg of func */
1641         .help_str = help_test_spi,
1642         .tokens = {        /* token list, NULL terminated */
1643                 (PGM_P)&cmd_test_spi_arg0,
1644                 NULL,
1645         },
1646 };
1647
1648 /**********************************************************/
1649
1650 /* this structure is filled when cmd_dump_xbee_stats is parsed successfully */
1651 struct cmd_dump_xbee_stats_result {
1652         fixed_string_t arg0;
1653 };
1654
1655 static void cmd_dump_xbee_stats_parsed(void *parsed_result, void *data)
1656 {
1657         (void)parsed_result;
1658         (void)data;
1659
1660         xbee_dump_stats(xbee_dev);
1661 }
1662
1663 const char PROGMEM str_dump_xbee_stats_arg0[] = "dump_xbee_stats";
1664 const parse_token_string_t PROGMEM cmd_dump_xbee_stats_arg0 =
1665         TOKEN_STRING_INITIALIZER(struct cmd_dump_xbee_stats_result, arg0,
1666                                  str_dump_xbee_stats_arg0);
1667
1668 const char PROGMEM help_dump_xbee_stats[] = "Test the spi";
1669 const parse_inst_t PROGMEM cmd_dump_xbee_stats = {
1670         .f = cmd_dump_xbee_stats_parsed,  /* function to call */
1671         .data = NULL,      /* 2nd arg of func */
1672         .help_str = help_dump_xbee_stats,
1673         .tokens = {        /* token list, NULL terminated */
1674                 (PGM_P)&cmd_dump_xbee_stats_arg0,
1675                 NULL,
1676         },
1677 };
1678
1679 /**********************************************************/
1680
1681 /* this structure is filled when cmd_test_eeprom_config is parsed successfully */
1682 struct cmd_test_eeprom_config_result {
1683         fixed_string_t arg0;
1684 };
1685
1686 static void cmd_test_eeprom_config_parsed(void *parsed_result, void *data)
1687 {
1688         (void)parsed_result;
1689         (void)data;
1690
1691         eeprom_dump_cmds();
1692         eeprom_append_cmd("salut1\n");
1693         eeprom_dump_cmds();
1694         eeprom_append_cmd("salut2\n");
1695         eeprom_append_cmd("salut3\n");
1696         eeprom_append_cmd("salut4\n");
1697         eeprom_dump_cmds();
1698         eeprom_insert_cmd_before("coin\n", 0);
1699         eeprom_insert_cmd_before("coin2\n", 2);
1700         eeprom_dump_cmds();
1701         eeprom_delete_cmd(2);
1702         eeprom_delete_cmd(0);
1703         eeprom_dump_cmds();
1704 }
1705
1706 const char PROGMEM str_test_eeprom_config_arg0[] = "test_eeprom_config";
1707 const parse_token_string_t PROGMEM cmd_test_eeprom_config_arg0 =
1708         TOKEN_STRING_INITIALIZER(struct cmd_test_eeprom_config_result, arg0,
1709                                  str_test_eeprom_config_arg0);
1710
1711 const char PROGMEM help_test_eeprom_config[] = "Test the eeprom configuration";
1712 const parse_inst_t PROGMEM cmd_test_eeprom_config = {
1713         .f = cmd_test_eeprom_config_parsed,  /* function to call */
1714         .data = NULL,      /* 2nd arg of func */
1715         .help_str = help_test_eeprom_config,
1716         .tokens = {        /* token list, NULL terminated */
1717                 (PGM_P)&cmd_test_eeprom_config_arg0,
1718                 NULL,
1719         },
1720 };
1721
1722 /* ************* */
1723
1724 struct cmd_eeprom_del_result {
1725         fixed_string_t cmd;
1726         fixed_string_t action;
1727         uint8_t n;
1728 };
1729
1730 static void cmd_eeprom_del_parsed(void *parsed_result,
1731                                 void *data)
1732 {
1733         struct cmd_eeprom_del_result *res = parsed_result;
1734
1735         (void)data;
1736         if (eeprom_delete_cmd(res->n) < 0)
1737                 printf_P(PSTR("cannot delete command\n"));
1738         eeprom_dump_cmds();
1739 }
1740
1741 const char PROGMEM str_eeprom_del_eeprom[] = "eeprom";
1742 const parse_token_string_t PROGMEM cmd_eeprom_del_cmd =
1743         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_del_result, cmd,
1744                                  str_eeprom_del_eeprom);
1745 const char PROGMEM str_eeprom_del_del[] = "del";
1746 const parse_token_string_t PROGMEM cmd_eeprom_del_action =
1747         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_del_result, action,
1748                                  str_eeprom_del_del);
1749 const parse_token_num_t PROGMEM cmd_eeprom_del_num =
1750         TOKEN_NUM_INITIALIZER(struct cmd_eeprom_del_result, n,
1751                               UINT8);
1752
1753 const char PROGMEM help_eeprom_del[] = "delete an eeprom init command";
1754 const parse_inst_t PROGMEM cmd_eeprom_del = {
1755         .f = cmd_eeprom_del_parsed,  /* function to call */
1756         .data = NULL,      /* 2nd arg of func */
1757         .help_str = help_eeprom_del,
1758         .tokens = {        /* token list, NULL terminated */
1759                 (PGM_P)&cmd_eeprom_del_cmd,
1760                 (PGM_P)&cmd_eeprom_del_action,
1761                 (PGM_P)&cmd_eeprom_del_num,
1762                 NULL,
1763         },
1764 };
1765
1766 /* ************* */
1767
1768 struct cmd_eeprom_add_result {
1769         fixed_string_t cmd;
1770         fixed_string_t action;
1771         uint8_t n;
1772 };
1773
1774 static void cmd_eeprom_add_parsed(void *parsed_result,
1775                                  void *data)
1776 {
1777         struct cmd_eeprom_add_result *res = parsed_result;
1778         struct rdline rdl;
1779         const char *buffer;
1780         int8_t ret;
1781         int16_t c;
1782
1783         rdline_init(&rdl, cmdline_write_char, NULL, NULL);
1784         rdline_newline(&rdl, "> ");
1785
1786         /* XXX bad: we should not block as we do not serve callout */
1787         while (1) {
1788                 c = cmdline_dev_recv(NULL);
1789                 if (c < 0)
1790                         continue;
1791
1792                 ret = rdline_char_in(&rdl, c);
1793                 if (ret == -2) {
1794                         printf_P(PSTR("abort\n"));
1795                         return;
1796                 }
1797                 if (ret == 1)
1798                         break;
1799         }
1800
1801         buffer = rdline_get_buffer(&rdl);
1802         if (data == NULL)
1803                 eeprom_insert_cmd_before(buffer, res->n);
1804         else
1805                 eeprom_append_cmd(buffer);
1806         eeprom_dump_cmds();
1807 }
1808
1809 const char PROGMEM str_eeprom_add_eeprom[] = "eeprom";
1810 const parse_token_string_t PROGMEM cmd_eeprom_add_cmd =
1811         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_add_result, cmd,
1812                                  str_eeprom_add_eeprom);
1813 const char PROGMEM str_eeprom_add_add[] = "add";
1814 const parse_token_string_t PROGMEM cmd_eeprom_add_action =
1815         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_add_result, action,
1816                                  str_eeprom_add_add);
1817 const parse_token_num_t PROGMEM cmd_eeprom_add_num =
1818         TOKEN_NUM_INITIALIZER(struct cmd_eeprom_add_result, n,
1819                               UINT8);
1820
1821 const char PROGMEM help_eeprom_add[] = "insert an eeprom init command";
1822 const parse_inst_t PROGMEM cmd_eeprom_add = {
1823         .f = cmd_eeprom_add_parsed,  /* function to call */
1824         .data = NULL,      /* 2nd arg of func */
1825         .help_str = help_eeprom_add,
1826         .tokens = {        /* token list, NULL terminated */
1827                 (PGM_P)&cmd_eeprom_add_cmd,
1828                 (PGM_P)&cmd_eeprom_add_action,
1829                 (PGM_P)&cmd_eeprom_add_num,
1830                 NULL,
1831         },
1832 };
1833
1834 const char PROGMEM help_eeprom_add2[] = "append an eeprom init command";
1835 const parse_inst_t PROGMEM cmd_eeprom_add2 = {
1836         .f = cmd_eeprom_add_parsed,  /* function to call */
1837         .data = (void *)1,      /* 2nd arg of func */
1838         .help_str = help_eeprom_add2,
1839         .tokens = {        /* token list, NULL terminated */
1840                 (PGM_P)&cmd_eeprom_add_cmd,
1841                 (PGM_P)&cmd_eeprom_add_action,
1842                 NULL,
1843         },
1844 };
1845
1846 /* ************* */
1847
1848 struct cmd_eeprom_list_result {
1849         fixed_string_t cmd;
1850         fixed_string_t action;
1851 };
1852
1853 static void cmd_eeprom_list_parsed(void *parsed_result,
1854                                 void *data)
1855 {
1856         (void)parsed_result;
1857         (void)data;
1858         eeprom_dump_cmds();
1859 }
1860
1861 const char PROGMEM str_eeprom_list_eeprom[] = "eeprom";
1862 const parse_token_string_t PROGMEM cmd_eeprom_list_cmd =
1863         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_list_result, cmd,
1864                                  str_eeprom_list_eeprom);
1865 const char PROGMEM str_eeprom_list_list[] = "list";
1866 const parse_token_string_t PROGMEM cmd_eeprom_list_action =
1867         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_list_result, action,
1868                                  str_eeprom_list_list);
1869
1870 const char PROGMEM help_eeprom_list[] = "list all eeprom init commands";
1871 const parse_inst_t PROGMEM cmd_eeprom_list = {
1872         .f = cmd_eeprom_list_parsed,  /* function to call */
1873         .data = NULL,      /* 2nd arg of func */
1874         .help_str = help_eeprom_list,
1875         .tokens = {        /* token list, NULL terminated */
1876                 (PGM_P)&cmd_eeprom_list_cmd,
1877                 (PGM_P)&cmd_eeprom_list_action,
1878                 NULL,
1879         },
1880 };
1881
1882
1883 /* ************* */
1884
1885 /* in progmem */
1886 const parse_ctx_t PROGMEM main_ctx[] = {
1887
1888         /* commands_gen.c */
1889         &cmd_reset,
1890         &cmd_bootloader,
1891         &cmd_log,
1892         &cmd_log_show,
1893         &cmd_log_type,
1894         &cmd_stack_space,
1895         &cmd_scheduler,
1896         &cmd_help,
1897         &cmd_neigh_del,
1898         &cmd_neigh_add,
1899         &cmd_neigh_list,
1900         &cmd_read,
1901         &cmd_write_none,
1902         &cmd_write_u8,
1903         &cmd_write_u16,
1904         &cmd_write_u32,
1905         &cmd_sendmsg,
1906         &cmd_send_hello,
1907         &cmd_send_hello_name,
1908         &cmd_sendmsg_name,
1909         &cmd_range,
1910         &cmd_range_period,
1911         &cmd_range_count,
1912         &cmd_range_powermask,
1913         &cmd_range_dstaddr,
1914         &cmd_monitor,
1915         &cmd_monitor_period,
1916         &cmd_monitor_add,
1917         &cmd_monitor_del,
1918         &cmd_ping,
1919         &cmd_raw,
1920         &cmd_dump,
1921         &cmd_debug,
1922         &cmd_baudrate,
1923         &cmd_beep,
1924         &cmd_servo_set,
1925         &cmd_servo_bypassppm,
1926         &cmd_servo_show,
1927         &cmd_test_spi,
1928         &cmd_dump_xbee_stats,
1929         &cmd_test_eeprom_config,
1930         &cmd_eeprom_del,
1931         &cmd_eeprom_add,
1932         &cmd_eeprom_add2,
1933         &cmd_eeprom_list,
1934         NULL,
1935 };