init
authorOlivier Matz <zer0@droids-corp.org>
Fri, 17 Feb 2012 17:21:19 +0000 (18:21 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Fri, 17 Feb 2012 17:21:19 +0000 (18:21 +0100)
21 files changed:
commands.c [new file with mode: 0644]
main.c [new file with mode: 0644]
main.h [new file with mode: 0644]
parse_atcmd.c [new file with mode: 0644]
parse_atcmd.h [new file with mode: 0644]
parse_monitor.c [new file with mode: 0644]
parse_monitor.h [new file with mode: 0644]
parse_neighbor.c [new file with mode: 0644]
parse_neighbor.h [new file with mode: 0644]
xbee.c [new file with mode: 0644]
xbee.h [new file with mode: 0644]
xbee_atcmd.c [new file with mode: 0644]
xbee_atcmd.h [new file with mode: 0644]
xbee_buf.c [new file with mode: 0644]
xbee_buf.h [new file with mode: 0644]
xbee_neighbor.c [new file with mode: 0644]
xbee_neighbor.h [new file with mode: 0644]
xbee_proto.c [new file with mode: 0644]
xbee_proto.h [new file with mode: 0644]
xbee_stats.c [new file with mode: 0644]
xbee_stats.h [new file with mode: 0644]

diff --git a/commands.c b/commands.c
new file mode 100644 (file)
index 0000000..a12ed42
--- /dev/null
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/queue.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+
+#include <event.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_file.h>
+#include <cmdline.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_atcmd.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee_proto.h"
+#include "xbee.h"
+#include "parse_atcmd.h"
+#include "parse_neighbor.h"
+#include "parse_monitor.h"
+#include "main.h"
+
+static struct monitor_reg_list monitor_list = LIST_HEAD_INITIALIZER(x/*XXX*/);
+static int monitor_period_ms = 1000;
+static int monitor_running = 0;
+static int monitor_count = 0;
+static struct event monitor_event;
+struct monitor_reg *monitor_current;
+
+static int range_period_ms = 1000;
+static int range_powermask = 0x1F;
+static uint8_t range_power = 0;
+static int range_running = 0;
+static uint64_t range_dstaddr = 0xFFFF; /* broadcast by default */
+static struct event range_event;
+static int range_count = 100;
+static int range_cur_count = 0;
+
+static const char *xbee_logfilename = "/tmp/xbee.log";
+
+static void monitor_cb(int s, short event, void *arg)
+{
+       struct timeval tv;
+       struct cmdline *cl = arg;
+
+       if (monitor_current == NULL)
+               monitor_current = LIST_FIRST(&monitor_list);
+
+       xbeeapp_send_atcmd(monitor_current->atcmd, NULL, 0, 0);
+       monitor_current = LIST_NEXT(monitor_current, next);
+
+       evtimer_set(&monitor_event, monitor_cb, cl);
+       tv.tv_sec = 0;
+       tv.tv_usec = (1000 * monitor_period_ms) / monitor_count;
+       evtimer_add(&monitor_event, &tv);
+}
+
+static void range_cb(int s, short event, void *arg)
+{
+       struct timeval tv;
+       struct cmdline *cl = arg;
+       char buf[16];
+       uint8_t i, mask;
+
+       range_cur_count--;
+
+       /* get new xmit power */
+       for (i = 1; i <= 8; i++) {
+               mask = 1 << ((range_power + i) & 0x7);
+               if (mask & range_powermask)
+                       break;
+       }
+       range_power = ((range_power + i) & 0x7);
+
+       xbeeapp_send_atcmd("PL", &range_power, sizeof(range_power), 0);
+       snprintf(buf, sizeof(buf), "range%d", range_power);
+       xbeeapp_send_msg(range_dstaddr, buf, strlen(buf), 0);
+
+       if (range_cur_count == 0) {
+               range_running = 0;
+               return;
+       }
+
+       evtimer_set(&range_event, range_cb, cl);
+       tv.tv_sec = 0;
+       tv.tv_usec = 1000 * range_period_ms;
+       evtimer_add(&range_event, &tv);
+}
+
+/* ************* */
+
+/* this structure is filled when cmd_stats is parsed successfully */
+struct cmd_stats_result {
+       cmdline_fixed_string_t stats;
+       cmdline_fixed_string_t action;
+};
+
+/* function called when cmd_stats is parsed successfully */
+static void cmd_stats_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+       struct cmd_stats_result *res = parsed_result;
+
+       if (!strcmp(res->action, "show")) {
+               xbee_dump_stats(stdout, xbee_dev);
+               if (xbee_logfile != NULL)
+                       xbee_dump_stats(xbee_logfile, xbee_dev);
+       }
+       else if (!strcmp(res->action, "reset"))
+               xbee_reset_stats(xbee_dev);
+}
+
+cmdline_parse_token_string_t cmd_stats_stats =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_result, stats, "stats");
+cmdline_parse_token_string_t cmd_stats_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_result, action, "show#reset");
+
+cmdline_parse_inst_t cmd_stats = {
+       .f = cmd_stats_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Send a stats to the xbee device",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_stats_stats,
+               (void *)&cmd_stats_action,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_monitor is parsed successfully */
+struct cmd_monitor_result {
+       cmdline_fixed_string_t monitor;
+       cmdline_fixed_string_t action;
+};
+
+/* function called when cmd_monitor is parsed successfully */
+static void cmd_monitor_parsed(void *parsed_result, struct cmdline *cl,
+                              void *data)
+{
+       struct cmd_monitor_result *res = parsed_result;
+       struct monitor_reg *m;
+
+       if (!strcmp(res->action, "show")) {
+               printf("monitor period is %d ms, %d regs in list\n",
+                      monitor_period_ms, monitor_count);
+               LIST_FOREACH(m, &monitor_list, next)
+                       printf(" %s\n", m->desc);
+       }
+       else if (!strcmp(res->action, "start")) {
+               struct timeval tv;
+               if (monitor_running) {
+                       printf("already running\n");
+                       return;
+               }
+               if (monitor_count == 0) {
+                       printf("no regs to be monitored\n");
+                       return;
+               }
+               evtimer_set(&monitor_event, monitor_cb, cl);
+               tv.tv_sec = 0;
+               tv.tv_usec = 0;
+               evtimer_add(&monitor_event, &tv);
+               monitor_running = 1;
+               monitor_current = LIST_FIRST(&monitor_list);
+       }
+       else if (!strcmp(res->action, "end")) {
+               if (monitor_running == 0) {
+                       printf("not running\n");
+                       return;
+               }
+               monitor_running = 0;
+               evtimer_del(&monitor_event);
+       }
+}
+
+cmdline_parse_token_string_t cmd_monitor_monitor =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_result, monitor, "monitor");
+cmdline_parse_token_string_t cmd_monitor_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_result, action,
+                                "show#start#end");
+
+cmdline_parse_inst_t cmd_monitor = {
+       .f = cmd_monitor_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "start/stop/show current monitoring",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_monitor_monitor,
+               (void *)&cmd_monitor_action,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_monitor_add is parsed successfully */
+struct cmd_monitor_add_result {
+       cmdline_fixed_string_t monitor;
+       cmdline_fixed_string_t action;
+       struct xbee_atcmd *cmd;
+};
+
+/* function called when cmd_monitor_add is parsed successfully */
+static void cmd_monitor_add_parsed(void *parsed_result, struct cmdline *cl,
+                                  void *data)
+{
+       struct cmd_monitor_add_result *res = parsed_result;
+       struct monitor_reg *m;
+
+       LIST_FOREACH(m, &monitor_list, next) {
+               if (!strcmp(m->desc, res->cmd->desc))
+                       break;
+       }
+
+       if (m != NULL) {
+               printf("already exist\n");
+               return;
+       }
+
+       m = malloc(sizeof(*m));
+       if (m == NULL) {
+               printf("no mem\n");
+               return;
+       }
+
+       m->desc = res->cmd->desc;
+       m->atcmd = res->cmd->name;
+       LIST_INSERT_HEAD(&monitor_list, m, next);
+       monitor_count ++;
+}
+
+cmdline_parse_token_string_t cmd_monitor_add_monitor_add =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_add_result, monitor,
+                                "monitor");
+cmdline_parse_token_string_t cmd_monitor_add_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_add_result, action,
+                                "add");
+parse_token_atcmd_t cmd_monitor_add_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_monitor_add_result, cmd, &xbee_dev,
+                               XBEE_ATCMD_F_READ, XBEE_ATCMD_F_READ);
+
+
+cmdline_parse_inst_t cmd_monitor_add = {
+       .f = cmd_monitor_add_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "add a register in monitor list",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_monitor_add_monitor_add,
+               (void *)&cmd_monitor_add_action,
+               (void *)&cmd_monitor_add_atcmd,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_monitor_period is parsed successfully */
+struct cmd_monitor_period_result {
+       cmdline_fixed_string_t monitor;
+       cmdline_fixed_string_t action;
+       uint32_t period;
+};
+
+/* function called when cmd_monitor_period is parsed successfully */
+static void cmd_monitor_period_parsed(void *parsed_result, struct cmdline *cl,
+                                  void *data)
+{
+       struct cmd_monitor_period_result *res = parsed_result;
+
+       if (res->period < 100) {
+               printf("error, minimum period is 100 ms\n");
+               return;
+       }
+
+       monitor_period_ms = res->period;
+}
+
+cmdline_parse_token_string_t cmd_monitor_period_monitor_period =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_period_result, monitor,
+                                "monitor");
+cmdline_parse_token_string_t cmd_monitor_period_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_period_result, action,
+                                "period");
+cmdline_parse_token_num_t cmd_monitor_period_period =
+       TOKEN_NUM_INITIALIZER(struct cmd_monitor_period_result, period, UINT32);
+
+
+cmdline_parse_inst_t cmd_monitor_period = {
+       .f = cmd_monitor_period_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "set register monitoring period",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_monitor_period_monitor_period,
+               (void *)&cmd_monitor_period_action,
+               (void *)&cmd_monitor_period_period,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_monitor_del is parsed successfully */
+struct cmd_monitor_del_result {
+       cmdline_fixed_string_t monitor;
+       cmdline_fixed_string_t action;
+       struct monitor_reg *m;
+};
+
+/* function called when cmd_monitor_del is parsed successfully */
+static void cmd_monitor_del_parsed(void *parsed_result, struct cmdline *cl,
+                                  void *data)
+{
+       struct cmd_monitor_del_result *res = parsed_result;
+
+       monitor_current = LIST_NEXT(res->m, next);
+       LIST_REMOVE(res->m, next);
+       free(res->m);
+       monitor_count --;
+       if (monitor_count == 0) {
+               printf("Disable monitoring, no more event\n");
+               evtimer_del(&monitor_event);
+               monitor_running = 0;
+               return;
+       }
+}
+
+cmdline_parse_token_string_t cmd_monitor_del_monitor_del =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_del_result, monitor,
+                                "monitor");
+cmdline_parse_token_string_t cmd_monitor_del_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_monitor_del_result, action,
+                                "del");
+parse_token_monitor_t cmd_monitor_del_atcmd =
+       TOKEN_MONITOR_INITIALIZER(struct cmd_monitor_del_result, m,
+                                 &monitor_list);
+
+
+cmdline_parse_inst_t cmd_monitor_del = {
+       .f = cmd_monitor_del_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "del a register in monitor list",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_monitor_del_monitor_del,
+               (void *)&cmd_monitor_del_action,
+               (void *)&cmd_monitor_del_atcmd,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_range is parsed successfully */
+struct cmd_range_result {
+       cmdline_fixed_string_t range;
+       cmdline_fixed_string_t action;
+};
+
+/* function called when cmd_range is parsed successfully */
+static void cmd_range_parsed(void *parsed_result, struct cmdline *cl,
+                              void *data)
+{
+       struct cmd_range_result *res = parsed_result;
+
+       if (!strcmp(res->action, "show")) {
+               printf("range infos:\n");
+               printf("  range period %d\n", range_period_ms);
+               printf("  range count %d\n", range_count);
+               printf("  range powermask 0x%x\n", range_powermask);
+               printf("  range dstaddr %"PRIx64"\n", range_dstaddr);
+               if (range_running)
+                       printf("  range test is running\n");
+               else
+                       printf("  range test is not running\n");
+       }
+       else if (!strcmp(res->action, "start")) {
+               struct timeval tv;
+               if (range_running) {
+                       printf("already running\n");
+                       return;
+               }
+               range_cur_count = range_count;
+               evtimer_set(&range_event, range_cb, cl);
+               tv.tv_sec = 0;
+               tv.tv_usec = 0;
+               evtimer_add(&range_event, &tv);
+               range_running = 1;
+       }
+       else if (!strcmp(res->action, "end")) {
+               if (range_running == 0) {
+                       printf("not running\n");
+                       return;
+               }
+               range_running = 0;
+               evtimer_del(&range_event);
+       }
+}
+
+cmdline_parse_token_string_t cmd_range_range =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_result, range, "range");
+cmdline_parse_token_string_t cmd_range_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_result, action,
+                                "show#start#end");
+
+cmdline_parse_inst_t cmd_range = {
+       .f = cmd_range_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "start/stop/show current rangeing",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_range_range,
+               (void *)&cmd_range_action,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_range_period is parsed successfully */
+struct cmd_range_period_result {
+       cmdline_fixed_string_t range;
+       cmdline_fixed_string_t action;
+       uint32_t period;
+};
+
+/* function called when cmd_range_period is parsed successfully */
+static void cmd_range_period_parsed(void *parsed_result, struct cmdline *cl,
+                                  void *data)
+{
+       struct cmd_range_period_result *res = parsed_result;
+
+       if (res->period < 10) {
+               printf("error, minimum period is 10 ms\n");
+               return;
+       }
+
+       range_period_ms = res->period;
+}
+
+cmdline_parse_token_string_t cmd_range_period_range_period =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_period_result, range,
+                                "range");
+cmdline_parse_token_string_t cmd_range_period_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_period_result, action,
+                                "period");
+cmdline_parse_token_num_t cmd_range_period_period =
+       TOKEN_NUM_INITIALIZER(struct cmd_range_period_result, period, UINT32);
+
+
+cmdline_parse_inst_t cmd_range_period = {
+       .f = cmd_range_period_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "set range test period",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_range_period_range_period,
+               (void *)&cmd_range_period_action,
+               (void *)&cmd_range_period_period,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_range_count is parsed successfully */
+struct cmd_range_count_result {
+       cmdline_fixed_string_t range;
+       cmdline_fixed_string_t action;
+       uint32_t count;
+};
+
+/* function called when cmd_range_count is parsed successfully */
+static void cmd_range_count_parsed(void *parsed_result, struct cmdline *cl,
+                                  void *data)
+{
+       struct cmd_range_count_result *res = parsed_result;
+       range_count = res->count;
+}
+
+cmdline_parse_token_string_t cmd_range_count_range_count =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_count_result, range,
+                                "range");
+cmdline_parse_token_string_t cmd_range_count_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_count_result, action,
+                                "count");
+cmdline_parse_token_num_t cmd_range_count_count =
+       TOKEN_NUM_INITIALIZER(struct cmd_range_count_result, count, UINT32);
+
+
+cmdline_parse_inst_t cmd_range_count = {
+       .f = cmd_range_count_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "set range test count",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_range_count_range_count,
+               (void *)&cmd_range_count_action,
+               (void *)&cmd_range_count_count,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_range_powermask is parsed successfully */
+struct cmd_range_powermask_result {
+       cmdline_fixed_string_t range;
+       cmdline_fixed_string_t action;
+       uint8_t powermask;
+};
+
+/* function called when cmd_range_powermask is parsed successfully */
+static void cmd_range_powermask_parsed(void *parsed_result, struct cmdline *cl,
+                                  void *data)
+{
+       struct cmd_range_powermask_result *res = parsed_result;
+       range_powermask = res->powermask;
+}
+
+cmdline_parse_token_string_t cmd_range_powermask_range_powermask =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_powermask_result, range,
+                                "range");
+cmdline_parse_token_string_t cmd_range_powermask_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_powermask_result, action,
+                                "powermask");
+cmdline_parse_token_num_t cmd_range_powermask_powermask =
+       TOKEN_NUM_INITIALIZER(struct cmd_range_powermask_result, powermask,
+                             UINT8);
+
+
+cmdline_parse_inst_t cmd_range_powermask = {
+       .f = cmd_range_powermask_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "set range test powermask",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_range_powermask_range_powermask,
+               (void *)&cmd_range_powermask_action,
+               (void *)&cmd_range_powermask_powermask,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_range_dstaddr is parsed successfully */
+struct cmd_range_dstaddr_result {
+       cmdline_fixed_string_t range;
+       cmdline_fixed_string_t action;
+       uint64_t dstaddr;
+};
+
+/* function called when cmd_range_dstaddr is parsed successfully */
+static void cmd_range_dstaddr_parsed(void *parsed_result, struct cmdline *cl,
+                                    void *data)
+{
+       struct cmd_range_dstaddr_result *res = parsed_result;
+
+       range_dstaddr = res->dstaddr;
+}
+
+cmdline_parse_token_string_t cmd_range_dstaddr_range_dstaddr =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_dstaddr_result, range,
+                                "range");
+cmdline_parse_token_string_t cmd_range_dstaddr_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_range_dstaddr_result, action,
+                                "dstaddr");
+cmdline_parse_token_num_t cmd_range_dstaddr_dstaddr =
+       TOKEN_NUM_INITIALIZER(struct cmd_range_dstaddr_result, dstaddr, UINT64);
+
+
+cmdline_parse_inst_t cmd_range_dstaddr = {
+       .f = cmd_range_dstaddr_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "set register rangeing dstaddr",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_range_dstaddr_range_dstaddr,
+               (void *)&cmd_range_dstaddr_action,
+               (void *)&cmd_range_dstaddr_dstaddr,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_ping is parsed successfully */
+struct cmd_ping_result {
+       cmdline_fixed_string_t ping;
+};
+
+/* function called when cmd_ping is parsed successfully */
+static void cmd_ping_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+       xbeeapp_send_atcmd("VL", NULL, 0, 1);
+}
+
+cmdline_parse_token_string_t cmd_ping_ping =
+       TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping, "ping");
+
+cmdline_parse_inst_t cmd_ping = {
+       .f = cmd_ping_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Send a ping to the xbee device",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_ping_ping,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_raw is parsed successfully */
+struct cmd_raw_result {
+       cmdline_fixed_string_t raw;
+};
+
+/* function called when cmd_raw is parsed successfully */
+static void cmd_raw_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+       printf("switched to raw mode, CTRL-D to exit\n");
+       rdline_stop(&cl->rdl); /* don't display prompt when return */
+       xbee_raw = 1;
+}
+
+cmdline_parse_token_string_t cmd_raw_raw =
+       TOKEN_STRING_INITIALIZER(struct cmd_raw_result, raw, "raw");
+
+cmdline_parse_inst_t cmd_raw = {
+       .f = cmd_raw_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Switch to raw mode",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_raw_raw,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_dump is parsed successfully */
+struct cmd_dump_result {
+       cmdline_fixed_string_t dump;
+       cmdline_fixed_string_t onoff;
+};
+
+/* function called when cmd_dump is parsed successfully */
+static void cmd_dump_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+       struct cmd_dump_result *res = parsed_result;
+       if (!strcmp(res->onoff, "on"))
+               xbee_hexdump = 1;
+       else
+               xbee_hexdump = 0;
+}
+
+cmdline_parse_token_string_t cmd_dump_dump =
+       TOKEN_STRING_INITIALIZER(struct cmd_dump_result, dump, "dump");
+
+cmdline_parse_token_string_t cmd_dump_onoff =
+       TOKEN_STRING_INITIALIZER(struct cmd_dump_result, onoff, "on#off");
+
+cmdline_parse_inst_t cmd_dump = {
+       .f = cmd_dump_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "enable/disable hexdump of received packets",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_dump_dump,
+               (void *)&cmd_dump_onoff,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_debug is parsed successfully */
+struct cmd_debug_result {
+       cmdline_fixed_string_t debug;
+       cmdline_fixed_string_t onoff;
+};
+
+/* function called when cmd_debug is parsed successfully */
+static void cmd_debug_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+       struct cmd_debug_result *res = parsed_result;
+       if (!strcmp(res->onoff, "on"))
+               xbee_debug = 1;
+       else
+               xbee_debug = 0;
+}
+
+cmdline_parse_token_string_t cmd_debug_debug =
+       TOKEN_STRING_INITIALIZER(struct cmd_debug_result, debug, "debug");
+
+cmdline_parse_token_string_t cmd_debug_onoff =
+       TOKEN_STRING_INITIALIZER(struct cmd_debug_result, onoff, "on#off");
+
+cmdline_parse_inst_t cmd_debug = {
+       .f = cmd_debug_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "enable/disable additionnal debug",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_debug_debug,
+               (void *)&cmd_debug_onoff,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_help is parsed successfully */
+struct cmd_help_result {
+       cmdline_fixed_string_t help;
+       struct xbee_atcmd *cmd;
+};
+
+/* function called when cmd_help is parsed successfully */
+static void cmd_help_parsed(void *parsed_result, struct cmdline *cl,
+                           void *data)
+{
+       struct cmd_help_result *res = parsed_result;
+       int type;
+
+       type = (res->cmd->flags & (XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE));
+       switch (type) {
+               case XBEE_ATCMD_F_READ:
+                       printf("Read-only\n");
+                       break;
+               case XBEE_ATCMD_F_WRITE:
+                       printf("Write-only\n");
+                       break;
+               default:
+                       printf("Read-write\n");
+                       break;
+       }
+       if (res->cmd->flags & XBEE_ATCMD_F_PARAM_NONE)
+               printf("No argument\n");
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_U8)
+               printf("Register is unsigned 8 bits\n");
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_U16)
+               printf("Register is unsigned 16 bits\n");
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_U32)
+               printf("Register is unsigned 32 bits\n");
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_S16)
+               printf("Register is signed 16 bits\n");
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_STRING_20B)
+               printf("Register is a 20 bytes string\n");
+       else
+               printf("Unknown argument\n");
+
+       printf("%s\n", res->cmd->help);
+}
+
+cmdline_parse_token_string_t cmd_help_help =
+       TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
+
+parse_token_atcmd_t cmd_help_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_help_result, cmd, &xbee_dev,
+                               0, 0);
+
+cmdline_parse_inst_t cmd_help = {
+       .f = cmd_help_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Help a register using an AT command",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_help_help,
+               (void *)&cmd_help_atcmd,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_read is parsed successfully */
+struct cmd_read_result {
+       cmdline_fixed_string_t read;
+       struct xbee_atcmd *cmd;
+};
+
+/* function called when cmd_read is parsed successfully */
+static void cmd_read_parsed(void *parsed_result, struct cmdline *cl,
+                           void *data)
+{
+       struct cmd_read_result *res = parsed_result;
+       xbeeapp_send_atcmd(res->cmd->name, NULL, 0, 1);
+}
+
+cmdline_parse_token_string_t cmd_read_read =
+       TOKEN_STRING_INITIALIZER(struct cmd_read_result, read, "read");
+
+parse_token_atcmd_t cmd_read_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_read_result, cmd, &xbee_dev,
+                               XBEE_ATCMD_F_READ, XBEE_ATCMD_F_READ);
+
+cmdline_parse_inst_t cmd_read = {
+       .f = cmd_read_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Read a register using an AT command",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_read_read,
+               (void *)&cmd_read_atcmd,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_write is parsed successfully */
+struct cmd_write_result {
+       cmdline_fixed_string_t write;
+       struct xbee_atcmd *cmd;
+       union {
+               uint8_t u8;
+               uint16_t u16;
+               uint32_t u32;
+       };
+};
+
+/* function called when cmd_write is parsed successfully */
+static void cmd_write_parsed(void *parsed_result, struct cmdline *cl,
+                            void *data)
+{
+       struct cmd_write_result *res = parsed_result;
+       int len;
+       void *param;
+
+       if (res->cmd->flags & XBEE_ATCMD_F_PARAM_NONE) {
+               len = 0;
+               param = NULL;
+       }
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_U8) {
+               len = sizeof(res->u8);
+               param = &res->u8;
+       }
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_U16) {
+               len = sizeof(res->u16);
+               res->u16 = htons(res->u16);
+               param = &res->u16;
+       }
+       else if (res->cmd->flags & XBEE_ATCMD_F_PARAM_U32) {
+               len = sizeof(res->u32);
+               res->u32 = htonl(res->u32);
+               param = &res->u32;
+       }
+       else {
+               printf("Unknown argument type\n");
+               return;
+       }
+       xbeeapp_send_atcmd(res->cmd->name, param, len, 1);
+}
+
+cmdline_parse_token_string_t cmd_write_write =
+       TOKEN_STRING_INITIALIZER(struct cmd_write_result, write,
+                                "write");
+
+parse_token_atcmd_t cmd_write_none_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
+                               &xbee_dev,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_NONE,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_NONE);
+
+cmdline_parse_inst_t cmd_write_none = {
+       .f = cmd_write_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Send an AT command (no argument)",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_write_write,
+               (void *)&cmd_write_none_atcmd,
+               NULL,
+       },
+};
+
+parse_token_atcmd_t cmd_write_u8_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
+                               &xbee_dev,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U8,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U8);
+
+cmdline_parse_token_num_t cmd_write_u8_u8 =
+       TOKEN_NUM_INITIALIZER(struct cmd_write_result, u8, UINT8);
+
+cmdline_parse_inst_t cmd_write_u8 = {
+       .f = cmd_write_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Write a 8 bits register using an AT command",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_write_write,
+               (void *)&cmd_write_u8_atcmd,
+               (void *)&cmd_write_u8_u8,
+               NULL,
+       },
+};
+
+parse_token_atcmd_t cmd_write_u16_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
+                               &xbee_dev,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U16,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U16);
+
+cmdline_parse_token_num_t cmd_write_u16_u16 =
+       TOKEN_NUM_INITIALIZER(struct cmd_write_result, u16, UINT16);
+
+cmdline_parse_inst_t cmd_write_u16 = {
+       .f = cmd_write_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Write a 16 bits register using an AT command",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_write_write,
+               (void *)&cmd_write_u16_atcmd,
+               (void *)&cmd_write_u16_u16,
+               NULL,
+       },
+};
+
+parse_token_atcmd_t cmd_write_u32_atcmd =
+       TOKEN_ATCMD_INITIALIZER(struct cmd_write_result, cmd,
+                               &xbee_dev,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U32,
+                               XBEE_ATCMD_F_WRITE | XBEE_ATCMD_F_PARAM_U32);
+
+cmdline_parse_token_num_t cmd_write_u32_u32 =
+       TOKEN_NUM_INITIALIZER(struct cmd_write_result, u32, UINT32);
+
+cmdline_parse_inst_t cmd_write_u32 = {
+       .f = cmd_write_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Write a 32 bits register using an AT command",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_write_write,
+               (void *)&cmd_write_u32_atcmd,
+               (void *)&cmd_write_u32_u32,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_sendmsg is parsed successfully */
+struct cmd_sendmsg_result {
+       cmdline_fixed_string_t sendmsg;
+       uint64_t addr;
+       cmdline_fixed_string_t data;
+};
+
+/* function called when cmd_sendmsg is parsed successfully */
+static void cmd_sendmsg_parsed(void *parsed_result, struct cmdline *cl,
+                           void *data)
+{
+       struct cmd_sendmsg_result *res = parsed_result;
+       xbeeapp_send_msg(res->addr, res->data, strlen(res->data), 1);
+}
+
+cmdline_parse_token_string_t cmd_sendmsg_sendmsg =
+       TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_result, sendmsg, "sendmsg");
+
+cmdline_parse_token_num_t cmd_sendmsg_addr =
+       TOKEN_NUM_INITIALIZER(struct cmd_sendmsg_result, addr, UINT64);
+
+cmdline_parse_token_string_t cmd_sendmsg_data =
+       TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_result, data, NULL);
+
+cmdline_parse_inst_t cmd_sendmsg = {
+       .f = cmd_sendmsg_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Send data to a node using its address",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_sendmsg_sendmsg,
+               (void *)&cmd_sendmsg_addr,
+               (void *)&cmd_sendmsg_data,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_sendmsg_name is parsed successfully */
+struct cmd_sendmsg_name_result {
+       cmdline_fixed_string_t sendmsg_name;
+       struct xbee_neigh *neigh;
+       cmdline_fixed_string_t data;
+};
+
+/* function called when cmd_sendmsg_name is parsed successfully */
+static void cmd_sendmsg_name_parsed(void *parsed_result, struct cmdline *cl,
+                           void *data)
+{
+       struct cmd_sendmsg_name_result *res = parsed_result;
+       xbeeapp_send_msg(res->neigh->addr, res->data, strlen(res->data), 1);
+}
+
+cmdline_parse_token_string_t cmd_sendmsg_name_sendmsg_name =
+       TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_name_result, sendmsg_name,
+                                "sendmsg");
+
+parse_token_neighbor_t cmd_sendmsg_name_neigh =
+       TOKEN_NEIGHBOR_INITIALIZER(struct cmd_sendmsg_name_result, neigh,
+                                  &xbee_dev);
+
+cmdline_parse_token_string_t cmd_sendmsg_name_data =
+       TOKEN_STRING_INITIALIZER(struct cmd_sendmsg_name_result, data, NULL);
+
+cmdline_parse_inst_t cmd_sendmsg_name = {
+       .f = cmd_sendmsg_name_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "Send data to a node using its name",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_sendmsg_name_sendmsg_name,
+               (void *)&cmd_sendmsg_name_neigh,
+               (void *)&cmd_sendmsg_name_data,
+               NULL,
+       },
+};
+
+/* ************* */
+
+struct cmd_neigh_del_result {
+       cmdline_fixed_string_t cmd;
+       cmdline_fixed_string_t action;
+       struct xbee_neigh *neigh;
+};
+
+static void cmd_neigh_del_parsed(void *parsed_result,
+                               struct cmdline *cl,
+                               void *data)
+{
+       struct cmd_neigh_del_result *res = parsed_result;
+       xbee_neigh_del(xbee_dev, res->neigh);
+}
+
+cmdline_parse_token_string_t cmd_neigh_del_cmd =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_del_result, cmd, "neigh");
+cmdline_parse_token_string_t cmd_neigh_del_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_del_result, action, "del");
+parse_token_neighbor_t cmd_neigh_del_neigh =
+       TOKEN_NEIGHBOR_INITIALIZER(struct cmd_neigh_del_result, neigh,
+                                  &xbee_dev);
+
+cmdline_parse_inst_t cmd_neigh_del = {
+       .f = cmd_neigh_del_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "delete a neighbor",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_neigh_del_cmd,
+               (void *)&cmd_neigh_del_action,
+               (void *)&cmd_neigh_del_neigh,
+               NULL,
+       },
+};
+
+/* ************* */
+
+struct cmd_neigh_add_result {
+       cmdline_fixed_string_t cmd;
+       cmdline_fixed_string_t action;
+       cmdline_fixed_string_t name;
+       uint64_t addr;
+};
+
+static void cmd_neigh_add_parsed(void *parsed_result,
+                               struct cmdline *cl,
+                               void *data)
+{
+       struct cmd_neigh_add_result *res = parsed_result;
+       if (xbee_neigh_add(xbee_dev, res->name, res->addr) == NULL)
+               printf("name or addr already exist\n");
+}
+
+cmdline_parse_token_string_t cmd_neigh_add_cmd =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_add_result, cmd, "neigh");
+cmdline_parse_token_string_t cmd_neigh_add_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_add_result, action, "add");
+cmdline_parse_token_string_t cmd_neigh_add_name =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_add_result, name, NULL);
+cmdline_parse_token_num_t cmd_neigh_add_addr =
+       TOKEN_NUM_INITIALIZER(struct cmd_neigh_add_result, addr, UINT64);
+
+cmdline_parse_inst_t cmd_neigh_add = {
+       .f = cmd_neigh_add_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "add a neighbor",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_neigh_add_cmd,
+               (void *)&cmd_neigh_add_action,
+               (void *)&cmd_neigh_add_name,
+               (void *)&cmd_neigh_add_addr,
+               NULL,
+       },
+};
+
+/* ************* */
+
+struct cmd_neigh_list_result {
+       cmdline_fixed_string_t cmd;
+       cmdline_fixed_string_t action;
+};
+
+static void cmd_neigh_list_parsed(void *parsed_result,
+                               struct cmdline *cl,
+                               void *data)
+{
+       struct xbee_neigh *neigh;
+
+       LIST_FOREACH(neigh, &xbee_dev->neigh_list, next) {
+               printf(" %s: 0x%"PRIx64"\n", neigh->name, neigh->addr);
+       }
+}
+
+cmdline_parse_token_string_t cmd_neigh_list_cmd =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_list_result, cmd, "neigh");
+cmdline_parse_token_string_t cmd_neigh_list_action =
+       TOKEN_STRING_INITIALIZER(struct cmd_neigh_list_result, action, "list");
+
+cmdline_parse_inst_t cmd_neigh_list = {
+       .f = cmd_neigh_list_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "list all known neighbors",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_neigh_list_cmd,
+               (void *)&cmd_neigh_list_action,
+               NULL,
+       },
+};
+
+/*******************/
+
+struct cmd_logfile_result {
+       cmdline_fixed_string_t logfile;
+       cmdline_filename_t file;
+};
+
+static void cmd_logfile_parsed(void *parsed_result,
+                              struct cmdline *cl,
+                              void *data)
+{
+       if (xbee_logfile != NULL)
+               fclose(xbee_logfile);
+       xbee_logfile = fopen(xbee_logfilename, "a");
+       if (xbee_logfile == NULL)
+               printf("cannot open file: %s\n", strerror(errno));
+       fprintf(xbee_logfile, "-------------------start\n");
+       printf("enabling log\n");
+}
+
+cmdline_parse_token_string_t cmd_logfile_logfile =
+       TOKEN_STRING_INITIALIZER(struct cmd_logfile_result, logfile, "logfile");
+
+cmdline_parse_token_file_t cmd_logfile_file =
+       TOKEN_FILE_INITIALIZER(struct cmd_logfile_result, file,
+                              PARSE_FILE_F_CREATE);
+
+cmdline_parse_inst_t cmd_logfile = {
+       .f = cmd_logfile_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "<logfile FILE> set log file",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_logfile_logfile,
+               (void *)&cmd_logfile_file,
+               NULL,
+       },
+};
+
+/* ************* */
+
+/* this structure is filled when cmd_log is parsed successfully */
+struct cmd_log_result {
+       cmdline_fixed_string_t log;
+       cmdline_fixed_string_t onoff;
+};
+
+/* function called when cmd_log is parsed successfully */
+static void cmd_log_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+       struct cmd_log_result *res = parsed_result;
+       if (!strcmp(res->onoff, "on") && xbee_logfile == NULL) {
+               xbee_logfile = fopen(xbee_logfilename, "a");
+               if (xbee_logfile == NULL)
+                       printf("cannot open file: %s\n", strerror(errno));
+               fprintf(xbee_logfile, "-------------------start\n");
+       }
+       else if (!strcmp(res->onoff, "off") && xbee_logfile != NULL) {
+               fclose(xbee_logfile);
+               xbee_logfile = NULL;
+       }
+}
+
+cmdline_parse_token_string_t cmd_log_log =
+       TOKEN_STRING_INITIALIZER(struct cmd_log_result, log, "log");
+
+cmdline_parse_token_string_t cmd_log_onoff =
+       TOKEN_STRING_INITIALIZER(struct cmd_log_result, onoff, "on#off");
+
+cmdline_parse_inst_t cmd_log = {
+       .f = cmd_log_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "enable/disable hexlog of received packets",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_log_log,
+               (void *)&cmd_log_onoff,
+               NULL,
+       },
+};
+
+
+/*******************/
+
+struct cmd_saveconfig_result {
+       cmdline_fixed_string_t saveconfig;
+       cmdline_filename_t file;
+};
+
+static void cmd_saveconfig_parsed(void *parsed_result,
+                              struct cmdline *cl,
+                              void *data)
+{
+       struct cmd_saveconfig_result *res = parsed_result;
+
+       if (xbeeapp_dump_config(res->file) < 0)
+               printf("cannot save config\n");
+}
+
+cmdline_parse_token_string_t cmd_saveconfig_saveconfig =
+       TOKEN_STRING_INITIALIZER(struct cmd_saveconfig_result, saveconfig,
+                                "saveconfig");
+
+cmdline_parse_token_file_t cmd_saveconfig_file =
+       TOKEN_FILE_INITIALIZER(struct cmd_saveconfig_result, file,
+                              PARSE_FILE_F_CREATE);
+
+cmdline_parse_inst_t cmd_saveconfig = {
+       .f = cmd_saveconfig_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "<saveconfig FILE> set log file",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_saveconfig_saveconfig,
+               (void *)&cmd_saveconfig_file,
+               NULL,
+       },
+};
+
+/*******************/
+
+struct cmd_loadconfig_result {
+       cmdline_fixed_string_t loadconfig;
+       cmdline_filename_t file;
+};
+
+static void cmd_loadconfig_parsed(void *parsed_result,
+                              struct cmdline *cl,
+                              void *data)
+{
+}
+
+cmdline_parse_token_string_t cmd_loadconfig_loadconfig =
+       TOKEN_STRING_INITIALIZER(struct cmd_loadconfig_result, loadconfig,
+                                "loadconfig");
+
+cmdline_parse_token_file_t cmd_loadconfig_file =
+       TOKEN_FILE_INITIALIZER(struct cmd_loadconfig_result, file,
+                              PARSE_FILE_F_CREATE);
+
+cmdline_parse_inst_t cmd_loadconfig = {
+       .f = cmd_loadconfig_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "<loadconfig FILE> set log file",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_loadconfig_loadconfig,
+               (void *)&cmd_loadconfig_file,
+               NULL,
+       },
+};
+
+/**********************************************************/
+/**********************************************************/
+/****** CONTEXT (list of instruction) */
+
+/* in progmem */
+cmdline_parse_ctx_t main_ctx = {
+       .name = "main",
+       .insts = {
+               &cmd_stats,
+               &cmd_monitor,
+               &cmd_monitor_period,
+               &cmd_monitor_add,
+               &cmd_monitor_del,
+               &cmd_range,
+               &cmd_range_period,
+               &cmd_range_count,
+               &cmd_range_powermask,
+               &cmd_range_dstaddr,
+               &cmd_ping,
+               &cmd_raw,
+               &cmd_dump,
+               &cmd_debug,
+               &cmd_help,
+               &cmd_read,
+               &cmd_write_none,
+               &cmd_write_u8,
+               &cmd_write_u16,
+               &cmd_write_u32,
+               &cmd_sendmsg,
+               &cmd_sendmsg_name,
+               &cmd_neigh_del,
+               &cmd_neigh_add,
+               &cmd_neigh_list,
+               &cmd_logfile,
+               &cmd_log,
+               &cmd_saveconfig,
+               &cmd_loadconfig,
+               NULL,
+       },
+};
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..52c0d80
--- /dev/null
+++ b/main.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _BSD_SOURCE /* for be64toh, endian.h */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <termios.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <endian.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <sys/queue.h>
+
+#include <getopt.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include <event.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_atcmd.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee_proto.h"
+#include "xbee.h"
+#include "main.h"
+
+#define TIMEOUT_US 1000000
+
+/* XXX qd on deconnecte, prend 100% du cpu */
+/* XXX rmt at cmd */
+/* XXX neighbor discovery */
+/* XXX dump et restauration de la config */
+
+/* global xbee device */
+static int xbeeapp_dump_conf_continue(struct xbee_ctx *ctx,
+                                     struct xbee_atresp_hdr *frame,
+                                     unsigned len);
+
+struct xbee_dev *xbee_dev;
+
+/* events */
+static struct event stdin_read_event, xbee_read_event;
+
+static struct cmdline *xbee_cl;
+
+/* parameters */
+static char *xbee_devname = NULL;
+static int xbee_baud = 9600;
+int xbee_raw = 0;
+int xbee_hexdump = 0;
+int xbee_debug = 0;
+FILE *xbee_logfile;
+
+void xbeeapp_log(int always_on_stdout, const char *fmt, ...)
+{
+       va_list ap, ap2;
+
+       va_start(ap, fmt);
+       va_copy(ap2, ap);
+       if (xbee_logfile != NULL)
+               vfprintf(xbee_logfile, fmt, ap);
+       if (always_on_stdout || xbee_debug)
+               vprintf(fmt, ap2);
+       va_end(ap2);
+       va_end(ap);
+}
+
+static void hexdump(int always_on_stdout, const char *title, const void *buf,
+                   unsigned int len)
+{
+       unsigned int i, out, ofs;
+       const unsigned char *data = buf;
+#define LINE_LEN 80
+       char line[LINE_LEN];    /* space needed 8+16*3+3+16 == 75 */
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       xbeeapp_log(always_on_stdout, "%"PRIi64".%.6d %s at [%p], len=%d\n",
+                   (uint64_t)tv.tv_sec, (int)tv.tv_usec, title, data, len);
+       ofs = 0;
+       while (ofs < len) {
+               /* format 1 line in the buffer, then use printk to print them */
+               out = snprintf(line, LINE_LEN, "%08X", ofs);
+               for (i=0; ofs+i < len && i<16; i++)
+                       out += snprintf(line+out, LINE_LEN - out, " %02X",
+                                       data[ofs+i]&0xff);
+               for (;i<=16;i++)
+                       out += snprintf(line+out, LINE_LEN - out, "   ");
+               for (i=0; ofs < len && i<16; i++, ofs++) {
+                       unsigned char c = data[ofs];
+                       if (!isascii(c) || !isprint(c))
+                               c = '.';
+                       out += snprintf(line+out, LINE_LEN - out, "%c", c);
+               }
+               xbeeapp_log(always_on_stdout, "%s\n", line);
+       }
+}
+
+static int parse_xmit_status(struct xbee_ctx *ctx,
+                            struct xbee_xmit_status_hdr *frame, unsigned len)
+{
+       if (ctx == NULL) {
+               xbeeapp_log(1, "no context\n");
+               return -1;
+       }
+
+       /* see if it matches a xmit query */
+       if (ctx->type != SEND_MSG) {
+               xbeeapp_log(ctx->foreground, "invalid response\n");
+               return -1;
+       }
+
+       /* XXX use defines for these values */
+       if (frame->delivery_status == 0x00)
+               xbeeapp_log(ctx->foreground, "Success\n");
+       else if (frame->delivery_status == 0x01)
+               xbeeapp_log(ctx->foreground, "MAC ACK Failure\n");
+       else if (frame->delivery_status == 0x15)
+               xbeeapp_log(ctx->foreground, "Invalid destination endpoint\n");
+       else if (frame->delivery_status == 0x21)
+               xbeeapp_log(ctx->foreground, "Network ACK Failure\n");
+       else if (frame->delivery_status == 0x25)
+               xbeeapp_log(ctx->foreground, "Route Not Found\n");
+
+       return 0;
+}
+
+static int atcmd_frame_status(struct xbee_atresp_hdr *frame, unsigned len)
+{
+       char atcmd_str[3];
+
+       /* get AT command from frame */
+       memcpy(atcmd_str, &frame->cmd, 2);
+       atcmd_str[2] = '\0';
+
+       if (frame->status == 1)
+               xbeeapp_log(1, "<%s>: Status is error\n", atcmd_str);
+       else if (frame->status == 2)
+               xbeeapp_log(1, "<%s>: Invalid command\n", atcmd_str);
+       else if (frame->status == 3)
+               xbeeapp_log(1, "<%s>: Invalid parameter\n", atcmd_str);
+       else if (frame->status != 0)
+               xbeeapp_log(1, "<%s>: Unknown status error %d\n", atcmd_str,
+                      frame->status);
+       return frame->status;
+}
+
+/* assume frame->status is 0 */
+static int atcmd_frame_to_string(struct xbee_atresp_hdr *frame, unsigned len,
+                                char *dstbuf, unsigned dstlen)
+{
+       union {
+               uint8_t u8;
+               uint16_t u16;
+               uint32_t u32;
+               int16_t s16;
+       } __attribute__((packed)) *result;
+       char atcmd_str[3];
+       struct xbee_atcmd *cmd;
+
+       /* get AT command from frame */
+       memcpy(atcmd_str, &frame->cmd, 2);
+       atcmd_str[2] = '\0';
+
+       /* see if it exists */
+       cmd = xbee_atcmd_lookup_name(atcmd_str);
+       if (cmd == NULL) {
+               xbeeapp_log(1, "unknown response\n");
+               return -1;
+       }
+
+       /* dump frame */
+       result = (void *)frame->data;
+       len -= offsetof(struct xbee_atresp_hdr, data);
+       if (cmd->flags & XBEE_ATCMD_F_PARAM_NONE && len == 0)
+               snprintf(dstbuf, dstlen, "ok");
+       if (cmd->flags & XBEE_ATCMD_F_PARAM_U8 && len == sizeof(uint8_t))
+               snprintf(dstbuf, dstlen, "0x%x", result->u8);
+       else if (cmd->flags & XBEE_ATCMD_F_PARAM_U16 && len == sizeof(uint16_t))
+               snprintf(dstbuf, dstlen, "0x%x", ntohs(result->u16));
+       else if (cmd->flags & XBEE_ATCMD_F_PARAM_U32 && len == sizeof(uint32_t))
+               snprintf(dstbuf, dstlen, "0x%x", ntohl(result->u32));
+       else if (cmd->flags & XBEE_ATCMD_F_PARAM_S16 && len == sizeof(int16_t))
+               snprintf(dstbuf, dstlen, "%d\n", ntohs(result->s16));
+       else
+               return -1;
+
+       return 0;
+}
+
+static int dump_atcmd(struct xbee_ctx *ctx, struct xbee_atresp_hdr *frame,
+                     unsigned len)
+{
+       char buf[32];
+
+       /* see if it matches query */
+       if (memcmp(&frame->cmd, ctx->atcmd_query->name, 2)) {
+               printf("invalid response\n");
+               return -1;
+       }
+
+       /* dump frame */
+       if (atcmd_frame_status(frame, len) == 0) {
+
+               if (len == sizeof(struct xbee_atresp_hdr))
+                       xbeeapp_log(ctx->foreground, "<%s>: ok\n",
+                                   ctx->atcmd_query->name);
+               else if (atcmd_frame_to_string(frame, len, buf,
+                                             sizeof(buf)) == 0)
+                       xbeeapp_log(ctx->foreground, "<%s> is %s\n",
+                                   ctx->atcmd_query->name, buf);
+               else
+                       hexdump(ctx->foreground, "atcmd answer", frame, len);
+       }
+       return 0;
+}
+
+void xbee_rx(struct xbee_dev *dev, int channel, int type,
+            void *frame, unsigned len, void *opaque)
+{
+       struct xbee_ctx *ctx = opaque;
+       int do_hexdump = xbee_hexdump;
+
+       xbeeapp_log(0, "type=0x%x, channel=%d, ctx=%p\n", type, channel, ctx);
+       hexdump(0, "rx", frame, len);
+
+       /* if ctx is !NULL, it is an answer to a query */
+       if (ctx != NULL) {
+               /* XXX only delete timeout if answer matched */
+               xbee_unload_timeout(ctx);
+               if (xbee_debug && ctx->atcmd_query != NULL)
+                       printf("Received answer to query <%s>\n",
+                              ctx->atcmd_query->name);
+               xbee_unregister_channel(dev, channel);
+       }
+
+       /* some additional checks before sending */
+       switch (type) {
+               case XBEE_TYPE_MODEM_STATUS: {
+                       printf("Received Modem Status frame\n");
+                       break;
+               }
+
+               case XBEE_TYPE_RMT_ATRESP: {
+                       uint64_t addr;
+                       memcpy(&addr, frame, sizeof(addr));
+                       addr = be64toh(addr);
+                       printf("from remote address %"PRIx64"\n", addr);
+
+                       /* this answer contains an atcmd answer at offset 10 */
+                       if (ctx != NULL && ctx->type == ATCMD_RMT) {
+                               if (dump_atcmd(ctx, frame + 10, len - 10) < 0)
+                                       do_hexdump = 1;
+                       }
+                       else {
+                               printf("invalid response\n");
+                               do_hexdump = 1;
+                       }
+                       break;
+               }
+               case XBEE_TYPE_ATRESP: {
+                       /* we are currently dumping config, continue */
+                       if (ctx != NULL && ctx->type == DUMP_CONF) {
+                               xbeeapp_dump_conf_continue(ctx, frame, len);
+                       }
+                       else if (ctx != NULL && ctx->type == ATCMD) {
+                               if (dump_atcmd(ctx, frame, len) < 0)
+                                       do_hexdump = 1;
+                       }
+                       else {
+                               printf("invalid response\n");
+                               do_hexdump = 1;
+                       }
+                       break;
+               }
+
+               case XBEE_TYPE_XMIT_STATUS: {
+                       if (parse_xmit_status(ctx, frame, len) < 0)
+                               do_hexdump = 1;
+                       break;
+               }
+
+               case XBEE_TYPE_RECV: {
+                       struct xbee_recv_hdr *recvframe = frame;
+                       int recvlen = len - sizeof(*recvframe);
+                       int on_stdout = 1;
+
+                       /* if we receive a range-test frame, ask for RSSI now */
+                       if (recvlen >= strlen("range") &&
+                           !strncmp((char *)recvframe->data,
+                                    "range", strlen("range"))) {
+                               xbeeapp_send_atcmd("DB", NULL, 0, 0);
+                               on_stdout = 0;
+                       }
+                       hexdump(on_stdout, "rx data", recvframe->data,
+                               recvlen);
+                       break;
+               }
+
+               case XBEE_TYPE_ATCMD:
+               case XBEE_TYPE_ATCMD_Q:
+               case XBEE_TYPE_XMIT:
+               case XBEE_TYPE_EXPL_XMIT:
+               case XBEE_TYPE_RMT_ATCMD:
+               case XBEE_TYPE_EXPL_RECV:
+               case XBEE_TYPE_NODE_ID:
+               default:
+                       xbeeapp_log(0, "Invalid frame\n");
+                       do_hexdump = 1;
+                       break;
+       }
+
+       if (do_hexdump) {
+               xbeeapp_log(1, "rx frame type=0x%x, channel=%d, ctx=%p\n",
+                           type, channel, ctx);
+               hexdump(1, "undecoded rx frame", frame, len);
+       }
+
+       /* restart command line if it was a blocking query */
+       if (ctx != NULL) {
+               if (ctx->foreground && !ctx->have_more_command) {
+                       xbee_stdin_enable();
+                       rdline_newline(&xbee_cl->rdl, xbee_cl->prompt);
+               }
+               if (!ctx->have_more_command)
+                       free(ctx);
+       }
+}
+
+static int xbeeapp_send(struct xbee_ctx *ctx, int type, void *buf, unsigned len,
+                       int foreground)
+{
+       int ret;
+       int channel;
+
+       if (len > XBEE_MAX_FRAME_LEN) {
+               printf("frame too large\n");
+               return -1;
+       }
+
+       /* register a channel */
+       channel = xbee_register_channel(xbee_dev, XBEE_CHANNEL_ANY,
+                                       xbee_rx, ctx);
+       if (channel < 0) {
+               printf("cannot send: no free channel\n");
+               return -1;
+       }
+
+       xbeeapp_log(0, "send frame ctx=%p channel=%d type=0x%x len=%d\n",
+              ctx, channel, type, len);
+       hexdump(0, "xmit frame", buf, len);
+
+       /* transmit the frame on this channel */
+       ret = xbee_proto_xmit(xbee_dev, channel, type, buf,
+                             len);
+       if (ret < 0) {
+               printf("cannot send: %s\n", strerror(errno));
+               xbee_unregister_channel(xbee_dev, channel);
+               return -1;
+       }
+
+       ctx->channel = channel;
+       xbee_load_timeout(ctx);   /* load a timeout event */
+
+       /* suspend command line until we have answer or timeout */
+       if (foreground) {
+               ctx->foreground = 1;
+               rdline_stop(&xbee_cl->rdl); /* don't display prompt when return */
+               xbee_stdin_disable();  /* unload file descriptor polling */
+       }
+
+       return 0;
+}
+
+/* send an AT command with parameters filled by caller. Disable
+ * command line until we get the answer or until a timeout occurs */
+int xbeeapp_send_atcmd(const char *atcmd_str, void *param, unsigned param_len,
+                      int foreground)
+{
+       struct xbee_ctx *ctx;
+       struct xbee_atcmd *cmd;
+       struct {
+               struct xbee_atcmd_hdr atcmd;
+               char buf[XBEE_MAX_FRAME_LEN];
+       } __attribute__((packed)) frame;
+
+       cmd = xbee_atcmd_lookup_name(atcmd_str);
+       if (cmd == NULL) {
+               printf("no such at command\n");
+               return -1;
+       }
+
+       /* allocate memory to store the context for async cb */
+       ctx = malloc(sizeof(*ctx));
+       if (ctx == NULL) {
+               printf("not enough memory\n");
+               return -1;
+       }
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->type = ATCMD;
+       ctx->atcmd_query = cmd;
+
+       memcpy(&frame.atcmd.cmd, atcmd_str, 2);
+       memcpy(&frame.buf, param, param_len);
+
+       if (xbeeapp_send(ctx, XBEE_TYPE_ATCMD, &frame,
+                        sizeof(struct xbee_atcmd_hdr) +
+                        param_len, foreground) < 0) {
+               free(ctx);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* dump config */
+static int __xbeeapp_dump_config(struct xbee_ctx *ctx, struct xbee_atcmd *cmd)
+{
+       struct xbee_atcmd_hdr atcmd;
+
+       /* find the first command that is readable and writable */
+       for (; cmd->name != NULL; cmd++) {
+               if ((cmd->flags & (XBEE_ATCMD_F_READ|XBEE_ATCMD_F_WRITE)) ==
+                   (XBEE_ATCMD_F_READ|XBEE_ATCMD_F_WRITE))
+                       break;
+       }
+       if (cmd->name == NULL) {
+               printf("no register to dump\n");
+               return -1;
+       }
+
+       ctx->atcmd_query = cmd;
+       ctx->have_more_command = 1;
+       memcpy(&atcmd.cmd, cmd->name, 2);
+
+       if (xbeeapp_send(ctx, XBEE_TYPE_ATCMD, &atcmd,
+                        sizeof(struct xbee_atcmd_hdr), 1) < 0) {
+               return -1;
+       }
+
+       return 0;
+}
+
+/* dump config */
+int xbeeapp_dump_config(const char *filename)
+{
+       struct xbee_ctx *ctx;
+       struct xbee_atcmd *cmd;
+       int ret;
+
+       /* find the first command that is readable and writable */
+       cmd = &xbee_atcmd_list[0];
+
+       /* allocate memory to store the context for async cb */
+       ctx = malloc(sizeof(*ctx));
+       if (ctx == NULL) {
+               printf("not enough memory\n");
+               return -1;
+       }
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->type = DUMP_CONF;
+       ret = __xbeeapp_dump_config(ctx, cmd);
+
+       if (ret < 0)
+               free(ctx);
+       return ret;
+}
+
+/* continue a dump conf */
+static int xbeeapp_dump_conf_continue(struct xbee_ctx *ctx,
+                                     struct xbee_atresp_hdr *frame,
+                                     unsigned len)
+{
+       struct xbee_atcmd *cmd;
+       char buf[32];
+
+       /* see if it matches query */
+       if (memcmp(&frame->cmd, ctx->atcmd_query->name, 2)) {
+               printf("invalid response\n");
+               ctx->have_more_command = 0;
+               return -1;
+       }
+
+       /* dump register content in buf, skip on error */
+       if (atcmd_frame_status(frame, len) == 0 &&
+           atcmd_frame_to_string(frame, len, buf, sizeof(buf)) == 0)
+               printf("write %s %s\n", ctx->atcmd_query->desc, buf);
+
+       cmd = ctx->atcmd_query + 1;
+       if (__xbeeapp_dump_config(ctx, cmd) < 0) {
+               ctx->have_more_command = 0;
+               //close(xbee_config_file);
+               printf("END\n"); /* XXX */
+       }
+       return 0;
+}
+
+/* send data message */
+int xbeeapp_send_msg(uint64_t addr, void *data, unsigned data_len,
+                    int foreground)
+{
+       struct xbee_ctx *ctx;
+       struct {
+               struct xbee_xmit_hdr xmit;
+               char buf[XBEE_MAX_FRAME_LEN];
+       } __attribute__((packed)) frame;
+
+       /* allocate memory to store the context for async cb */
+       ctx = malloc(sizeof(*ctx));
+       if (ctx == NULL) {
+               printf("not enough memory\n");
+               return -1;
+       }
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->type = SEND_MSG;
+       ctx->atcmd_query = NULL;
+
+       frame.xmit.dstaddr = htobe64(addr);
+       frame.xmit.reserved = htons(0xFFFE);
+       frame.xmit.bcast_radius = 0;
+       frame.xmit.opts = 0;
+       memcpy(&frame.buf, data, data_len);
+
+       if (xbeeapp_send(ctx, XBEE_TYPE_XMIT, &frame,
+                        sizeof(struct xbee_xmit_hdr) +
+                        data_len, foreground) < 0) {
+               free(ctx);
+               return -1;
+       }
+
+       return 0;
+}
+
+void xbee_stdin_enable(void)
+{
+       event_add(&stdin_read_event, NULL);
+}
+
+void xbee_stdin_disable(void)
+{
+       event_del(&stdin_read_event);
+}
+
+static void evt_timeout(int s, short event, void *arg)
+{
+       struct xbee_ctx *ctx = arg;
+
+       xbeeapp_log(0, "Timeout\n");
+
+       /* restart command line */
+       if (ctx->foreground) {
+               if (xbee_debug == 0)
+                       printf("Timeout\n");
+               xbee_stdin_enable();
+               rdline_newline(&xbee_cl->rdl, xbee_cl->prompt);
+       }
+       /* free event */
+       xbee_unregister_channel(xbee_dev, ctx->channel);
+       free(ctx);
+}
+
+void xbee_load_timeout(struct xbee_ctx *ctx)
+{
+       struct timeval tv;
+
+       tv.tv_sec = 0;
+       tv.tv_usec = TIMEOUT_US;
+       evtimer_set(&ctx->timeout, evt_timeout, ctx);
+       evtimer_add(&ctx->timeout, &tv);
+}
+
+void xbee_unload_timeout(struct xbee_ctx *ctx)
+{
+       evtimer_del(&ctx->timeout);
+}
+
+static void
+evt_stdin_input(int s, short event, void *arg)
+{
+       char buf[2048];
+       int n;
+
+       n = read(s, buf, sizeof(buf));
+       if (n < 0) {
+               event_loopbreak();
+               return;
+       }
+
+       if (xbee_raw) {
+               int i;
+               for (i = 0; i < n; i++) {
+                       /* ctrl-d is pressed, back in cmdline mode XXX */
+                       if (buf[i] == 4) {
+                               xbee_raw = 0;
+                               n = i;
+                               rdline_newline(&xbee_cl->rdl, xbee_cl->prompt);
+                               break;
+                       }
+               }
+               /* XXX bad hack */
+               if (buf[0] == '\n')
+                       write(xbee_dev->fd, "\r\n", 2);
+               else
+                       write(xbee_dev->fd, buf, n);
+               write(s, buf, n);
+
+       }
+       else {
+               if (cmdline_in(xbee_cl, buf, n) < 0) {
+                       event_loopbreak();
+                       return;
+               }
+       }
+}
+
+static void
+evt_xbee_input(int s, short event, void *arg)
+{
+       if (xbee_raw) {
+               char buf[2048];
+               int n;
+
+               n = read(s, buf, sizeof(buf));
+               if (n < 0)
+                       return;
+
+               write(1, buf, n);
+       }
+       else {
+               xbee_read(xbee_dev);
+               xbee_process_queue(xbee_dev);
+       }
+}
+
+static void
+usage(const char *prgname)
+{
+       printf("%s [-s BAUD] -d DEVNAME\n"
+              "  -s BAUD:      set baud rate of xbee device\n"
+              "  -d DEVNAME:   xbee char device\n"
+              "  -r:           start in raw mode\n"
+              "\n",
+              prgname);
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+parse_args(int argc, char **argv)
+{
+       int opt, ret;
+       char **argvopt;
+       int option_index;
+       char *prgname = argv[0];
+       static struct option lgopts[] = {
+               {0, 0, 0, 0}
+       };
+
+       argvopt = argv;
+
+       while ((opt = getopt_long(argc, argvopt, "hd:s:",
+                                 lgopts, &option_index)) != EOF) {
+
+               switch (opt) {
+
+               case 'h':
+                       usage(prgname);
+                       exit(0);
+                       break;
+
+               case 'd':
+                       xbee_devname = strdup(optarg);
+                       break;
+
+               case 's':
+                       xbee_baud = atoi(optarg);
+                       break;
+
+               case 'r':
+                       xbee_raw = 1;
+                       break;
+
+               /* long options */
+               case 0:
+                       /* if (!strcmp(lgopts[option_index].name, "option")) */
+                       break;
+
+               default:
+                       usage(prgname);
+                       return -1;
+               }
+       }
+
+       if (xbee_devname == NULL) {
+               fprintf(stderr, "xbee device argument missing\n");
+               usage(prgname);
+               return -1;
+       }
+
+       if (argc != optind) {
+               printf("Invalid argument\n");
+               usage(prgname);
+               return -1;
+       }
+
+       ret = optind-1;
+
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       struct termios oldterm, term;
+       int err = 0;
+       const char *homedir;
+       char xbeerc_path[256];
+
+       if (parse_args(argc, argv) < 0)
+               exit(1);
+
+       /* initializa libevent */
+       event_init();
+
+       /* initialize libxbee */
+       err = xbee_init();
+       if (err < 0)
+               return -1;
+
+       /* open xbee device */
+       xbee_dev = xbee_open(xbee_devname, xbee_baud);
+       if (xbee_dev == NULL)
+               return -1;
+
+       /* register default channel with a callback */
+       if (xbee_register_channel(xbee_dev, XBEE_DEFAULT_CHANNEL,
+                                 xbee_rx, NULL) < 0) {
+               fprintf(stderr, "cannot register default channel\n");
+               return -1;
+       }
+
+       /* add read event on xbee device */
+       event_set(&xbee_read_event, xbee_dev->fd, EV_READ | EV_PERSIST,
+                 evt_xbee_input, xbee_dev);
+       event_add(&xbee_read_event, NULL);
+
+       /* set terminal in raw mode */
+       tcgetattr(0, &oldterm);
+       memcpy(&term, &oldterm, sizeof(term));
+       term.c_lflag &= ~(ICANON | ECHO | ISIG);
+       tcsetattr(0, TCSANOW, &term);
+       setbuf(stdin, NULL);
+
+       /* parse the config file */
+       homedir = getenv("HOME");
+       if (homedir != NULL) {
+               snprintf(xbeerc_path, sizeof(xbeerc_path), "%s/.xbeerc",
+                        homedir);
+               if (access(xbeerc_path, R_OK) == 0) {
+
+                       xbee_cl = cmdline_file_new(&main_ctx, "xbeerc> ",
+                                             "/home/zer0/.xbeerc", 1);
+                       if (xbee_cl != NULL) {
+                               cmdline_interact(xbee_cl);
+                               cmdline_free(xbee_cl);
+                               printf("\nconfig file parsed\n");
+                       }
+               }
+       }
+
+       /* create a new cmdline instance */
+       xbee_cl = cmdline_stdin_new(&main_ctx, "xbee> ");
+       if (xbee_cl == NULL) {
+               err = 1;
+               goto fail;
+       }
+
+       /* load read event on stdin */
+       event_set(&stdin_read_event, 0, EV_READ | EV_PERSIST,
+                 evt_stdin_input, xbee_cl);
+       event_add(&stdin_read_event, NULL);
+
+       /* libevent main loop */
+       event_dispatch();
+
+       tcsetattr(0, TCSANOW, &oldterm);
+       return 0;
+
+ fail:
+       tcsetattr(0, TCSANOW, &oldterm);
+       return err;
+}
diff --git a/main.h b/main.h
new file mode 100644 (file)
index 0000000..548cc62
--- /dev/null
+++ b/main.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+enum xbee_ctx_type {
+       SEND_MSG,
+       ATCMD,
+       ATCMD_RMT,
+       DUMP_CONF,
+};
+
+/* used for timeouts and xbee rx callback */
+struct xbee_ctx {
+       enum xbee_ctx_type type;
+       int have_more_command;
+       int foreground;
+       int channel;
+       struct event timeout;
+       struct xbee_atcmd *atcmd_query;
+};
+
+extern cmdline_parse_ctx_t main_ctx;
+extern struct xbee_dev *xbee_dev;
+extern int xbee_raw;
+extern int xbee_hexdump;
+extern int xbee_debug;
+extern FILE *xbee_logfile;
+
+#define XBEE_LOG_FILE "/home/zer0/xbee.log"
+extern FILE *xbee_log_file;
+
+void xbeeapp_log(int always_on_stdout, const char *fmt, ...);
+
+void xbee_rx(struct xbee_dev *dev, int channel, int type,
+            void *frame, unsigned len, void *opaque);
+int xbeeapp_send_atcmd(const char *atcmd_str, void *param, unsigned param_len,
+                      int foreground);
+int xbeeapp_send_msg(uint64_t addr, void *data, unsigned data_len,
+                    int foreground);
+int xbeeapp_dump_config(const char *filename);
+
+void xbee_stdin_enable(void);
+void xbee_stdin_disable(void);
+
+void xbee_load_timeout(struct xbee_ctx *ctx);
+void xbee_unload_timeout(struct xbee_ctx *ctx);
diff --git a/parse_atcmd.c b/parse_atcmd.c
new file mode 100644 (file)
index 0000000..ffde312
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse.h>
+
+#include "xbee_atcmd.h"
+#include "parse_atcmd.h"
+
+/* This file is an example of extension of libcmdline. It provides an
+ * example of named objects stored in a list, supporting the
+ * completion on objects name */
+
+static int
+parse_atcmd(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+           unsigned ressize)
+{
+       struct token_atcmd *tk2 = (struct token_atcmd *)tk;
+       struct token_atcmd_data *tkd = &tk2->atcmd_data;
+       struct xbee_atcmd *cmd;
+
+       if (res && ressize < sizeof(struct object *))
+               return -1;
+
+       /* XXX should be related to an xbee device */
+       cmd = xbee_atcmd_lookup_desc(buf);
+       if (cmd == NULL)
+               return -1;
+
+       /* command must match flags */
+       if ((cmd->flags & tkd->atcmd_mask) != tkd->atcmd_flags)
+               return -1;
+
+       /* store the address of object in structure */
+       if (res)
+               *(struct xbee_atcmd **)res = cmd;
+
+       return 0;
+}
+
+static int
+complete_atcmd_start(cmdline_parse_token_hdr_t *tk,
+                    __attribute__((unused)) const char *tokstr,
+                    void **opaque)
+{
+       struct xbee_atcmd *cmd;
+
+       cmd = &xbee_atcmd_list[0];
+       *opaque = (void *)cmd;
+       return 0;
+}
+
+static int
+complete_atcmd_iterate(cmdline_parse_token_hdr_t *tk, void **opaque,
+                      char *dstbuf, unsigned int size)
+{
+       struct token_atcmd *tk2 = (struct token_atcmd *)tk;
+       struct token_atcmd_data *tkd = &tk2->atcmd_data;
+       struct xbee_atcmd *cmd;
+       int len;
+
+       cmd = *opaque;
+
+       while (1) {
+               if (cmd->name == NULL)
+                       return -1;
+
+               /* skip commands that don't match flags */
+               if ((cmd->flags & tkd->atcmd_mask) != tkd->atcmd_flags) {
+                       cmd++;
+                       continue;
+               }
+
+               len = snprintf(dstbuf, size, "%s", cmd->desc);
+               if (len < 0 || len >= size)
+                       return -1;
+
+               strcpy(dstbuf, cmd->desc);
+               break;
+       }
+       cmd++;
+       *opaque = cmd;
+       return 0;
+}
+
+static int
+cmdline_help_atcmd(cmdline_parse_token_hdr_t *tk, char *dstbuf,
+                  unsigned int size)
+{
+       snprintf(dstbuf, size, "ATCMD");
+       return 0;
+}
+
+struct cmdline_token_ops token_atcmd_ops = {
+       .parse = parse_atcmd,
+       .complete_start = complete_atcmd_start,
+       .complete_iterate = complete_atcmd_iterate,
+       .complete_end = NULL,
+       .help = cmdline_help_atcmd,
+};
diff --git a/parse_atcmd.h b/parse_atcmd.h
new file mode 100644 (file)
index 0000000..657e7ec
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PARSE_ATCMD_H_
+#define _PARSE_ATCMD_H_
+
+#include <cmdline_parse.h>
+
+struct token_atcmd_data {
+       struct xbee_dev **xbee_dev;
+       unsigned atcmd_flags;
+       unsigned atcmd_mask;
+};
+
+struct token_atcmd {
+       struct cmdline_token_hdr hdr;
+       struct token_atcmd_data atcmd_data;
+};
+typedef struct token_atcmd parse_token_atcmd_t;
+
+extern struct cmdline_token_ops token_atcmd_ops;
+
+#define TOKEN_ATCMD_INITIALIZER(structure, field, dev, flags, mask)    \
+{                                                                      \
+       .hdr = {                                                        \
+               .ops = &token_atcmd_ops,                                \
+               .offset = offsetof(structure, field),                   \
+       },                                                              \
+       .atcmd_data = {                                                 \
+               .xbee_dev = dev,                                        \
+               .atcmd_flags = flags,                                   \
+               .atcmd_mask = mask,                                     \
+       },                                                              \
+}
+
+#endif /* _PARSE_ATCMD_H_ */
diff --git a/parse_monitor.c b/parse_monitor.c
new file mode 100644 (file)
index 0000000..19ecd0b
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse.h>
+
+#include "parse_monitor.h"
+
+static int
+parse_monitor(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+              unsigned ressize)
+{
+       struct token_monitor *tk2 = (struct token_monitor *)tk;
+       struct token_monitor_data *tkd = &tk2->monitor_data;
+       struct monitor_reg *m;
+
+       if (res && ressize < sizeof(struct monitor_reg *))
+               return -1;
+
+       LIST_FOREACH(m, tkd->list, next) {
+               if (strcmp(buf, m->desc))
+                       continue;
+               break;
+       }
+       if (m == NULL) /* not found */
+               return -1;
+
+       /* store the address of object in structure */
+       if (res)
+               *(struct monitor_reg **)res = m;
+
+       return 0;
+}
+
+static int
+complete_monitor_start(cmdline_parse_token_hdr_t *tk,
+                       __attribute__((unused)) const char *tokstr,
+                       void **opaque)
+{
+       struct token_monitor *tk2 = (struct token_monitor *)tk;
+       struct token_monitor_data *tkd = &tk2->monitor_data;
+       struct monitor_reg *m;
+
+       m = LIST_FIRST(tkd->list);
+       *opaque = (void *)m;
+       if (m == NULL)
+               return -1; /* no completion */
+       return 0;
+}
+
+static int
+complete_monitor_iterate(cmdline_parse_token_hdr_t *tk, void **opaque,
+                         char *dstbuf, unsigned int size)
+{
+       struct monitor_reg *m;
+       int len;
+
+       m = *opaque;
+       if (m == NULL)
+               return -1;
+
+       len = snprintf(dstbuf, size, "%s", m->desc);
+       if (len < 0 || len >= size)
+               return -1;
+
+       strcpy(dstbuf, m->desc);
+       m = LIST_NEXT(m, next);
+       *opaque = m;
+       return 0;
+}
+
+
+static int
+cmdline_help_monitor(cmdline_parse_token_hdr_t *tk, char *dstbuf,
+                     unsigned int size)
+{
+       snprintf(dstbuf, size, "Monitor-register");
+       return 0;
+}
+
+struct cmdline_token_ops token_monitor_ops = {
+       .parse = parse_monitor,
+       .complete_start = complete_monitor_start,
+       .complete_iterate = complete_monitor_iterate,
+       .complete_end = NULL,
+       .help = cmdline_help_monitor,
+};
diff --git a/parse_monitor.h b/parse_monitor.h
new file mode 100644 (file)
index 0000000..2f6ab62
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PARSE_MONITOR_H_
+#define _PARSE_MONITOR_H_
+
+#include <sys/queue.h>
+#include <cmdline_parse.h>
+
+struct monitor_reg {
+       LIST_ENTRY(monitor_reg) next;
+       const char *desc;
+       const char *atcmd;
+};
+
+LIST_HEAD(monitor_reg_list, monitor_reg);
+
+/* data is a pointer to a list */
+struct token_monitor_data {
+       struct monitor_reg_list *list;
+};
+
+struct token_monitor {
+       struct cmdline_token_hdr hdr;
+       struct token_monitor_data monitor_data;
+};
+typedef struct token_monitor parse_token_monitor_t;
+
+extern struct cmdline_token_ops token_monitor_ops;
+
+#define TOKEN_MONITOR_INITIALIZER(structure, field, monitor_ptr)  \
+{                                                                  \
+       .hdr = {                                                    \
+               .ops = &token_monitor_ops,                          \
+               .offset = offsetof(structure, field),               \
+       },                                                          \
+               .monitor_data = {                                   \
+               .list = monitor_ptr,                                \
+       },                                                          \
+}
+
+#endif /* _PARSE_MONITOR_H_ */
diff --git a/parse_neighbor.c b/parse_neighbor.c
new file mode 100644 (file)
index 0000000..0cba0ea
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <cmdline_parse.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_atcmd.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee_proto.h"
+#include "xbee.h"
+
+#include "parse_neighbor.h"
+
+static int
+parse_neighbor(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+              unsigned ressize)
+{
+       struct token_neighbor *tk2 = (struct token_neighbor *)tk;
+       struct token_neighbor_data *tkd = &tk2->neighbor_data;
+       struct xbee_dev *dev = *tkd->xbee_dev;
+       struct xbee_neigh *neigh;
+
+       if (res && ressize < sizeof(struct xbee_neigh *))
+               return -1;
+
+       neigh = xbee_neigh_lookup(dev, buf);
+       if (neigh == NULL) /* not found */
+               return -1;
+
+       /* store the address of xbee_neigh in structure */
+       if (res)
+               *(struct xbee_neigh **)res = neigh;
+
+       return 0;
+}
+
+static int
+complete_neighbor_start(cmdline_parse_token_hdr_t *tk,
+                       __attribute__((unused)) const char *tokstr,
+                       void **opaque)
+{
+       struct token_neighbor *tk2 = (struct token_neighbor *)tk;
+       struct token_neighbor_data *tkd = &tk2->neighbor_data;
+       struct xbee_dev *dev = *tkd->xbee_dev;
+       struct xbee_neigh *neigh;
+
+       neigh = LIST_FIRST(&dev->neigh_list);
+       *opaque = (void *)neigh;
+       if (neigh == NULL)
+               return -1; /* no completion */
+       return 0;
+}
+
+static int
+complete_neighbor_iterate(cmdline_parse_token_hdr_t *tk, void **opaque,
+                         char *dstbuf, unsigned int size)
+{
+       struct xbee_neigh *neigh;
+       int len;
+
+       neigh = *opaque;
+       if (neigh == NULL)
+               return -1;
+
+       len = snprintf(dstbuf, size, "%s", neigh->name);
+       if (len < 0 || len >= size)
+               return -1;
+
+       strcpy(dstbuf, neigh->name);
+       neigh = LIST_NEXT(neigh, next);
+       *opaque = neigh;
+       return 0;
+}
+
+
+static int
+cmdline_help_neighbor(cmdline_parse_token_hdr_t *tk, char *dstbuf,
+                     unsigned int size)
+{
+       snprintf(dstbuf, size, "Neighbor");
+       return 0;
+}
+
+struct cmdline_token_ops token_neighbor_ops = {
+       .parse = parse_neighbor,
+       .complete_start = complete_neighbor_start,
+       .complete_iterate = complete_neighbor_iterate,
+       .complete_end = NULL,
+       .help = cmdline_help_neighbor,
+};
diff --git a/parse_neighbor.h b/parse_neighbor.h
new file mode 100644 (file)
index 0000000..bdf84d9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PARSE_NEIGHBOR_H_
+#define _PARSE_NEIGHBOR_H_
+
+struct token_neighbor_data {
+       struct xbee_dev **xbee_dev;
+};
+
+struct token_neighbor {
+       struct cmdline_token_hdr hdr;
+       struct token_neighbor_data neighbor_data;
+};
+typedef struct token_neighbor parse_token_neighbor_t;
+
+extern struct cmdline_token_ops token_neighbor_ops;
+
+#define TOKEN_NEIGHBOR_INITIALIZER(structure, field, dev)              \
+       {                                                               \
+       .hdr = {                                                        \
+               .ops = &token_neighbor_ops,                             \
+               .offset = offsetof(structure, field),                   \
+       },                                                              \
+       .neighbor_data = {                                              \
+               .xbee_dev = dev,                                        \
+       },                                                              \
+}
+
+#endif /* _PARSE_NEIGHBOR_H_ */
diff --git a/xbee.c b/xbee.c
new file mode 100644 (file)
index 0000000..c4e8062
--- /dev/null
+++ b/xbee.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee_proto.h"
+#include "xbee.h"
+
+int xbee_init(void)
+{
+       return 0;
+}
+
+static int xbee_settermios(struct xbee_dev *dev)
+{
+       struct termios term;
+
+       memset(&term, 0, sizeof(term));
+       term.c_cflag = CREAD | HUPCL;
+
+       switch (dev->baud) {
+               case 50: term.c_cflag |= B50; break;
+               case 75: term.c_cflag |= B75; break;
+               case 110: term.c_cflag |= B110; break;
+               case 134: term.c_cflag |= B134; break;
+               case 150: term.c_cflag |= B150; break;
+               case 200: term.c_cflag |= B200; break;
+               case 300: term.c_cflag |= B300; break;
+               case 600: term.c_cflag |= B600; break;
+               case 1200: term.c_cflag |= B1200; break;
+               case 1800: term.c_cflag |= B1800; break;
+               case 2400: term.c_cflag |= B2400; break;
+               case 4800: term.c_cflag |= B4800; break;
+               case 9600: term.c_cflag |= B9600; break;
+               case 19200: term.c_cflag |= B19200; break;
+               case 38400: term.c_cflag |= B38400; break;
+               case 57600: term.c_cflag |= B57600; break;
+               case 115200: term.c_cflag |= B115200; break;
+               case 230400: term.c_cflag |= B230400; break;
+               default:
+                       fprintf(stderr, "invalid baudrate\n");
+                       return -1;
+       }
+
+       /* ignore modem control lines */
+       term.c_cflag |= CLOCAL;
+
+       /* non-canonical mode */
+       term.c_lflag &= ~ICANON;
+
+       /* minimum number of chars and minimum timeout for non-canonical read */
+       term.c_cc[VMIN] = 1;
+       term.c_cc[VTIME] = 0;
+
+#if 0
+       /* XXX later */
+       switch (dev->parity) {
+               case PARITY_ODD: term.c_cflag |= PARENB | PARODD; break;
+               case PARITY_EVEN: term.c_cflag |= PARENB; break;
+               default:                break;
+       }
+
+       if (twostopb)
+               term.c_cflag |= CSTOPB;
+
+       if (software)
+               term.c_iflag |= IXON | IXOFF;
+       if (hardware)
+               term.c_cflag |= CRTSCTS;
+
+#endif
+
+       if (tcsetattr(dev->fd, TCSAFLUSH, &term) < 0) {
+               fprintf(stderr, "ERROR: tcsetattr(TCSAFLUSH) failed: %s\n",
+                       strerror(errno));
+               return -1;
+       }
+       return(0);
+}
+
+int xbee_register_channel(struct xbee_dev *dev, int channel,
+                         xbee_rx_cb_t *rx_cb, void *opaque)
+{
+       /* user asked for any channel */
+       if (channel == XBEE_CHANNEL_ANY) {
+               int ch;
+
+               /* skip XBEE_DEFAULT_CHANNEL == 0 */
+               for (ch = 1; ch < XBEE_MAX_CHANNEL; ch++) {
+                       if (dev->channel[ch].registered == 0) {
+                               channel = ch;
+                               break;
+                       }
+               }
+               /* no available channels */
+               if (channel == XBEE_CHANNEL_ANY)
+                       return -1;
+       }
+       /* user requested a specific channel */
+       else if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
+                dev->channel[channel].registered == 1)
+               return -1; /* not available */
+
+       dev->channel[channel].registered = 1;
+       dev->channel[channel].rx_cb = rx_cb;
+       dev->channel[channel].arg = opaque;
+       return channel;
+}
+
+int xbee_unregister_channel(struct xbee_dev *dev, int channel)
+{
+       if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
+           dev->channel[channel].registered == 0)
+               return -1;
+       dev->channel[channel].registered = 0;
+       dev->channel[channel].rx_cb = NULL;
+       dev->channel[channel].arg = NULL;
+       return 0;
+}
+
+struct xbee_dev *xbee_open(const char *devname, unsigned baudrate)
+{
+       struct xbee_dev *dev;
+       int fd;
+
+       /* allocate structure for xbee device */
+       dev = malloc(sizeof(*dev));
+       if (dev == NULL) {
+               fprintf(stderr, "not enough memory\n");
+               return NULL;
+       }
+       memset(dev, 0, sizeof(*dev));
+
+       /* open the serial port */
+       fd = open(devname, O_NONBLOCK|O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "cannot open %s: %s\n", devname,
+                       strerror(errno));
+               free(dev);
+               return NULL;
+       }
+
+       /* set termios */
+       dev->baud = baudrate;
+       dev->fd = fd;
+       if (xbee_settermios(dev) < 0) {
+               close(fd);
+               free(dev);
+               return NULL;
+       }
+
+       dev->name = strdup(devname);
+       xbee_bufq_init(&dev->queue);
+       xbee_neigh_init(dev);
+
+       return dev;
+}
+
+/* read data from device fd and put it in queue */
+int xbee_read(struct xbee_dev *dev)
+{
+       struct xbee_buf *xbuf;
+       int n, tailroom, total = 0;
+       char *data;
+
+       do {
+               /* get an xbuf to store data */
+               xbuf = xbee_bufq_last(&dev->queue);
+               if (xbuf == NULL || xbee_buf_tailroom(xbuf) == 0) {
+                       xbuf = xbee_buf_alloc();
+
+                       if (xbuf == NULL) {
+                               fprintf(stderr, "FATAL: cannot allocate buffer\n");
+                               return -1;
+                       }
+
+                       /* put the xbuf in queue */
+                       xbee_buf_enqueue(&dev->queue, xbuf);
+               }
+
+               /* read data from char device */
+               tailroom = xbee_buf_tailroom(xbuf);
+               data = xbee_buf_tail(xbuf);
+               n = read(dev->fd, data, tailroom);
+
+               /* error in read */
+               if (n < 0) {
+                       fprintf(stderr, "read() failed: %s\n", strerror(errno));
+                       return -1;
+               }
+
+               /* update queue len and xbuf len */
+               xbee_bufq_append(&dev->queue, n);
+
+               total += n;
+
+       } while (n == tailroom);
+
+       return total;
+}
+
+/* process all data in queue */
+int xbee_process_queue(struct xbee_dev *dev)
+{
+       char buf[XBEE_MAX_FRAME_LEN];
+       int len, ret;
+
+       while (1) {
+               len = xbee_proto_get_frame(dev, buf, sizeof(buf));
+               if (len == 0) /* no more frame */
+                       break;
+
+               if (len < 0) {
+                       /* a frame was dropped... */
+                       fprintf(stderr, "xbee_proto_get_frame() failed\n");
+                       continue;
+               }
+
+               ret = xbee_proto_parse_frame(dev, buf, len);
+               if (ret < 0) {
+                       fprintf(stderr, "xbee_proto_parse_frame() failed\n");
+                       continue;
+               }
+       }
+
+       return 0;
+}
diff --git a/xbee.h b/xbee.h
new file mode 100644 (file)
index 0000000..e1cfbbd
--- /dev/null
+++ b/xbee.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Callback when receiving data on a specific channel. The arguments
+ * of the function are the xbee device, the channel ID, the type of
+ * the frame (example: XBEE_TYPE_ATRESP), the pointer to the frame,
+ * the length of the frame, and an opaque pointer (reserved for user) */
+typedef void (xbee_rx_cb_t)(struct xbee_dev *, int, int, void *,
+                           unsigned, void *);
+
+/* an xbee queue */
+struct xbee_channel {
+       int registered;
+       xbee_rx_cb_t *rx_cb;
+       void *arg;
+};
+
+#define XBEE_DEFAULT_CHANNEL 0
+#define XBEE_MAX_CHANNEL 16
+#define XBEE_CHANNEL_ANY XBEE_MAX_CHANNEL
+
+/* structure identifying a xbee device */
+struct xbee_dev {
+       const char *name;
+       int fd;
+       unsigned baud;
+       struct xbee_bufq queue;
+       struct xbee_channel channel[XBEE_MAX_CHANNEL];
+       struct xbee_stats stats;
+       struct xbee_neigh_list neigh_list;
+};
+
+/* initialize xbee library */
+int xbee_init(void);
+
+/* open an xbee device */
+struct xbee_dev *xbee_open(const char *devname, unsigned baudrate);
+
+/* closes an xbee device */
+int xbee_close(struct xbee_dev *dev);
+
+/* Register a channel, return the ID of the channel or a negative
+ * value on error. The rx_cb is a pointer to a function that will be
+ * called by xbee_read() when a frame is received for this channel. If
+ * rx_cb is NULL, no callback will occur. The "channel" argument can
+ * be XBEE_CHANNEL_ANY to let the library choose the channel, or a
+ * channel number to request a specific one. */
+int xbee_register_channel(struct xbee_dev *dev, int channel,
+                         xbee_rx_cb_t *rx_cb, void *opaque);
+
+/* Unregister a channel, return 0 on success */
+int xbee_unregister_channel(struct xbee_dev *dev, int channel_id);
+
+/* read data from device fd and put it in queue */
+int xbee_read(struct xbee_dev *dev);
+
+/* process all data in queue */
+int xbee_process_queue(struct xbee_dev *dev);
diff --git a/xbee_atcmd.c b/xbee_atcmd.c
new file mode 100644 (file)
index 0000000..91238f7
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "xbee_atcmd.h"
+
+struct xbee_atcmd xbee_atcmd_list[] = {
+       {
+               "WR",
+               "write-param",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Write parameter values to non-volatile memory.",
+       },
+       {
+               "RE",
+               "restore-defaults",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Restore module parameters to factory defaults.",
+       },
+       {
+               "FR",
+               "soft-reset",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Software Reset. Responds with 'OK' then performs a "
+               "reset 100ms later.",
+       },
+       {
+               "AC",
+               "apply-changes",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Apply Changes without exiting command mode.",
+       },
+       {
+               "R1",
+               "restore-compiled",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Restore module parameters to compiled defaults.",
+       },
+       {
+               "VL",
+               "version-long",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Shows detailed version information including"
+               "application build date and time.",
+       },
+       {
+               "DH",
+               "dst-addr-high",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Upper 32 bits of the 64-bit destination address (0 "
+               "to 0xFFFFFFFF, default is 0x0000FFFF).",
+       },
+       {
+               "DL",
+               "dst-addr-low",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Lower 32 bits of the 64-bit destination address (0 "
+               "to 0xFFFFFFFF, default is 0x0000FFFF).",
+       },
+       {
+               "DD",
+               "device-type-id",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+               "Device Type Identifier, it can be used to differentiate "
+               "multiple XBee-based products (0 to 0xFFFFFFFF, read-only, "
+               "default is 0x40000).",
+       },
+       {
+               "SH",
+               "src-addr-high",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+               "Upper 32 bits of the 64-bit source address (read-only).",
+       },
+       {
+               "SL",
+               "src-addr-low",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+               "Lower 32 bits of the 64-bit source address (read-only).",
+       },
+       {
+               "SE",
+               "src-endpoint",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "The application source endpoint for all data transmissions "
+               "(0 to 0xFF, default is 0xE8).",
+       },
+       {
+               "DE",
+               "dst-endpoint",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "The application destination endpoint for all data "
+               "transmissions (0 to 0xFF, default is 0xE8).",
+       },
+       {
+               "CI",
+               "cluster-id",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Cluster Identifier for all data transmissions (0 to 0xFFFF, "
+               "default is 0x11).",
+       },
+       {
+               "NP",
+               "max-rf-payload",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Maximum RF Payload Bytes that can be sent in a unicast "
+               "transmission based on the current configuration (0 to "
+               "0xFFFF).",
+       },
+       {
+               "CE",
+               "coord-end-device",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Coordinator/End Device, messaging mode of the module "
+               "(0 - Normal, 1 - Indirect coordinator, 2 - Polling, default "
+               "is 0).",
+       },
+       {
+               "AP",
+               "api-mode",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "API mode (0 - off, 1 - on, 2 - on with escape sequences).",
+       },
+       {
+               "AO",
+               "api-output-format",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "API Output Format (0 - standard [0x90 for RX], 1 - explicit "
+               "addressing [0x91 for RX]).",
+       },
+       {
+               "BD",
+               "baud-rate",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Baud rate of serial interface (0-8 select preset standard "
+               "rates, and 0x39 to 0x1c9c38 select baud rate).",
+       },
+       {
+               "RO",
+               "packetization-timeout",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Packetization Timeout: the inter-character silence required "
+               "before packetization specified in character times (0 to 0xFF, "
+               "default is 3).",
+       },
+       {
+               "FT",
+               "flow-control-thres",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Flow Control Threshhold. De-assert CTS and/or send XOFF when "
+               "FT bytes are in the UART receive buffer. Re-assert CTS when "
+               "less than FT - 16 bytes are in the UART receive buffer (0x11 "
+               "to 0xEE, default is 0xBE).",
+       },
+       {
+               "NB",
+               "parity",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Parity (0 - no parity, 1 - even parity, 2 - odd parity, 3 - "
+               "forced high parity, 4 - forced low parity). Default is 0.",
+       },
+       {
+               "D7",
+               "dio7",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO7 Configuration (0 - unmonitored input, 1 - CTS, 3 - "
+               "digital input, 4 - digital output low, 5 - digital output "
+               "high, 6 - RS-485 low Tx, 7 -  RS-485 high Tx). Default is "
+               "0.",
+       },
+       {
+               "D6",
+               "dio6",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO6 Configuration (0 - unmonitored input, 1 - RTS, 3 - "
+               "digital input, 4 - digital output low, 5 - digital output "
+               "high). Default is 0.",
+       },
+       {
+               "P0",
+               "dio10-pwm0",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO10/PWM0 Configuration. (0 - unmonitored input, 1 - RSSI, 2 "
+               "- PWM0, 3 - digital input, 4 - digital output low, 5 - "
+               "digital output high). Default is 1.",
+       },
+       {
+               "P1",
+               "dio11-pwm1",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO11/PWM1 Configuration. (0 - unmonitored input, 2 "
+               "- PWM1, 3 - digital input, 4 - digital output low, 5 - "
+               "digital output high). Default is 0.",
+       },
+       {
+               "P2",
+               "dio12",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO12 Configuration. (0 - unmonitored input, "
+               "3 - digital input, 4 - digital output low, 5 - "
+               "digital output high). Default is 0.",
+       },
+       {
+               "RP",
+               "rssi-pwm",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Time RSSI signal will be output after last transmission. "
+               "When RP = 0xFF, output will always be on (0 - 0xFF, default "
+               "is 0x28 = 4 seconds).",
+       },
+       {
+               "1S",
+               "sensor-sample",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Forces a sample to be taken on an XBee Sensor device.",
+       },
+       {
+               "D0",
+               "dio0-ad0",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "AD0/DIO0 Configuration. (0 - unmonitored input, 1 - "
+               "commission button enabled, 2 - analog input, 3 - digital "
+               "input, 4 - digital output low, 5 - digital output high). "
+               "Default is 1.",
+       },
+       {
+               "D1",
+               "dio1-ad1",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "AD1/DIO1 Configuration. (0 - unmonitored input, "
+               "2 - analog input, 3 - digital input, 4 - digital output "
+               "low, 5 - digital output high). Default is 0.",
+       },
+       {
+               "D2",
+               "dio2-ad2",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "AD2/DIO2 Configuration. (0 - unmonitored input, "
+               "2 - analog input, 3 - digital input, 4 - digital output "
+               "low, 5 - digital output high). Default is 0.",
+       },
+       {
+               "D3",
+               "dio3-ad3",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "AD3/DIO3 Configuration. (0 - unmonitored input, "
+               "2 - analog input, 3 - digital input, 4 - digital output "
+               "low, 5 - digital output high). Default is 0.",
+       },
+       {
+               "D4",
+               "dio4-ad4",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "AD4/DIO4 Configuration. (0 - unmonitored input, "
+               "2 - analog input, 3 - digital input, 4 - digital output "
+               "low, 5 - digital output high). Default is 0.",
+       },
+       {
+               "D5",
+               "dio5-ad5",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "AD4/DIO4 Configuration. (0 - unmonitored input, 1 - LED, "
+               "2 - analog input, 3 - digital input, 4 - digital output "
+               "low, 5 - digital output high). Default is 1.",
+       },
+       {
+               "D8",
+               "dio8-sleep-rq",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO8/SLEEP_RQ Configuration. (0 - unmonitored input, 1 - LED, "
+               "2 - analog input, 3 - digital input, 4 - digital output "
+               "low, 5 - digital output high). Default is 0. When used as "
+               "SLEEP_RQ, the D8 parameter should be configured in mode 0 "
+               "or 3.",
+       },
+       {
+               "D9",
+               "dio9-on-sleep",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "DIO9/ON_SLEEP Configuration. (0 - unmonitored input, 1 - "
+               "ON/SLEEP, 2 - analog input, 3 - digital input, 4 - digital "
+               "output low, 5 - digital output high). Default is ?.",
+       },
+       {
+               "PR",
+               "pull-up-resistor",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Pull-up Resistor. Bit field that configures the internal "
+               "pull-up resistors for the I/O lines (bit set = pull-up "
+               "enabled). Range is from 0 to 0x1FFF, default is 0x1FFF.",
+       },
+       {
+               "M0",
+               "pwm0-out-level",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "PWM0 Output Level. The line should be configured as a PWM "
+               "output using the P0 command (0 to 0x3FF, default is 0).",
+       },
+       {
+               "M1",
+               "pwm1-out-level",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "PWM1 Output Level. The line should be configured as a PWM "
+               "output using the P1 command (0 to 0x3FF, default is 0).",
+       },
+       {
+               "LT",
+               "led-blink-time",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Associate LED Blink Time (should be enabled through D5 "
+               "command). Range is 0x14-0xFF (x10ms), default is 0.",  },
+       {
+               "IS",
+               "force-sample",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Forces a read of all enabled digital and "
+               "analog input lines.",
+       },
+       {
+               "IC",
+               "digital-change-detect",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "I/O Digital Change Detection. If a pin is enabled as a "
+               "digital input/output, the IC command can be used to "
+               "force an immediate I/O sample transmission when the DIO "
+               "state changes. IC is a bitmask, range is 0 to 0xFFFF, "
+               "default is 0",
+       },
+       {
+               "IR",
+               "io-sample-rate",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "IO Sample Rate for periodic sampling. If zero, periodic "
+               "sampling is disabled. Else the value is in milliseconds "
+               "(range 0 to 0xFFFF, default is 0).",
+       },
+       {
+               "CB",
+               "comissioning-button",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Commissioning Pushbutton, simulate commissioning button "
+               "in software. The parameter value should be set to the number "
+               "of button presses to be simulated (range is 0 to 4).",
+       },
+       {
+               "VR",
+               "firmware-version",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+               "Firmware version of the module (read only).",
+       },
+       {
+               "HV",
+               "hardware-version",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Hardware version of the module (read only)."
+       },
+       {
+               "CK",
+               "config-code",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+               "Configuration Code, that can be used as a quick "
+               "check to determine if a node has been configured as "
+               "desired (read-only, 0-0xFFFFFFFF)."
+       },
+       {
+               "ER",
+               "rf-errors",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Number of times a packet was received which contained errors "
+               "of some sort. Read-only, saturate at 0xFFFF.",
+       },
+       {
+               "GD",
+               "good-packets",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Number of good received frames. Read-only, saturate at "
+               "0xFFFF.",
+       },
+       {
+               "RP",
+               "rssi-pwm-timer",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "RSSI PWM timer, the time in tenth of seconds that the RSSI "
+               "output indicating signal strength will remain active after "
+               "the last reception (1 to 0xff, default is 0x20 = 3.2 secs).",
+       },
+       {
+               "TR",
+               "tx-errors",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Transmission Errors, the number of MAC frames that "
+               "exhaust MAC retries without ever receiving a MAC "
+               "acknowledgement message. Read-only, saturate at 0xFFFF.",
+       },
+       {
+               "TP",
+               "temperature",
+               XBEE_ATCMD_F_PARAM_S16 | XBEE_ATCMD_F_READ,
+               "Temperature. Read module temperature in (tenths of ?) "
+               "Celsius. Negatives temperatures can be returned (read-only, "
+               "from 0xff74 [-140] to 0x0258 [600]).",
+       },
+       {
+               "DB",
+               "rx-signal-strength",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Received Signal Strength of the last received RF data "
+               "packet measured in -dBm. For example if DB returns 0x60, "
+               "then the RSSI of the last packet received was -96dBm "
+               "(read-only)."
+       },
+       {
+               "DC",
+               "duty-cycle",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+               "Duty Cycle. Returns a current usage percentage of the "
+               "10% duty cycle measured over the period of 1 hour "
+               "(read-only, from 0 to 0x64).",
+       },
+       {
+               "RC",
+               "rssi-for-channel", //XXX in fact it is a read with a param
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_WRITE,
+               "Reads the dBm level (RSSI) of the designated "
+               "channel.",
+       },
+       {
+               "R#",
+               "reset-number",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+               "Tells the reason for the last module reset (0 - Power up "
+               "reset, 2 - Watchdog reset, 3 - Software reset, 4 - Reset "
+               "line reset, 5 - Brownout reset). Read-only.",
+       },
+       {
+               "TA",
+               "tx-ack-errors",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+               "Transmit Acknowlegement Errors. Incremented once for "
+               "each failed ack retry (read-only, from 0 to 0xFFFF).",
+       },
+       {
+               "%V",
+               "supply-voltage",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+               "Voltage on the Vcc pin in mV (read-only, from 0 to 0xF00).",
+       },
+       {
+               "CT",
+               "cmd-mode-timeout",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Command Mode Timeout: the period of inactivity (no valid "
+               "commands received) after which the RF module automatically "
+               "exits AT Command Mode and returns to Idle Mode (2 to 0x1770, "
+               "default is 0x64).",
+       },
+       {
+               "CN",
+               "exit-cmd-mode",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Exit Command Mode.",
+       },
+       {
+               "GT",
+               "guard-times",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Guard Times: period of silence in ms before and after the "
+               "Command Sequence Characters of the AT Command Mode Sequence, "
+               "used to prevent inadvertent entrance into AT Command Mode "
+               "(0 to 0xFFFF, default is 0x3E8).",
+       },
+       {
+               "CC",
+               "command-chars",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Command Character used between guard times of the AT Command "
+               "Mode Sequence (0 to 0xFF, default is 0x2B).",
+       },
+       {
+               "ID",
+               "network-id",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Network ID. Nodes must have the same network identifier "
+               "to communicate (0 to 0x7FFF, default is 0x7FFF).",
+       },
+       {
+               "NT",
+               "ndisc-timeout",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Node Discover Timeout, time in tenth of secs a node will "
+               "spend discovering other nodes when ND or DN is issued (0 "
+               "to 0xFC, default is 0x82).",
+       },
+       {
+               "NI",
+               "node-id",
+               XBEE_ATCMD_F_PARAM_STRING_20B | XBEE_ATCMD_F_READ |
+               XBEE_ATCMD_F_WRITE,
+               "Node Identifier in printable ASCII characters. This string is "
+               "returned as part of the ATND (Network Discover) command. This "
+               "identifier is also used with the ATDN (Destination Node) "
+               "command. The string contains up to 20 byte ASCII string, "
+               "default is a space character.",
+       },
+       {
+               "DN",
+               "disc-node",
+               XBEE_ATCMD_F_PARAM_STRING_20B | XBEE_ATCMD_F_READ |
+               XBEE_ATCMD_F_WRITE,
+               /* XXX */
+               "Resolves a Node Identifier string to a physical address "
+               "(case sensitive). 0xFFFE and the 64bits extended address are "
+               "returned."
+       },
+       {
+               "ND",
+               "network-discover",
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+               "Network Discovery, see doc", /* XXX */
+       },
+       {
+               "NO",
+               "ndisc-options",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Network Discovery Options, a bitfield value that changes the "
+               "behavior of the ND command (bit0 - Append DD value, bit1 - "
+               "Local device sends ND response frame when ND is issued). "
+               "Default is 0."
+       },
+       {
+               "EE",
+               "security-enable",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Enable or disable 128-bit AES encryption (0 or 1, 0 is the "
+               "default).",
+       },
+       {
+               "KY", /* XXX */
+               "security-key",
+               XBEE_ATCMD_F_PARAM_HEXBUF_16B | XBEE_ATCMD_F_WRITE,
+               "The 128bits security key (the command is write-only).",
+       },
+       {
+               "MT",
+               "bcast-multi-xmit",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Number of additional MAC-level broadcast transmissions. All "
+               "broadcast packets are transmitted MT+1 times to ensure "
+               "it is received (0 to 0xF, default is 3).",
+       },
+       {
+               "RR",
+               "unicast-retries",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Number of additional MAC-level packet delivery attempts for "
+               "unicast transactions. If RR is non-zero, packets sent from "
+               "the radio will request an acknowledgement, and can be resent "
+               "up to RR times if no acknowledgement is received. (0 to 0xF, "
+               "default is 10).",
+       },
+       {
+               "PL",
+               "power-level",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Power Level of RF transmitter (0 - 1mW, 1 - 23mW, 2 - 100mW, "
+               "3 - 158 mW, 4 - 316 mW). Default is 4.",
+       },
+       {
+               "SM",
+               "sleep-mode",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Sleep Mode (0 - disabled, 1 - pin sleep, 4 - async cyclic "
+               "sleep, 5 - async cyclic sleep with pin wakeup). Default "
+               "is 0.",
+       },
+       {
+               "SO",
+               "sleep-options",
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Sleep Options bitmask (bit8 - always wake for ST time). "
+               "Default is 0.",
+       },
+       {
+               "ST",
+               "wake-time",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Wake Time: the amount of time in ms that the module will stay "
+               "awake after receiving RF or serial data (from 0x45 to "
+               "0x36EE80, default is 0x7D0 = 2 secs).",
+       },
+       {
+               "SP",
+               "sleep-period",
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Sleep Period: the amount of time in 10ms unit the module will "
+               "sleep per cycle.  For a node operating as an Indirect "
+               "Messaging Coordinator, this command defines the amount of "
+               "time that it will hold an indirect message for an end device. "
+               "The coordinator will hold the message for (2.5 * SP). Range "
+               "is from 1 to 1440000, default is 200 (2 secs).",
+       },
+       {
+               "SN",
+               "num-sleep-periods",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Number of Sleep Periods that must elapse between assertions "
+               "of the ON_SLEEP line during the wake time of asynchronous "
+               "cyclic sleep (1 to 0xFFFF, default is 1).",
+       },
+       {
+               "WH",
+               "wake-host",
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+               "Wake Host time. If it is set to a non-zero value, it "
+               "specifies the time in ms that the device should allow after "
+               "waking from sleep before sending data out the UART or "
+               "transmitting an I/O sample. If serial characters are "
+               "received, the WH timer is stopped immediately. Range is "
+               "from 0 to 0xFFFF, default is 0.",
+       },
+       {
+               NULL,
+               NULL,
+               0,
+               NULL,
+       },
+};
+
+struct xbee_atcmd *xbee_atcmd_lookup_name(const char *atcmd_str)
+{
+       struct xbee_atcmd *cmd;
+
+       for (cmd = &xbee_atcmd_list[0]; cmd->name != NULL; cmd++) {
+               if (strcmp(atcmd_str, cmd->name))
+                       continue;
+               break;
+       }
+
+       if (cmd->name == NULL) /* not found */
+               return NULL;
+
+       return cmd;
+}
+
+struct xbee_atcmd *xbee_atcmd_lookup_desc(const char *desc)
+{
+       struct xbee_atcmd *cmd;
+
+       for (cmd = &xbee_atcmd_list[0]; cmd->desc != NULL; cmd++) {
+               if (strcmp(desc, cmd->desc))
+                       continue;
+               break;
+       }
+
+       if (cmd->name == NULL) /* not found */
+               return NULL;
+
+       return cmd;
+}
diff --git a/xbee_atcmd.h b/xbee_atcmd.h
new file mode 100644 (file)
index 0000000..91a7e3d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XBEE_ATCMD_H_
+#define _XBEE_ATCMD_H_
+
+#define XBEE_ATCMD_F_READ              0x001
+#define XBEE_ATCMD_F_WRITE             0x002
+#define XBEE_ATCMD_F_PARAM_NONE        0x004
+#define XBEE_ATCMD_F_PARAM_U8          0x008
+#define XBEE_ATCMD_F_PARAM_U16         0x010
+#define XBEE_ATCMD_F_PARAM_S16         0x020
+#define XBEE_ATCMD_F_PARAM_U32         0x040
+#define XBEE_ATCMD_F_PARAM_STRING_20B  0x080
+#define XBEE_ATCMD_F_PARAM_HEXBUF_16B  0x100
+
+/* list of xbee at commands */
+struct xbee_atcmd {
+       const char *name;
+       const char *desc;
+       unsigned int flags;
+       const char *help;
+};
+
+extern struct xbee_atcmd xbee_atcmd_list[];
+
+struct xbee_atcmd *xbee_atcmd_lookup_name(const char *atcmd_str);
+struct xbee_atcmd *xbee_atcmd_lookup_desc(const char *desc);
+
+#endif /* _xBEE_ATCMD_H_ */
diff --git a/xbee_buf.c b/xbee_buf.c
new file mode 100644 (file)
index 0000000..b33ed0b
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee.h"
+
+struct xbee_buf *xbee_buf_alloc(void)
+{
+       struct xbee_buf *xbuf;
+
+       xbuf = malloc(sizeof(*xbuf));
+       if (xbuf == NULL)
+               return NULL;
+       memset(xbuf, 0, sizeof(*xbuf));
+       xbuf->offset = 0;
+       xbuf->len = 0;
+       return xbuf;
+}
+
+int xbee_buf_tailroom(struct xbee_buf *xbuf)
+{
+       return XBEE_BUF_SIZE - xbuf->len - xbuf->offset;
+}
+
+char *xbee_buf_data(struct xbee_buf *xbuf, unsigned off)
+{
+       if (off >= xbuf->len)
+               return NULL;
+       return xbuf->buf + xbuf->offset + off;
+}
+
+char *xbee_buf_head(struct xbee_buf *xbuf)
+{
+       return xbuf->buf + xbuf->offset;
+}
+
+char *xbee_buf_tail(struct xbee_buf *xbuf)
+{
+       return xbuf->buf + xbuf->offset + xbuf->len;
+}
+
+void xbee_buf_enqueue(struct xbee_bufq *q, struct xbee_buf *xbuf)
+{
+       CIRCLEQ_INSERT_TAIL(&q->xbq, xbuf, next);
+       q->len += xbuf->len;
+       q->nseg++;
+}
+
+struct xbee_buf *xbee_bufq_last(struct xbee_bufq *q)
+{
+       if (CIRCLEQ_EMPTY(&q->xbq))
+               return NULL;
+       return CIRCLEQ_LAST(&q->xbq);
+}
+
+void xbee_bufq_init(struct xbee_bufq *q)
+{
+       CIRCLEQ_INIT(&q->xbq);
+       q->len = 0;
+       q->nseg = 0;
+}
+
+void xbee_bufq_append(struct xbee_bufq *q, unsigned len)
+{
+       struct xbee_buf *xbuf;
+
+       q->len += len;
+       xbuf = CIRCLEQ_LAST(&q->xbq);
+       xbuf->len += len;
+}
+
+void xbee_bufq_flush(struct xbee_bufq *q)
+{
+       struct xbee_buf *xbuf;
+
+       while (!CIRCLEQ_EMPTY(&q->xbq)) {
+               xbuf = CIRCLEQ_FIRST(&q->xbq);
+               CIRCLEQ_REMOVE(&q->xbq, xbuf, next);
+               q->nseg --;
+               q->len -= xbuf->len;
+               free(xbuf);
+       }
+}
+
+char *xbee_bufq_data(struct xbee_bufq *q, unsigned off)
+{
+       struct xbee_buf *xbuf;
+       char *data = NULL;
+
+       if (off >= q->len)
+               return NULL;
+
+       CIRCLEQ_FOREACH(xbuf, &q->xbq, next) {
+               data = xbee_buf_data(xbuf, off);
+               if (data != NULL)
+                       return data;
+               off -= xbuf->len;
+       }
+
+       return data;
+}
+
+/* drop data in front of queue */
+int xbee_bufq_drop(struct xbee_bufq *q, unsigned len)
+{
+       struct xbee_buf *xbuf;
+
+       if (len > q->len)
+               return -1;
+
+       while (!CIRCLEQ_EMPTY(&q->xbq)) {
+               xbuf = CIRCLEQ_FIRST(&q->xbq);
+               if (xbuf->len > len)
+                       break;
+               CIRCLEQ_REMOVE(&q->xbq, xbuf, next);
+               len -= xbuf->len;
+               q->nseg --;
+               q->len -= xbuf->len;
+               free(xbuf);
+               xbuf = NULL;
+       }
+
+       if (xbuf != NULL) {
+               xbuf->len -= len;
+               xbuf->offset += len;
+               q->len -= len;
+       }
+
+       return 0;
+}
+
+int xbee_bufq_copy(struct xbee_bufq *q, void *buf, unsigned len)
+{
+       struct xbee_buf *xbuf;
+       unsigned dstoff = 0, copylen;
+
+       if (len > q->len)
+               return -1;
+
+       CIRCLEQ_FOREACH(xbuf, &q->xbq, next) {
+               copylen = len;
+               if (xbuf->len < len)
+                       copylen = xbuf->len;
+               memcpy(buf + dstoff, xbuf->buf + xbuf->offset, copylen);
+               len -= copylen;
+               if (len == 0)
+                       break;
+               dstoff += copylen;
+       }
+
+       return 0;
+}
+
diff --git a/xbee_buf.h b/xbee_buf.h
new file mode 100644 (file)
index 0000000..cecddcf
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define XBEE_BUF_SIZE 0x200
+
+/* a xbee data buffer */
+struct xbee_buf {
+       CIRCLEQ_ENTRY(xbee_buf) next;
+       unsigned offset;
+       unsigned len;
+       char buf[XBEE_BUF_SIZE];
+};
+
+/* queue of xbee_buf */
+CIRCLEQ_HEAD(xbufq, xbee_buf);
+
+struct xbee_bufq {
+       struct xbufq xbq;
+       unsigned len;
+       unsigned nseg;
+};
+
+/* allocate a new xbee_buf */
+struct xbee_buf *xbee_buf_alloc(void);
+
+/* return the number of remaining bytes in xbee_buf */
+int xbee_buf_tailroom(struct xbee_buf *xbuf);
+
+/* return the pointer to data at offset 'off', or NULL if off > xbuf->len */
+char *xbee_buf_data(struct xbee_buf *xbuf, unsigned off);
+
+/* return the first data of a xbuf (also works if len is 0) */
+char *xbee_buf_head(struct xbee_buf *xbuf);
+
+/* return the pointer just after data of a xbuf (also works if len is 0) */
+char *xbee_buf_tail(struct xbee_buf *xbuf);
+
+/* enqueue a xbuf in a xbufq */
+void xbee_buf_enqueue(struct xbee_bufq *q, struct xbee_buf *xbuf);
+
+
+
+/* return the last xbuf of a queue, or NULL if the queue is empty */
+struct xbee_buf *xbee_bufq_last(struct xbee_bufq *q);
+
+/* initialize a xbuf queue */
+void xbee_bufq_init(struct xbee_bufq *q);
+
+/* flush a xbuf queue */
+void xbee_bufq_flush(struct xbee_bufq *q);
+
+/* append data in queue (just update lens), user should memcpy first */
+void xbee_bufq_append(struct xbee_bufq *q, unsigned len);
+
+/* return the pointer to data at offset 'off', or NULL if off > q->len */
+char *xbee_bufq_data(struct xbee_bufq *q, unsigned off);
+
+/* drop data in front of queue */
+int xbee_bufq_drop(struct xbee_bufq *q, unsigned len);
+
+/* copy data in front of queue in a linear buffer */
+int xbee_bufq_copy(struct xbee_bufq *q, void *buf, unsigned len);
diff --git a/xbee_neighbor.c b/xbee_neighbor.c
new file mode 100644 (file)
index 0000000..3495f8b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_atcmd.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee_proto.h"
+#include "xbee.h"
+
+void xbee_neigh_init(struct xbee_dev *dev)
+{
+       LIST_INIT(&dev->neigh_list);
+}
+
+struct xbee_neigh *xbee_neigh_lookup(struct xbee_dev *dev, const char *name)
+{
+       struct xbee_neigh *neigh;
+
+       LIST_FOREACH(neigh, &dev->neigh_list, next) {
+               if (strcmp(name, neigh->name))
+                       continue;
+               break;
+       }
+
+       return neigh;
+}
+
+struct xbee_neigh *xbee_neigh_rlookup(struct xbee_dev *dev, uint64_t addr)
+{
+       struct xbee_neigh *neigh;
+
+       LIST_FOREACH(neigh, &dev->neigh_list, next) {
+               if (addr != neigh->addr)
+                       continue;
+               break;
+       }
+
+       return neigh;
+}
+
+struct xbee_neigh *xbee_neigh_add(struct xbee_dev *dev, const char *name,
+                                 uint64_t addr)
+{
+       struct xbee_neigh *neigh;
+
+       if (xbee_neigh_rlookup(dev, addr) != NULL)
+               return NULL;
+
+       if (xbee_neigh_lookup(dev, name) != NULL)
+               return NULL;
+
+       neigh = malloc(sizeof(*neigh));
+       if (neigh == NULL)
+               return NULL;
+
+       neigh->addr = addr;
+       snprintf(neigh->name, sizeof(neigh->name), "%s", name);
+       LIST_INSERT_HEAD(&dev->neigh_list, neigh, next);
+
+       return neigh;
+}
+
+void xbee_neigh_del(struct xbee_dev *dev, struct xbee_neigh *neigh)
+{
+       dev = dev; /* silent compiler */
+       LIST_REMOVE(neigh, next);
+       free(neigh);
+}
diff --git a/xbee_neighbor.h b/xbee_neighbor.h
new file mode 100644 (file)
index 0000000..0939a24
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XBEE_NEIGHBOR_H_
+#define _XBEE_NEIGHBOR_H_
+
+struct xbee_neigh {
+       LIST_ENTRY(xbee_neigh) next;
+       char name[21];
+       uint64_t addr;
+};
+
+struct xbee_dev;
+
+/* define struct xbee_neigh_list */
+LIST_HEAD(xbee_neigh_list, xbee_neigh);
+
+/* init neighbor list of an xbee device */
+void xbee_neigh_init(struct xbee_dev *dev);
+
+/* return a neighbor from its name */
+struct xbee_neigh *xbee_neigh_lookup(struct xbee_dev *dev, const char *name);
+
+/* return a neighbor from its address (in host order) */
+struct xbee_neigh *xbee_neigh_rlookup(struct xbee_dev *dev, uint64_t addr);
+
+/* add a neighbor */
+struct xbee_neigh *xbee_neigh_add(struct xbee_dev *dev, const char *name,
+                                 uint64_t addr);
+
+/* del a neighbor from list */
+void xbee_neigh_del(struct xbee_dev *dev, struct xbee_neigh *neigh);
+
+#endif /* _XBEE_NEIGHBOR_H_ */
diff --git a/xbee_proto.c b/xbee_proto.c
new file mode 100644 (file)
index 0000000..3c694bc
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/queue.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+
+/* remove */
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_buf.h"
+#include "xbee_proto.h"
+#include "xbee.h"
+
+static void xbee_proto_drop_garbage(struct xbee_dev *dev)
+{
+       struct xbee_bufq *q = &dev->queue;
+       char *data;
+
+       /* drop all data != delimiter */
+       while ((data = xbee_bufq_data(q, 0))) {
+               /* no more data */
+               if (data == NULL)
+                       break;
+
+               if (*data == XBEE_DELIMITER)
+                       break;
+
+               dev->stats.rx_no_delim++;
+               xbee_bufq_drop(q, 1);
+       }
+}
+
+/* return negative on error, 0 if there is not frame, or framelen */
+int xbee_proto_get_frame(struct xbee_dev *dev, void *buf, unsigned len)
+{
+       uint16_t framelen;
+       struct xbee_hdr hdr;
+       struct xbee_bufq *q = &dev->queue;
+
+       xbee_proto_drop_garbage(dev);
+
+       if (xbee_bufq_copy(q, &hdr, sizeof(hdr)) < 0)
+               return 0;
+
+       framelen = ntohs(hdr.len);
+       framelen += 4; /* 1 for delimiter, 2 for len, 1 for cksum */
+
+       /* not enough data to read */
+       if (q->len < framelen)
+               return 0;
+
+       /* arf, provided buffer is to small */
+       if (framelen > len) {
+               fprintf(stderr, "drop packet, buffer too small\n");
+               dev->stats.rx_frame_too_large++;
+               xbee_bufq_drop(q, framelen);
+               return -1;
+       }
+
+       xbee_bufq_copy(q, buf, framelen);
+       xbee_bufq_drop(q, framelen);
+       return framelen;
+}
+
+/* return -1 if the frame is invalid */
+static int xbee_proto_parse_atresp(struct xbee_dev *dev, void *buf,
+                                  unsigned len)
+{
+       struct xbee_atresp_hdr *atresp_hdr;
+
+       dev->stats.rx_atresp++;
+
+       if (len < sizeof(struct xbee_hdr) + sizeof(struct xbee_atresp_hdr)) {
+               dev->stats.rx_frame_too_small++;
+               return -1;
+       }
+
+       atresp_hdr = buf + sizeof(struct xbee_hdr);
+
+       /* bad status, but let the frame continue */
+       if (atresp_hdr->status != 0)
+               dev->stats.rx_atresp_error++;
+
+       return 0;
+}
+
+/* return -1 if the frame is invalid */
+static int xbee_proto_parse_rmt_atresp(struct xbee_dev *dev, void *buf,
+                                  unsigned len)
+{
+       struct xbee_rmt_atresp_hdr *rmt_atresp_hdr;
+
+       dev->stats.rx_rmt_atresp++;
+
+       if (len < sizeof(struct xbee_hdr) + sizeof(struct xbee_rmt_atresp_hdr)) {
+               dev->stats.rx_frame_too_small++;
+               return -1;
+       }
+
+       rmt_atresp_hdr = buf + sizeof(struct xbee_hdr);
+
+       /* bad status, but let the frame continue */
+       if (rmt_atresp_hdr->status != 0)
+               dev->stats.rx_rmt_atresp_error++;
+
+       return 0;
+}
+
+/* return -1 if the frame is invalid */
+static int xbee_proto_parse_xmit_status(struct xbee_dev *dev, void *buf,
+                                       unsigned len)
+{
+       struct xbee_xmit_status_hdr *xmit_status_hdr;
+
+       dev->stats.rx_xmit_status++;
+
+       if (len < sizeof(struct xbee_hdr) + sizeof(struct xbee_xmit_status_hdr)) {
+               dev->stats.rx_frame_too_small++;
+               return -1;
+       }
+
+       xmit_status_hdr = buf + sizeof(struct xbee_hdr);
+       dev->stats.tx_xmit_retries += xmit_status_hdr->xmit_retry_cnt;
+
+       /* bad status, but let the frame continue */
+       if (xmit_status_hdr->delivery_status != 0)
+               dev->stats.rx_xmit_status_error++;
+
+       return 0;
+}
+
+/* parse a frame: return 0 if the frame is valid, else a negative value */
+// XXX rename
+int xbee_proto_parse_frame(struct xbee_dev *dev, void *buf, unsigned len)
+{
+       struct xbee_hdr *hdr = buf;
+       int i;
+       uint8_t cksum = 0;
+       int channel;
+       unsigned hdrlen;
+
+       dev->stats.rx_frame++;
+
+       /* check frame len: we must be able to read frame type */
+       if (len < (offsetof(struct xbee_hdr, type) + 1)) {
+               dev->stats.rx_frame_too_small++;
+               fprintf(stderr, "Frame too small\n");
+               return -1;
+       }
+
+       switch (hdr->type) {
+               case XBEE_TYPE_MODEM_STATUS:
+               case XBEE_TYPE_RECV:
+               case XBEE_TYPE_EXPL_RECV:
+                       hdrlen = sizeof(struct xbee_hdr) - 1; /* no frame ID */
+                       break;
+               default:
+                       hdrlen = sizeof(struct xbee_hdr);
+                       break;
+       }
+
+       /* check frame len */
+       if (len < (hdrlen + 1)) {
+               dev->stats.rx_frame_too_small++;
+               fprintf(stderr, "Frame too small\n");
+               return -1;
+       }
+
+       /* validate the cksum */
+       for (i = 3; i < (len - 1); i++)
+               cksum += ((uint8_t *)buf)[i];
+       cksum = 0xff - cksum;
+       if (cksum != ((uint8_t *)buf)[len-1]) {
+               fprintf(stderr, "Invalid cksum\n");
+               dev->stats.rx_invalid_cksum++;
+               return -1;
+       }
+
+       /* dispatch */
+       switch (hdr->type) {
+               case XBEE_TYPE_MODEM_STATUS:
+                       dev->stats.rx_modem_status++;
+                       channel = XBEE_DEFAULT_CHANNEL;
+                       break;
+               case XBEE_TYPE_ATRESP:
+                       if (xbee_proto_parse_atresp(dev, buf, len) < 0)
+                               return -1;
+                       channel = hdr->id;
+                       break;
+               case XBEE_TYPE_RMT_ATRESP:
+                       if (xbee_proto_parse_rmt_atresp(dev, buf, len) < 0)
+                               return -1;
+                       channel = hdr->id;
+                       break;
+               case XBEE_TYPE_XMIT_STATUS:
+                       if (xbee_proto_parse_xmit_status(dev, buf, len) < 0)
+                               return -1;
+                       channel = hdr->id;
+                       break;
+               case XBEE_TYPE_RECV:
+                       dev->stats.rx_data++;
+                       channel = XBEE_DEFAULT_CHANNEL;
+                       break;
+               case XBEE_TYPE_EXPL_RECV:
+                       dev->stats.rx_expl_data++;
+                       channel = XBEE_DEFAULT_CHANNEL;
+                       break;
+               case XBEE_TYPE_NODE_ID:
+                       dev->stats.rx_node_id++;
+                       channel = hdr->id; //XXX
+                       break;
+                       /* invalid commands */
+               case XBEE_TYPE_ATCMD:
+               case XBEE_TYPE_ATCMD_Q:
+               case XBEE_TYPE_XMIT:
+               case XBEE_TYPE_EXPL_XMIT:
+               case XBEE_TYPE_RMT_ATCMD:
+               default:
+                       dev->stats.rx_invalid_type++;
+                       break;
+       }
+
+       /* fallback to default channel if not registered */
+       if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
+           dev->channel[channel].registered == 0)
+               channel = XBEE_DEFAULT_CHANNEL;
+
+       /* execute the callback if any */
+       if (dev->channel[channel].rx_cb != NULL)
+               dev->channel[channel].rx_cb(dev, channel, hdr->type,
+                                           buf + hdrlen, len - hdrlen - 1,
+                                           dev->channel[channel].arg);
+
+       return 0;
+}
+
+static void hexdump(const char *title, const void *buf, unsigned int len)
+{
+       unsigned int i, out, ofs;
+       const unsigned char *data = buf;
+#define LINE_LEN 80
+       char line[LINE_LEN];    /* space needed 8+16*3+3+16 == 75 */
+
+       printf("%s at [%p], len=%d\n", title, data, len);
+       ofs = 0;
+       while (ofs < len) {
+               /* format 1 line in the buffer, then use printk to print them */
+               out = snprintf(line, LINE_LEN, "%08X", ofs);
+               for (i=0; ofs+i < len && i<16; i++)
+                       out += snprintf(line+out, LINE_LEN - out, " %02X",
+                                       data[ofs+i]&0xff);
+               for (;i<=16;i++)
+                       out += snprintf(line+out, LINE_LEN - out, "   ");
+               for (i=0; ofs < len && i<16; i++, ofs++) {
+                       unsigned char c = data[ofs];
+                       if (!isascii(c) || !isprint(c))
+                               c = '.';
+                       out += snprintf(line+out, LINE_LEN - out, "%c", c);
+               }
+               printf("%s\n", line);
+       }
+}
+
+int xbee_proto_xmit(struct xbee_dev *dev, uint8_t channel_id, uint8_t type,
+                   void *buf, unsigned len)
+{
+       struct xbee_hdr hdr;
+       struct iovec iov[3];
+       int i;
+       uint8_t cksum = 0;
+
+       /* there is no empty message, so return an error */
+       if (len == 0)
+               return -1;
+
+       /* prepare an iovec to avoid a copy: prepend a header to the
+        * buffer and append a checksum */
+       hdr.delimiter = XBEE_DELIMITER;
+       hdr.len = htons(len + 2);
+       hdr.type = type;
+       hdr.id = channel_id;
+
+       iov[0].iov_base = &hdr;
+       iov[0].iov_len = sizeof(hdr);
+       iov[1].iov_base = buf;
+       iov[1].iov_len = len;
+       iov[2].iov_base = &cksum;
+       iov[2].iov_len = 1;
+
+       if (channel_id < 0 || channel_id >= XBEE_MAX_CHANNEL ||
+           dev->channel[channel_id].registered == 0) {
+               dev->stats.tx_invalid_channel ++;
+               return -1;
+       }
+
+       /* calculate the cksum */
+       cksum = hdr.type;
+       cksum += hdr.id;
+       for (i = 0; i < len; i++)
+               cksum += ((uint8_t *)buf)[i];
+       cksum = 0xff - cksum;
+       dev->stats.tx_frame ++;
+
+       /* some additional checks before sending */
+       switch (hdr.type) {
+
+               case XBEE_TYPE_ATCMD:
+                       // XXX some checks ?
+                       dev->stats.tx_atcmd ++;
+                       break;
+               case XBEE_TYPE_ATCMD_Q:
+                       dev->stats.tx_atcmd_q ++;
+                       break;
+               case XBEE_TYPE_XMIT:
+                       dev->stats.tx_data ++;
+                       break;
+               case XBEE_TYPE_EXPL_XMIT:
+                       dev->stats.tx_expl_data ++;
+                       break;
+               case XBEE_TYPE_RMT_ATCMD:
+                       dev->stats.tx_rmt_atcmd ++;
+                       break;
+
+               /* invalid commands */
+               case XBEE_TYPE_XMIT_STATUS:
+               case XBEE_TYPE_MODEM_STATUS:
+               case XBEE_TYPE_ATRESP:
+               case XBEE_TYPE_RECV:
+               case XBEE_TYPE_EXPL_RECV:
+               case XBEE_TYPE_NODE_ID:
+               case XBEE_TYPE_RMT_ATRESP:
+               default:
+                       dev->stats.tx_invalid_type ++;
+                       fprintf(stderr, "unhandled xmit type=%x\n", hdr.type);
+                       return -1;
+       }
+
+       hexdump("hdr", (uint8_t *)&hdr, sizeof(hdr));
+       hexdump("buf", (uint8_t *)buf, len);
+       hexdump("cksum", &cksum, 1);
+
+       return writev(dev->fd, iov, 3);
+}
+
diff --git a/xbee_proto.h b/xbee_proto.h
new file mode 100644 (file)
index 0000000..49af583
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* protocol headers */
+
+#define XBEE_DELIMITER 0x7E
+#define XBEE_MAX_FRAME_LEN 0x200
+
+struct xbee_hdr {
+       uint8_t delimiter;
+       uint16_t len;
+       uint8_t type;
+       uint8_t id; /* not always present */
+} __attribute__((packed));
+
+#define XBEE_TYPE_ATCMD 0x08
+struct xbee_atcmd_hdr {
+       uint16_t cmd;
+       uint8_t params[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_ATCMD_Q 0x09
+struct xbee_atcmd_q_hdr {
+       uint16_t cmd;
+       uint8_t params[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_XMIT 0x10
+struct xbee_xmit_hdr {
+       uint64_t dstaddr;
+       uint16_t reserved;
+       uint8_t bcast_radius;
+       uint8_t opts;
+       uint8_t data[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_EXPL_XMIT 0x11
+struct xbee_expl_xmit_hdr {
+       uint64_t dstaddr;
+       uint16_t reserved;
+       uint8_t src_endpoint;
+       uint8_t dst_endpoint;
+       uint16_t cluster_id;
+       uint16_t profile_id;
+       uint8_t bcast_radius;
+       uint8_t opts;
+       uint8_t data[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_RMT_ATCMD 0x17
+struct xbee_rmt_atcmd_hdr {
+       uint64_t dstaddr;
+       uint16_t reserved;
+       uint8_t opts;
+       uint16_t cmd;
+       uint8_t params[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_ATRESP 0x88
+struct xbee_atresp_hdr {
+       uint16_t cmd;
+       uint8_t status;
+       uint8_t data[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_MODEM_STATUS 0x8A
+struct xbee_modem_status_hdr {
+       /* empty */
+} __attribute__((packed));
+
+#define XBEE_TYPE_XMIT_STATUS 0x8B
+struct xbee_xmit_status_hdr {
+       uint16_t reserved;
+       uint8_t xmit_retry_cnt;
+       uint8_t delivery_status;
+       uint8_t discovery_status;
+} __attribute__((packed));
+
+#define XBEE_TYPE_RECV 0x90
+struct xbee_recv_hdr {
+       uint64_t srcaddr;
+       uint16_t reserved;
+       uint8_t opts;
+       uint8_t data[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_EXPL_RECV 0x91
+struct xbee_expl_recv_hdr {
+       uint64_t srcaddr;
+       uint16_t reserved;
+       uint8_t src_endpoint;
+       uint8_t dst_endpoint;
+       uint16_t cluster_id;
+       uint16_t profile_id;
+       uint8_t opts;
+       uint8_t data[];
+} __attribute__((packed));
+
+#define XBEE_TYPE_NODE_ID 0x95
+struct xbee_node_id_hdr {
+       uint64_t srcaddr;
+       uint16_t srcnetwork;
+       uint8_t opts;
+       uint16_t dstnetwork;
+       uint64_t dstaddr;
+       uint8_t ni_string[];
+       /* uint16_t parentaddr; after variable field */
+} __attribute__((packed));
+
+#define XBEE_TYPE_RMT_ATRESP 0x97
+struct xbee_rmt_atresp_hdr {
+       uint64_t srcaddr;
+       uint16_t reserved;
+       uint16_t cmd;
+       uint8_t status;
+       uint8_t data[];
+} __attribute__((packed));
+
+struct xbee_dev;
+
+/* return negative on error, 0 if there is not frame, or framelen */
+int xbee_proto_get_frame(struct xbee_dev *dev, void *buf, unsigned len);
+
+/* parse a frame: return 0 if the frame is valid, else a negative value */
+int xbee_proto_parse_frame(struct xbee_dev *dev, void *buf, unsigned len);
+
+/* send a frame */
+int xbee_proto_xmit(struct xbee_dev *dev, uint8_t id, uint8_t type,
+                   void *buf, unsigned len);
diff --git a/xbee_stats.c b/xbee_stats.c
new file mode 100644 (file)
index 0000000..424abc0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_proto.h"
+#include "xbee_buf.h"
+#include "xbee.h"
+
+struct xbee_stats *xbee_get_stats(struct xbee_dev *dev)
+{
+       return &dev->stats;
+}
+
+void xbee_reset_stats(struct xbee_dev *dev)
+{
+       memset(&dev->stats, 0, sizeof(dev->stats));
+}
+
+void xbee_dump_stats(FILE *file, struct xbee_dev *dev)
+{
+       fprintf(file, "statistics on dev %s:\n", dev->name);
+       fprintf(file, " rx_frame: %d\n", dev->stats.rx_frame);
+       fprintf(file, " rx_atresp: %d\n", dev->stats.rx_atresp);
+       fprintf(file, " rx_atresp_error: %d\n", dev->stats.rx_atresp_error);
+       fprintf(file, " rx_modem_status: %d\n", dev->stats.rx_modem_status);
+       fprintf(file, " rx_xmit_status: %d\n", dev->stats.rx_xmit_status);
+       fprintf(file, " rx_xmit_status_error: %d\n", dev->stats.rx_xmit_status_error);
+       fprintf(file, " rx_data: %d\n", dev->stats.rx_data);
+       fprintf(file, " rx_expl_data: %d\n", dev->stats.rx_expl_data);
+       fprintf(file, " rx_node_id: %d\n", dev->stats.rx_node_id);
+       fprintf(file, " rx_rmt_atresp: %d\n", dev->stats.rx_rmt_atresp);
+       fprintf(file, " rx_rmt_atresp_error: %d\n", dev->stats.rx_rmt_atresp_error);
+       fprintf(file, " rx_frame_too_small: %d\n", dev->stats.rx_frame_too_small);
+       fprintf(file, " rx_frame_too_large: %d\n", dev->stats.rx_frame_too_large);
+       fprintf(file, " rx_invalid_cksum: %d\n", dev->stats.rx_invalid_cksum);
+       fprintf(file, " rx_invalid_type: %d\n", dev->stats.rx_invalid_type);
+       fprintf(file, " rx_no_delim: %d\n", dev->stats.rx_no_delim);
+       fprintf(file, " tx_frame: %d\n", dev->stats.tx_frame);
+       fprintf(file, " tx_atcmd: %d\n", dev->stats.tx_atcmd);
+       fprintf(file, " tx_atcmd_q: %d\n", dev->stats.tx_atcmd_q);
+       fprintf(file, " tx_data: %d\n", dev->stats.tx_data);
+       fprintf(file, " tx_expl_data: %d\n", dev->stats.tx_expl_data);
+       fprintf(file, " tx_xmit_retries: %d\n", dev->stats.tx_xmit_retries);
+       fprintf(file, " tx_rmt_atcmd: %d\n", dev->stats.tx_rmt_atcmd);
+       fprintf(file, " tx_invalid_type: %d\n", dev->stats.tx_invalid_type);
+       fprintf(file, " tx_invalid_channel: %d\n", dev->stats.tx_invalid_channel);
+}
diff --git a/xbee_stats.h b/xbee_stats.h
new file mode 100644 (file)
index 0000000..0d3f8ec
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* per-device statistics */
+struct xbee_stats {
+       int rx_frame;
+       int rx_atresp;
+       int rx_atresp_error;
+       int rx_modem_status;
+       int rx_xmit_status;
+       int rx_xmit_status_error;
+       int rx_data;
+       int rx_expl_data;
+       int rx_node_id;
+       int rx_rmt_atresp;
+       int rx_rmt_atresp_error;
+       int rx_frame_too_small;
+       int rx_frame_too_large;
+       int rx_invalid_cksum;
+       int rx_invalid_type;
+       int rx_no_delim;
+
+       int tx_frame;
+       int tx_atcmd;
+       int tx_atcmd_q;
+       int tx_data;
+       int tx_expl_data;
+       int tx_xmit_retries;
+       int tx_rmt_atcmd;
+       int tx_invalid_type;
+       int tx_invalid_channel;
+};
+
+struct xbee_dev;
+
+/* return pointer to device stats */
+struct xbee_stats *xbee_get_stats(struct xbee_dev *dev);
+
+/* reset statistics of device */
+void xbee_reset_stats(struct xbee_dev *dev);
+
+/* dump statistics on specified file */
+void xbee_dump_stats(FILE *file, struct xbee_dev *dev);