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