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