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