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