--- /dev/null
+/*
+ * 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,
+ },
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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,
+};
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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,
+};
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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,
+};
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);