rc_proto: allow to configure timers
[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_timers is parsed successfully */
1617 struct cmd_rc_proto_timers_result {
1618         fixed_string_t arg0;
1619         fixed_string_t arg1;
1620         uint16_t servo_min;
1621         uint16_t servo_max;
1622         uint16_t power_probe;
1623         uint16_t autobypass;
1624 };
1625
1626 static void cmd_rc_proto_timers_parsed(void *parsed_result, void *data)
1627 {
1628         struct cmd_rc_proto_timers_result *res = parsed_result;
1629         (void)data;
1630
1631         if (!strcmp_P(res->arg1, PSTR("set"))) {
1632                 rc_proto_timers.send_servo_min_ms = res->servo_min;
1633                 rc_proto_timers.send_servo_max_ms = res->servo_max;
1634                 rc_proto_timers.send_power_probe_ms = res->power_probe;
1635                 rc_proto_timers.autobypass_ms = res->autobypass;
1636         }
1637
1638         printf_P(PSTR("rc_proto_timers: min=%d, max=%d, "
1639                         "power_probe=%d autobypass=%d\n"),
1640                 rc_proto_timers.send_servo_min_ms,
1641                 rc_proto_timers.send_servo_max_ms,
1642                 rc_proto_timers.send_power_probe_ms,
1643                 rc_proto_timers.autobypass_ms);
1644 }
1645
1646 const char PROGMEM str_rc_proto_timers_arg0[] = "rc_proto_timers";
1647 const parse_token_string_t PROGMEM cmd_rc_proto_timers_arg0 =
1648         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_timers_result, arg0,
1649                                  str_rc_proto_timers_arg0);
1650 const char PROGMEM str_rc_proto_timers_arg1[] = "set";
1651 const parse_token_string_t PROGMEM cmd_rc_proto_timers_arg1 =
1652         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_timers_result, arg1,
1653                                  str_rc_proto_timers_arg1);
1654 const parse_token_num_t PROGMEM cmd_rc_proto_timers_servo_min =
1655         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_timers_result, servo_min,
1656                 UINT16);
1657 const parse_token_num_t PROGMEM cmd_rc_proto_timers_servo_max =
1658         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_timers_result, servo_max,
1659                 UINT16);
1660 const parse_token_num_t PROGMEM cmd_rc_proto_timers_power_probe =
1661         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_timers_result, power_probe,
1662                 UINT16);
1663 const parse_token_num_t PROGMEM cmd_rc_proto_timers_autobypass =
1664         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_timers_result, autobypass,
1665                 UINT16);
1666
1667 const char PROGMEM help_rc_proto_timers[] = "set rc_proto_timers (servo_min, "
1668         "servo_max, pow_probe, autobypass)";
1669 const parse_inst_t PROGMEM cmd_rc_proto_timers = {
1670         .f = cmd_rc_proto_timers_parsed,  /* function to call */
1671         .data = NULL,      /* 2nd arg of func */
1672         .help_str = help_rc_proto_timers,
1673         .tokens = {        /* token list, NULL terminated */
1674                 (PGM_P)&cmd_rc_proto_timers_arg0,
1675                 (PGM_P)&cmd_rc_proto_timers_arg1,
1676                 (PGM_P)&cmd_rc_proto_timers_servo_min,
1677                 (PGM_P)&cmd_rc_proto_timers_servo_max,
1678                 (PGM_P)&cmd_rc_proto_timers_power_probe,
1679                 (PGM_P)&cmd_rc_proto_timers_autobypass,
1680                 NULL,
1681         },
1682 };
1683
1684 const char PROGMEM str_rc_proto_timers_show_arg1[] = "show";
1685 const parse_token_string_t PROGMEM cmd_rc_proto_timers_show_arg1 =
1686         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_timers_result, arg1,
1687                                  str_rc_proto_timers_show_arg1);
1688
1689 const char PROGMEM help_rc_proto_timers_show[] = "show rc_proto timers value";
1690 const parse_inst_t PROGMEM cmd_rc_proto_timers_show = {
1691         .f = cmd_rc_proto_timers_parsed,  /* function to call */
1692         .data = NULL,      /* 2nd arg of func */
1693         .help_str = help_rc_proto_timers_show,
1694         .tokens = {        /* token list, NULL terminated */
1695                 (PGM_P)&cmd_rc_proto_timers_arg0,
1696                 (PGM_P)&cmd_rc_proto_timers_show_arg1,
1697                 NULL,
1698         },
1699 };
1700
1701 /**********************************************************/
1702
1703 /* this structure is filled when cmd_rc_proto_mode is parsed successfully */
1704 struct cmd_rc_proto_mode_result {
1705         fixed_string_t arg0;
1706         fixed_string_t cmd;
1707         fixed_string_t val;
1708 };
1709
1710 static void cmd_rc_proto_mode_parsed(void *parsed_result, void *data)
1711 {
1712         struct cmd_rc_proto_mode_result *res = parsed_result;
1713         (void)data;
1714         uint8_t flags;
1715         uint8_t on = 0;
1716
1717         flags = rc_proto_get_mode();
1718         if (!strcmp_P(res->val, PSTR("on")))
1719                 on = 1;
1720
1721         if (!strcmp_P(res->cmd, PSTR("rx_copy_spi"))) {
1722                 if (on == 1)
1723                         flags |= RC_PROTO_FLAGS_RX_COPY_SPI;
1724                 else
1725                         flags &= ~RC_PROTO_FLAGS_RX_COPY_SPI;
1726         }
1727         else if (!strcmp_P(res->cmd, PSTR("rx_autobypass"))) {
1728                 if (on == 1)
1729                         flags |= RC_PROTO_FLAGS_RX_AUTOBYPASS;
1730                 else
1731                         flags &= ~RC_PROTO_FLAGS_RX_AUTOBYPASS;
1732         }
1733         else if (!strcmp_P(res->cmd, PSTR("tx_stats"))) {
1734                 if (on == 1)
1735                         flags |= RC_PROTO_FLAGS_TX_STATS;
1736                 else
1737                         flags &= ~RC_PROTO_FLAGS_TX_STATS;
1738         }
1739         else if (!strcmp_P(res->cmd, PSTR("tx_power_probe"))) {
1740                 if (on == 1)
1741                         flags |= RC_PROTO_FLAGS_TX_POW_PROBE;
1742                 else
1743                         flags &= ~RC_PROTO_FLAGS_TX_POW_PROBE;
1744         }
1745         else if (!strcmp_P(res->cmd, PSTR("tx"))) {
1746                 flags &= ~RC_PROTO_FLAGS_TX_MASK;
1747                 if (!strcmp_P(res->val, PSTR("bypass")))
1748                         flags |= RC_PROTO_FLAGS_TX_BYPASS;
1749                 else if (!strcmp_P(res->val, PSTR("copy_spi")))
1750                         flags |= RC_PROTO_FLAGS_TX_COPY_SPI;
1751         }
1752         rc_proto_set_mode(flags);
1753
1754         /* dump state */
1755         if ((flags & RC_PROTO_FLAGS_TX_MASK) == RC_PROTO_FLAGS_TX_OFF)
1756                 printf_P(PSTR("rc_proto_mode tx off\n"));
1757         else if ((flags & RC_PROTO_FLAGS_TX_MASK) == RC_PROTO_FLAGS_TX_BYPASS)
1758                 printf_P(PSTR("rc_proto_mode tx bypass\n"));
1759         else if ((flags & RC_PROTO_FLAGS_TX_MASK) == RC_PROTO_FLAGS_TX_COPY_SPI)
1760                 printf_P(PSTR("rc_proto_mode tx copy_spi\n"));
1761         printf_P(PSTR("rc_proto_mode rx_copy_spi %s\n"),
1762                 (flags & RC_PROTO_FLAGS_RX_COPY_SPI) ? "on" : "off");
1763         printf_P(PSTR("rc_proto_mode rx_autobypass %s\n"),
1764                 (flags & RC_PROTO_FLAGS_RX_AUTOBYPASS) ? "on" : "off");
1765         printf_P(PSTR("rc_proto_mode tx_stats %s\n"),
1766                 (flags & RC_PROTO_FLAGS_TX_STATS) ? "on" : "off");
1767         printf_P(PSTR("rc_proto_mode tx_power_probe %s\n"),
1768                 (flags & RC_PROTO_FLAGS_TX_POW_PROBE) ? "on" : "off");
1769 }
1770
1771 const char PROGMEM str_rc_proto_mode_arg0[] = "rc_proto_mode";
1772 const parse_token_string_t PROGMEM cmd_rc_proto_mode_arg0 =
1773         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_mode_result, arg0,
1774                                  str_rc_proto_mode_arg0);
1775
1776 const char PROGMEM str_rc_proto_mode_cmd[] =
1777         "rx_copy_spi#rx_autobypass#tx_stats#tx_power_probe";
1778 const parse_token_string_t PROGMEM cmd_rc_proto_mode_cmd =
1779         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_mode_result, cmd,
1780                 str_rc_proto_mode_cmd);
1781
1782 const char PROGMEM str_rc_proto_mode_onoff[] = "on#off";
1783 const parse_token_string_t PROGMEM cmd_rc_proto_mode_onoff =
1784         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_mode_result, val,
1785                                  str_rc_proto_mode_onoff);
1786
1787 const char PROGMEM help_rc_proto_mode[] = "Set rc proto behavior";
1788 const parse_inst_t PROGMEM cmd_rc_proto_mode = {
1789         .f = cmd_rc_proto_mode_parsed,  /* function to call */
1790         .data = NULL,      /* 2nd arg of func */
1791         .help_str = help_rc_proto_mode,
1792         .tokens = {        /* token list, NULL terminated */
1793                 (PGM_P)&cmd_rc_proto_mode_arg0,
1794                 (PGM_P)&cmd_rc_proto_mode_cmd,
1795                 (PGM_P)&cmd_rc_proto_mode_onoff,
1796                 NULL,
1797         },
1798 };
1799
1800 const char PROGMEM str_rc_proto_mode_cmd2[] = "tx";
1801 const parse_token_string_t PROGMEM cmd_rc_proto_mode_cmd2 =
1802         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_mode_result, cmd,
1803                 str_rc_proto_mode_cmd2);
1804
1805 const char PROGMEM str_rc_proto_mode_val[] = "off#bypass#copy_spi";
1806 const parse_token_string_t PROGMEM cmd_rc_proto_mode_val =
1807         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_mode_result, val,
1808                                  str_rc_proto_mode_val);
1809
1810 const parse_inst_t PROGMEM cmd_rc_proto_mode2 = {
1811         .f = cmd_rc_proto_mode_parsed,  /* function to call */
1812         .data = NULL,      /* 2nd arg of func */
1813         .help_str = help_rc_proto_mode,
1814         .tokens = {        /* token list, NULL terminated */
1815                 (PGM_P)&cmd_rc_proto_mode_arg0,
1816                 (PGM_P)&cmd_rc_proto_mode_cmd2,
1817                 (PGM_P)&cmd_rc_proto_mode_val,
1818                 NULL,
1819         },
1820 };
1821
1822 const char PROGMEM str_rc_proto_mode_cmd3[] = "show";
1823 const parse_token_string_t PROGMEM cmd_rc_proto_mode_cmd3 =
1824         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_mode_result, cmd,
1825                 str_rc_proto_mode_cmd3);
1826
1827 const parse_inst_t PROGMEM cmd_rc_proto_mode3 = {
1828         .f = cmd_rc_proto_mode_parsed,  /* function to call */
1829         .data = NULL,      /* 2nd arg of func */
1830         .help_str = help_rc_proto_mode,
1831         .tokens = {        /* token list, NULL terminated */
1832                 (PGM_P)&cmd_rc_proto_mode_arg0,
1833                 (PGM_P)&cmd_rc_proto_mode_cmd3,
1834                 NULL,
1835         },
1836 };
1837
1838 /**********************************************************/
1839
1840 /* this structure is filled when cmd_rc_proto_hello is parsed successfully */
1841 struct cmd_rc_proto_hello_result {
1842         fixed_string_t rc_proto_hello;
1843         uint64_t addr;
1844         struct xbee_neigh *neigh;
1845         uint16_t period;
1846         uint16_t count;
1847         fixed_string_t data;
1848 };
1849
1850 /* function called when cmd_rc_proto_hello is parsed successfully */
1851 static void cmd_rc_proto_hello_parsed(void *parsed_result, void *use_neigh)
1852 {
1853         struct cmd_rc_proto_hello_result *res = parsed_result;
1854         uint16_t now, next, diff;
1855         uint8_t flags;
1856         uint64_t addr;
1857
1858         if (use_neigh)
1859                 addr = res->neigh->addr;
1860         else
1861                 addr = res->addr;
1862
1863         IRQ_LOCK(flags);
1864         now = global_ms;
1865         IRQ_UNLOCK(flags);
1866
1867         next = now;
1868
1869         while (!cmdline_keypressed() && res->count != 0) {
1870                 IRQ_LOCK(flags);
1871                 now = global_ms;
1872                 IRQ_UNLOCK(flags);
1873
1874                 diff = now - next;
1875                 if (diff < res->period)
1876                         continue;
1877
1878                 rc_proto_send_hello(addr, res->data, strlen(res->data), -1);
1879                 next += res->period;
1880                 res->count--;
1881         }
1882 }
1883
1884 const char PROGMEM str_rc_proto_hello[] = "rc_proto_hello";
1885
1886 const parse_token_string_t PROGMEM cmd_rc_proto_hello_rc_proto_hello =
1887         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_hello_result, rc_proto_hello,
1888                                  str_rc_proto_hello);
1889
1890 const parse_token_num_t PROGMEM cmd_rc_proto_hello_addr =
1891         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_hello_result, addr, UINT64);
1892
1893 const parse_token_num_t PROGMEM cmd_rc_proto_hello_period =
1894         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_hello_result, period, UINT16);
1895
1896 const parse_token_num_t PROGMEM cmd_rc_proto_hello_count =
1897         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_hello_result, count, UINT16);
1898
1899 const parse_token_string_t PROGMEM cmd_rc_proto_hello_data =
1900         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_hello_result, data, NULL);
1901
1902 const char PROGMEM help_rc_proto_hello[] =
1903         "Send hello msg to a node: addr, period_ms, count, str";
1904
1905 const parse_inst_t PROGMEM cmd_rc_proto_hello = {
1906         .f = cmd_rc_proto_hello_parsed,  /* function to call */
1907         .data = NULL,      /* 2nd arg of func */
1908         .help_str = help_rc_proto_hello,
1909         .tokens = {        /* token list, NULL terminated */
1910                 (PGM_P)&cmd_rc_proto_hello_rc_proto_hello,
1911                 (PGM_P)&cmd_rc_proto_hello_addr,
1912                 (PGM_P)&cmd_rc_proto_hello_period,
1913                 (PGM_P)&cmd_rc_proto_hello_count,
1914                 (PGM_P)&cmd_rc_proto_hello_data,
1915                 NULL,
1916         },
1917 };
1918
1919 const parse_token_neighbor_t PROGMEM cmd_rc_proto_hello_neigh =
1920         TOKEN_NEIGHBOR_INITIALIZER(struct cmd_rc_proto_hello_result, neigh,
1921                                    &xbee_dev);
1922
1923 const parse_inst_t PROGMEM cmd_rc_proto_hello_name = {
1924         .f = cmd_rc_proto_hello_parsed,  /* function to call */
1925         .data = (void *)1,      /* 2nd arg of func */
1926         .help_str = help_rc_proto_hello,
1927         .tokens = {        /* token list, NULL terminated */
1928                 (PGM_P)&cmd_rc_proto_hello_rc_proto_hello,
1929                 (PGM_P)&cmd_rc_proto_hello_neigh,
1930                 (PGM_P)&cmd_rc_proto_hello_period,
1931                 (PGM_P)&cmd_rc_proto_hello_count,
1932                 (PGM_P)&cmd_rc_proto_hello_data,
1933                 NULL,
1934         },
1935 };
1936
1937 /**********************************************************/
1938
1939 /* this structure is filled when cmd_rc_proto_echo is parsed successfully */
1940 struct cmd_rc_proto_echo_result {
1941         fixed_string_t rc_proto_echo;
1942         uint64_t addr;
1943         struct xbee_neigh *neigh;
1944         uint16_t period;
1945         uint16_t count;
1946         fixed_string_t data;
1947 };
1948
1949 /* function called when cmd_rc_proto_echo is parsed successfully */
1950 static void cmd_rc_proto_echo_parsed(void *parsed_result, void *use_neigh)
1951 {
1952         struct cmd_rc_proto_echo_result *res = parsed_result;
1953         uint16_t now, next, diff;
1954         uint8_t flags;
1955         uint64_t addr;
1956
1957         if (use_neigh)
1958                 addr = res->neigh->addr;
1959         else
1960                 addr = res->addr;
1961
1962         IRQ_LOCK(flags);
1963         now = global_ms;
1964         IRQ_UNLOCK(flags);
1965
1966         next = now;
1967
1968         while (!cmdline_keypressed() && res->count != 0) {
1969                 IRQ_LOCK(flags);
1970                 now = global_ms;
1971                 IRQ_UNLOCK(flags);
1972
1973                 diff = now - next;
1974                 if (diff < res->period)
1975                         continue;
1976
1977                 rc_proto_send_echo_req(addr, res->data, strlen(res->data), -1);
1978                 next += res->period;
1979                 res->count--;
1980         }
1981 }
1982
1983 const char PROGMEM str_rc_proto_echo[] = "rc_proto_echo";
1984
1985 const parse_token_string_t PROGMEM cmd_rc_proto_echo_rc_proto_echo =
1986         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_echo_result, rc_proto_echo,
1987                                  str_rc_proto_echo);
1988
1989 const parse_token_num_t PROGMEM cmd_rc_proto_echo_addr =
1990         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_echo_result, addr, UINT64);
1991
1992 const parse_token_num_t PROGMEM cmd_rc_proto_echo_period =
1993         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_echo_result, period, UINT16);
1994
1995 const parse_token_num_t PROGMEM cmd_rc_proto_echo_count =
1996         TOKEN_NUM_INITIALIZER(struct cmd_rc_proto_echo_result, count, UINT16);
1997
1998 const parse_token_string_t PROGMEM cmd_rc_proto_echo_data =
1999         TOKEN_STRING_INITIALIZER(struct cmd_rc_proto_echo_result, data, NULL);
2000
2001 const char PROGMEM help_rc_proto_echo[] =
2002         "Send echo msg to a node: addr, period_ms, count, str";
2003
2004 const parse_inst_t PROGMEM cmd_rc_proto_echo = {
2005         .f = cmd_rc_proto_echo_parsed,  /* function to call */
2006         .data = NULL,      /* 2nd arg of func */
2007         .help_str = help_rc_proto_echo,
2008         .tokens = {        /* token list, NULL terminated */
2009                 (PGM_P)&cmd_rc_proto_echo_rc_proto_echo,
2010                 (PGM_P)&cmd_rc_proto_echo_addr,
2011                 (PGM_P)&cmd_rc_proto_echo_period,
2012                 (PGM_P)&cmd_rc_proto_echo_count,
2013                 (PGM_P)&cmd_rc_proto_echo_data,
2014                 NULL,
2015         },
2016 };
2017
2018 const parse_token_neighbor_t PROGMEM cmd_rc_proto_echo_neigh =
2019         TOKEN_NEIGHBOR_INITIALIZER(struct cmd_rc_proto_echo_result, neigh,
2020                                    &xbee_dev);
2021
2022 const parse_inst_t PROGMEM cmd_rc_proto_echo_name = {
2023         .f = cmd_rc_proto_echo_parsed,  /* function to call */
2024         .data = (void *)1,      /* 2nd arg of func */
2025         .help_str = help_rc_proto_echo,
2026         .tokens = {        /* token list, NULL terminated */
2027                 (PGM_P)&cmd_rc_proto_echo_rc_proto_echo,
2028                 (PGM_P)&cmd_rc_proto_echo_neigh,
2029                 (PGM_P)&cmd_rc_proto_echo_period,
2030                 (PGM_P)&cmd_rc_proto_echo_count,
2031                 (PGM_P)&cmd_rc_proto_echo_data,
2032                 NULL,
2033         },
2034 };
2035
2036 /**********************************************************/
2037
2038 /* this structure is filled when cmd_test_eeprom_config is parsed successfully */
2039 struct cmd_test_eeprom_config_result {
2040         fixed_string_t arg0;
2041 };
2042
2043 static void cmd_test_eeprom_config_parsed(void *parsed_result, void *data)
2044 {
2045         (void)parsed_result;
2046         (void)data;
2047
2048         eeprom_dump_cmds();
2049         eeprom_append_cmd("salut1\n");
2050         eeprom_dump_cmds();
2051         eeprom_append_cmd("salut2\n");
2052         eeprom_append_cmd("salut3\n");
2053         eeprom_append_cmd("salut4\n");
2054         eeprom_dump_cmds();
2055         eeprom_insert_cmd_before("coin\n", 0);
2056         eeprom_insert_cmd_before("coin2\n", 2);
2057         eeprom_dump_cmds();
2058         eeprom_delete_cmd(2);
2059         eeprom_delete_cmd(0);
2060         eeprom_dump_cmds();
2061 }
2062
2063 const char PROGMEM str_test_eeprom_config_arg0[] = "test_eeprom_config";
2064 const parse_token_string_t PROGMEM cmd_test_eeprom_config_arg0 =
2065         TOKEN_STRING_INITIALIZER(struct cmd_test_eeprom_config_result, arg0,
2066                                  str_test_eeprom_config_arg0);
2067
2068 const char PROGMEM help_test_eeprom_config[] = "Test the eeprom configuration";
2069 const parse_inst_t PROGMEM cmd_test_eeprom_config = {
2070         .f = cmd_test_eeprom_config_parsed,  /* function to call */
2071         .data = NULL,      /* 2nd arg of func */
2072         .help_str = help_test_eeprom_config,
2073         .tokens = {        /* token list, NULL terminated */
2074                 (PGM_P)&cmd_test_eeprom_config_arg0,
2075                 NULL,
2076         },
2077 };
2078
2079 /* ************* */
2080
2081 struct cmd_eeprom_del_result {
2082         fixed_string_t cmd;
2083         fixed_string_t action;
2084         uint8_t n;
2085 };
2086
2087 static void cmd_eeprom_del_parsed(void *parsed_result,
2088                                 void *data)
2089 {
2090         struct cmd_eeprom_del_result *res = parsed_result;
2091
2092         (void)data;
2093         if (eeprom_delete_cmd(res->n) < 0)
2094                 printf_P(PSTR("cannot delete command\n"));
2095         eeprom_dump_cmds();
2096 }
2097
2098 const char PROGMEM str_eeprom_del_eeprom[] = "eeprom";
2099 const parse_token_string_t PROGMEM cmd_eeprom_del_cmd =
2100         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_del_result, cmd,
2101                                  str_eeprom_del_eeprom);
2102 const char PROGMEM str_eeprom_del_del[] = "del";
2103 const parse_token_string_t PROGMEM cmd_eeprom_del_action =
2104         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_del_result, action,
2105                                  str_eeprom_del_del);
2106 const parse_token_num_t PROGMEM cmd_eeprom_del_num =
2107         TOKEN_NUM_INITIALIZER(struct cmd_eeprom_del_result, n,
2108                               UINT8);
2109
2110 const char PROGMEM help_eeprom_del[] = "delete an eeprom init command";
2111 const parse_inst_t PROGMEM cmd_eeprom_del = {
2112         .f = cmd_eeprom_del_parsed,  /* function to call */
2113         .data = NULL,      /* 2nd arg of func */
2114         .help_str = help_eeprom_del,
2115         .tokens = {        /* token list, NULL terminated */
2116                 (PGM_P)&cmd_eeprom_del_cmd,
2117                 (PGM_P)&cmd_eeprom_del_action,
2118                 (PGM_P)&cmd_eeprom_del_num,
2119                 NULL,
2120         },
2121 };
2122
2123 /* ************* */
2124
2125 struct cmd_eeprom_add_result {
2126         fixed_string_t cmd;
2127         fixed_string_t action;
2128         uint8_t n;
2129 };
2130
2131 static void cmd_eeprom_add_parsed(void *parsed_result,
2132                                  void *data)
2133 {
2134         struct cmd_eeprom_add_result *res = parsed_result;
2135         struct rdline rdl;
2136         const char *buffer;
2137         int8_t ret;
2138         int16_t c;
2139
2140         rdline_init(&rdl, cmdline_write_char, NULL, NULL);
2141         rdline_newline(&rdl, "> ");
2142
2143         while (1) {
2144                 c = cmdline_dev_recv(NULL);
2145                 if (c < 0)
2146                         continue;
2147
2148                 ret = rdline_char_in(&rdl, c);
2149                 if (ret == -2) {
2150                         printf_P(PSTR("abort\n"));
2151                         return;
2152                 }
2153                 if (ret == 1)
2154                         break;
2155         }
2156
2157         buffer = rdline_get_buffer(&rdl);
2158         if (data == NULL)
2159                 eeprom_insert_cmd_before(buffer, res->n);
2160         else
2161                 eeprom_append_cmd(buffer);
2162         eeprom_dump_cmds();
2163 }
2164
2165 const char PROGMEM str_eeprom_add_eeprom[] = "eeprom";
2166 const parse_token_string_t PROGMEM cmd_eeprom_add_cmd =
2167         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_add_result, cmd,
2168                                  str_eeprom_add_eeprom);
2169 const char PROGMEM str_eeprom_add_add[] = "add";
2170 const parse_token_string_t PROGMEM cmd_eeprom_add_action =
2171         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_add_result, action,
2172                                  str_eeprom_add_add);
2173 const parse_token_num_t PROGMEM cmd_eeprom_add_num =
2174         TOKEN_NUM_INITIALIZER(struct cmd_eeprom_add_result, n,
2175                               UINT8);
2176
2177 const char PROGMEM help_eeprom_add[] = "insert an eeprom init command";
2178 const parse_inst_t PROGMEM cmd_eeprom_add = {
2179         .f = cmd_eeprom_add_parsed,  /* function to call */
2180         .data = NULL,      /* 2nd arg of func */
2181         .help_str = help_eeprom_add,
2182         .tokens = {        /* token list, NULL terminated */
2183                 (PGM_P)&cmd_eeprom_add_cmd,
2184                 (PGM_P)&cmd_eeprom_add_action,
2185                 (PGM_P)&cmd_eeprom_add_num,
2186                 NULL,
2187         },
2188 };
2189
2190 const char PROGMEM help_eeprom_add2[] = "append an eeprom init command";
2191 const parse_inst_t PROGMEM cmd_eeprom_add2 = {
2192         .f = cmd_eeprom_add_parsed,  /* function to call */
2193         .data = (void *)1,      /* 2nd arg of func */
2194         .help_str = help_eeprom_add2,
2195         .tokens = {        /* token list, NULL terminated */
2196                 (PGM_P)&cmd_eeprom_add_cmd,
2197                 (PGM_P)&cmd_eeprom_add_action,
2198                 NULL,
2199         },
2200 };
2201
2202 /* ************* */
2203
2204 struct cmd_eeprom_list_result {
2205         fixed_string_t cmd;
2206         fixed_string_t action;
2207 };
2208
2209 static void cmd_eeprom_list_parsed(void *parsed_result,
2210                                 void *data)
2211 {
2212         (void)parsed_result;
2213         (void)data;
2214         eeprom_dump_cmds();
2215 }
2216
2217 const char PROGMEM str_eeprom_list_eeprom[] = "eeprom";
2218 const parse_token_string_t PROGMEM cmd_eeprom_list_cmd =
2219         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_list_result, cmd,
2220                                  str_eeprom_list_eeprom);
2221 const char PROGMEM str_eeprom_list_list[] = "list";
2222 const parse_token_string_t PROGMEM cmd_eeprom_list_action =
2223         TOKEN_STRING_INITIALIZER(struct cmd_eeprom_list_result, action,
2224                                  str_eeprom_list_list);
2225
2226 const char PROGMEM help_eeprom_list[] = "list all eeprom init commands";
2227 const parse_inst_t PROGMEM cmd_eeprom_list = {
2228         .f = cmd_eeprom_list_parsed,  /* function to call */
2229         .data = NULL,      /* 2nd arg of func */
2230         .help_str = help_eeprom_list,
2231         .tokens = {        /* token list, NULL terminated */
2232                 (PGM_P)&cmd_eeprom_list_cmd,
2233                 (PGM_P)&cmd_eeprom_list_action,
2234                 NULL,
2235         },
2236 };
2237
2238
2239 /* ************* */
2240
2241 /* in progmem */
2242 const parse_ctx_t PROGMEM main_ctx[] = {
2243
2244         /* commands_gen.c */
2245         &cmd_reset,
2246         &cmd_bootloader,
2247         &cmd_log,
2248         &cmd_log_show,
2249         &cmd_log_type,
2250         &cmd_stack_space,
2251         &cmd_callout,
2252         &cmd_help,
2253         &cmd_neigh_del,
2254         &cmd_neigh_add,
2255         &cmd_neigh_list,
2256         &cmd_read,
2257         &cmd_write_none,
2258         &cmd_write_u8,
2259         &cmd_write_u16,
2260         &cmd_write_u32,
2261         &cmd_sendmsg,
2262         &cmd_sendmsg_name,
2263         &cmd_range,
2264         &cmd_range_period,
2265         &cmd_range_count,
2266         &cmd_range_powermask,
2267         &cmd_range_dstaddr,
2268         &cmd_monitor,
2269         &cmd_monitor_period,
2270         &cmd_monitor_add,
2271         &cmd_monitor_del,
2272         &cmd_ping,
2273         &cmd_raw,
2274         &cmd_baudrate,
2275         &cmd_beep,
2276         &cmd_servo_set,
2277         &cmd_servo_bypassppm,
2278         &cmd_servo_show,
2279         &cmd_test_spi,
2280         &cmd_dump_xbee_stats,
2281         &cmd_rc_proto_stats,
2282         &cmd_rc_proto_timers,
2283         &cmd_rc_proto_timers_show,
2284         &cmd_rc_proto_mode,
2285         &cmd_rc_proto_mode2,
2286         &cmd_rc_proto_mode3,
2287         &cmd_rc_proto_hello,
2288         &cmd_rc_proto_hello_name,
2289         &cmd_rc_proto_echo,
2290         &cmd_rc_proto_echo_name,
2291         &cmd_test_eeprom_config,
2292         &cmd_eeprom_del,
2293         &cmd_eeprom_add,
2294         &cmd_eeprom_add2,
2295         &cmd_eeprom_list,
2296         NULL,
2297 };