xbee: add a new module
authorOlivier Matz <zer0@droids-corp.org>
Thu, 7 Nov 2013 19:33:25 +0000 (20:33 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Sat, 24 May 2014 16:54:02 +0000 (18:54 +0200)
Signed-off-by: Olivier Matz <zer0@droids-corp.org>
14 files changed:
config/Configure.help
config/config.in
config/generate_aversive_config
modules/devices/radio/xbee/Makefile [new file with mode: 0644]
modules/devices/radio/xbee/xbee.c [new file with mode: 0644]
modules/devices/radio/xbee/xbee.h [new file with mode: 0644]
modules/devices/radio/xbee/xbee_atcmd.c [new file with mode: 0644]
modules/devices/radio/xbee/xbee_atcmd.h [new file with mode: 0644]
modules/devices/radio/xbee/xbee_neighbor.c [new file with mode: 0644]
modules/devices/radio/xbee/xbee_neighbor.h [new file with mode: 0644]
modules/devices/radio/xbee/xbee_rxtx.c [new file with mode: 0644]
modules/devices/radio/xbee/xbee_rxtx.h [new file with mode: 0644]
modules/devices/radio/xbee/xbee_stats.c [new file with mode: 0644]
modules/devices/radio/xbee/xbee_stats.h [new file with mode: 0644]

index d4da4fa..63b9bca 100644 (file)
@@ -193,6 +193,16 @@ CONFIG_MODULE_CC2420
   in wireless sensors.
   This modules requires SPI to be activated.
 
+CONFIG_MODULE_XBEE
+  This modules implements the protocol to use a xbee radio chip.
+  It currently only supports xbee868.
+
+CONFIG_MODULE_XBEE_STATS
+  Enable xbee statistics (takes ~100 bytes per device).
+
+CONFIG_MODULE_XBEE_ATCMD_HELP
+  Embed help strings of AT commands in program memory.
+
 CONFIG_MODULE_MENU
   The menu module provides some helpers to create a human-machine
   interface that uses a tree-organized static menu.
index 0e0d83d..8c479c0 100644 (file)
@@ -435,6 +435,14 @@ dep_bool 'CC2420 Radio Device (IEEE 802.15.4) (VERY EXPERIMENTAL)' CONFIG_MODULE
 dep_bool '  |-- Create Default CC2420 config' CONFIG_MODULE_CC2420_CREATE_CONFIG \
        $CONFIG_MODULE_CC2420
 
+bool 'Xbee Device' CONFIG_MODULE_XBEE
+
+dep_bool '  |-- Enable xbee stats' CONFIG_MODULE_XBEE_STATS \
+       $CONFIG_MODULE_XBEE
+
+dep_bool '  |-- Embed help strings in program memory' CONFIG_MODULE_XBEE_ATCMD_HELP \
+       $CONFIG_MODULE_XBEE
+
 endmenu # radio
 
 
index df7d569..f034165 100755 (executable)
@@ -35,6 +35,7 @@ MODULES_LIST="CONFIG_MODULE_BRUSHLESS_3PHASE_DIGITAL_HALL,/devices/brushless_mot
               CONFIG_MODULE_SCHEDULER,base/scheduler
               CONFIG_MODULE_SPI,comm/spi
               CONFIG_MODULE_CC2420,devices/radio/cc2420
+              CONFIG_MODULE_XBEE,devices/radio/xbee
               CONFIG_MODULE_UART,comm/uart
               CONFIG_MODULE_I2C,comm/i2c
               CONFIG_MODULE_MF2_CLIENT,comm/mf2_client
diff --git a/modules/devices/radio/xbee/Makefile b/modules/devices/radio/xbee/Makefile
new file mode 100644 (file)
index 0000000..0aa0391
--- /dev/null
@@ -0,0 +1,14 @@
+#-include .config
+
+TARGET = xbee
+
+# List C source files here. (C dependencies are automatically generated.)
+SRC  = xbee.c
+SRC += xbee_atcmd.c
+SRC += xbee_neighbor.c
+SRC += xbee_rxtx.c
+SRC += xbee_stats.c
+
+###########################################
+
+include $(AVERSIVE_DIR)/mk/aversive_module.mk
diff --git a/modules/devices/radio/xbee/xbee.c b/modules/devices/radio/xbee/xbee.c
new file mode 100644 (file)
index 0000000..9072fdd
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 <aversive.h>
+#include <aversive/queue.h>
+#include <aversive/pgmspace.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_rxtx.h"
+#include "xbee.h"
+
+int xbee_init(void)
+{
+       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;
+}
+
+int xbee_set_opaque(struct xbee_dev *dev, int channel, void *opaque)
+{
+       if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
+           dev->channel[channel].registered == 0)
+               return -1;
+
+       dev->channel[channel].arg = opaque;
+       return 0;
+}
+
+int xbee_open(struct xbee_dev *dev, FILE *xbee_file)
+{
+       memset(dev, 0, sizeof(*dev));
+       dev->file = xbee_file;
+       xbee_neigh_init(dev);
+       return 0;
+}
diff --git a/modules/devices/radio/xbee/xbee.h b/modules/devices/radio/xbee/xbee.h
new file mode 100644 (file)
index 0000000..87d72ef
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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_H_
+#define _XBEE_H_
+
+#include "xbee_neighbor.h"
+#include "xbee_atcmd.h"
+#include "xbee_stats.h"
+#include "xbee_rxtx.h"
+
+/* 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). The given length exludes the xbee_hdr
+ * structure (delimiter, len, type, id) and the cksum.  */
+typedef int8_t (xbee_rx_cb_t)(struct xbee_dev *dev, int channel, int type,
+       void *frame, unsigned len, void *opaque);
+
+/* 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 {
+       FILE *file;
+       struct xbee_channel channel[XBEE_MAX_CHANNEL];
+       uint8_t frame_len;
+       char frame[XBEE_MAX_FRAME_LEN];
+       struct xbee_neigh_list neigh_list;
+#ifdef CONFIG_MODULE_XBEE_STATS
+       struct xbee_stats stats;
+#endif
+};
+
+/* initialize xbee library */
+int xbee_init(void);
+
+/* open an xbee device */
+int xbee_open(struct xbee_dev *dev, FILE *xbee_file);
+
+/* 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);
+
+/* This function (re)sets the opaque pointer on a registered
+ * channel. The function returns 0 on success and -1 on error (channel
+ * not registered). As the opaque pointer can already be set after a
+ * call to xbee_register_channel(), this function is only useful if
+ * the opaque pointer has to be modified. */
+int xbee_set_opaque(struct xbee_dev *dev, int channel, 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);
+
+#endif /* _XBEE_H_ */
diff --git a/modules/devices/radio/xbee/xbee_atcmd.c b/modules/devices/radio/xbee/xbee_atcmd.c
new file mode 100644 (file)
index 0000000..f77ecfe
--- /dev/null
@@ -0,0 +1,1490 @@
+/*
+ * 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 <aversive/pgmspace.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "xbee_atcmd.h"
+
+static const char PROGMEM atcmd0_name[] = "WR";
+static const char PROGMEM atcmd0_desc[] = "write-param";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd0_help[] =
+       "Write parameter values to non-volatile memory.";
+#endif
+
+static const char PROGMEM atcmd1_name[] = "RE";
+static const char PROGMEM atcmd1_desc[] = "restore-defaults";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd1_help[] =
+       "Restore module parameters to factory defaults.";
+#endif
+
+static const char PROGMEM atcmd2_name[] = "FR";
+static const char PROGMEM atcmd2_desc[] = "soft-reset";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd2_help[] =
+       "Software Reset. Responds with 'OK' then performs a "
+       "reset 100ms later.";
+#endif
+
+static const char PROGMEM atcmd3_name[] = "AC";
+static const char PROGMEM atcmd3_desc[] = "apply-changes";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd3_help[] =
+       "Apply Changes without exiting command mode.";
+#endif
+
+static const char PROGMEM atcmd4_name[] = "R1";
+static const char PROGMEM atcmd4_desc[] = "restore-compiled";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd4_help[] =
+       "Restore module parameters to compiled defaults.";
+#endif
+
+static const char PROGMEM atcmd5_name[] = "VL";
+static const char PROGMEM atcmd5_desc[] = "version-long";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd5_help[] =
+       "Shows detailed version information including"
+       "application build date and time.";
+#endif
+
+static const char PROGMEM atcmd6_name[] = "DH";
+static const char PROGMEM atcmd6_desc[] = "dst-addr-high";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd6_help[] =
+       "Upper 32 bits of the 64-bit destination address (0 "
+       "to 0xFFFFFFFF, default is 0x0000FFFF).";
+#endif
+
+static const char PROGMEM atcmd7_name[] = "DL";
+static const char PROGMEM atcmd7_desc[] = "dst-addr-low";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd7_help[] =
+       "Lower 32 bits of the 64-bit destination address (0 "
+       "to 0xFFFFFFFF, default is 0x0000FFFF).";
+#endif
+
+static const char PROGMEM atcmd8_name[] = "DD";
+static const char PROGMEM atcmd8_desc[] = "device-type-id";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd8_help[] =
+       "Device Type Identifier, it can be used to differentiate "
+       "multiple XBee-based products (0 to 0xFFFFFFFF, read-only, "
+       "default is 0x40000).";
+#endif
+
+static const char PROGMEM atcmd9_name[] = "SH";
+static const char PROGMEM atcmd9_desc[] = "src-addr-high";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd9_help[] =
+       "Upper 32 bits of the 64-bit source address (read-only).";
+#endif
+
+static const char PROGMEM atcmd10_name[] = "SL";
+static const char PROGMEM atcmd10_desc[] = "src-addr-low";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd10_help[] =
+       "Lower 32 bits of the 64-bit source address (read-only).";
+#endif
+
+static const char PROGMEM atcmd11_name[] = "SE";
+static const char PROGMEM atcmd11_desc[] = "src-endpoint";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd11_help[] =
+       "The application source endpoint for all data transmissions "
+       "(0 to 0xFF, default is 0xE8).";
+#endif
+
+static const char PROGMEM atcmd12_name[] = "DE";
+static const char PROGMEM atcmd12_desc[] = "dst-endpoint";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd12_help[] =
+       "The application destination endpoint for all data "
+       "transmissions (0 to 0xFF, default is 0xE8).";
+#endif
+
+static const char PROGMEM atcmd13_name[] = "CI";
+static const char PROGMEM atcmd13_desc[] = "cluster-id";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd13_help[] =
+       "Cluster Identifier for all data transmissions (0 to 0xFFFF, "
+       "default is 0x11).";
+#endif
+
+static const char PROGMEM atcmd14_name[] = "NP";
+static const char PROGMEM atcmd14_desc[] = "max-rf-payload";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd14_help[] =
+       "Maximum RF Payload Bytes that can be sent in a unicast "
+       "transmission based on the current configuration (0 to "
+       "0xFFFF).";
+#endif
+
+static const char PROGMEM atcmd15_name[] = "CE";
+static const char PROGMEM atcmd15_desc[] = "coord-end-device";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd15_help[] =
+       "Coordinator/End Device, messaging mode of the module "
+       "(0 - Normal, 1 - Indirect coordinator, 2 - Polling, default "
+       "is 0).";
+#endif
+
+static const char PROGMEM atcmd16_name[] = "AP";
+static const char PROGMEM atcmd16_desc[] = "api-mode";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd16_help[] =
+       "API mode (0 - off, 1 - on, 2 - on with escape sequences).";
+#endif
+
+static const char PROGMEM atcmd17_name[] = "AO";
+static const char PROGMEM atcmd17_desc[] = "api-output-format";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd17_help[] =
+       "API Output Format (0 - standard [0x90 for RX], 1 - explicit "
+       "addressing [0x91 for RX]).";
+#endif
+
+static const char PROGMEM atcmd18_name[] = "BD";
+static const char PROGMEM atcmd18_desc[] = "baud-rate";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd18_help[] =
+       "Baud rate of serial interface (0-8 select preset standard "
+       "rates, and 0x39 to 0x1c9c38 select baud rate).";
+#endif
+
+static const char PROGMEM atcmd19_name[] = "RO";
+static const char PROGMEM atcmd19_desc[] = "packetization-timeout";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd19_help[] =
+       "Packetization Timeout: the inter-character silence required "
+       "before packetization specified in character times (0 to 0xFF, "
+       "default is 3).";
+#endif
+
+static const char PROGMEM atcmd20_name[] = "FT";
+static const char PROGMEM atcmd20_desc[] = "flow-control-thres";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd20_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd21_name[] = "NB";
+static const char PROGMEM atcmd21_desc[] = "parity";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd21_help[] =
+       "Parity (0 - no parity, 1 - even parity, 2 - odd parity, 3 - "
+       "forced high parity, 4 - forced low parity). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd22_name[] = "D7";
+static const char PROGMEM atcmd22_desc[] = "dio7";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd22_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd23_name[] = "D6";
+static const char PROGMEM atcmd23_desc[] = "dio6";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd23_help[] =
+       "DIO6 Configuration (0 - unmonitored input, 1 - RTS, 3 - "
+       "digital input, 4 - digital output low, 5 - digital output "
+       "high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd24_name[] = "P0";
+static const char PROGMEM atcmd24_desc[] = "dio10-pwm0";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd24_help[] =
+       "DIO10/PWM0 Configuration. (0 - unmonitored input, 1 - RSSI, 2 "
+       "- PWM0, 3 - digital input, 4 - digital output low, 5 - "
+       "digital output high). Default is 1.";
+#endif
+
+static const char PROGMEM atcmd25_name[] = "P1";
+static const char PROGMEM atcmd25_desc[] = "dio11-pwm1";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd25_help[] =
+       "DIO11/PWM1 Configuration. (0 - unmonitored input, 2 "
+       "- PWM1, 3 - digital input, 4 - digital output low, 5 - "
+       "digital output high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd26_name[] = "P2";
+static const char PROGMEM atcmd26_desc[] = "dio12";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd26_help[] =
+       "DIO12 Configuration. (0 - unmonitored input, "
+       "3 - digital input, 4 - digital output low, 5 - "
+       "digital output high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd27_name[] = "RP";
+static const char PROGMEM atcmd27_desc[] = "rssi-pwm";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd27_help[] =
+       "Time RSSI signal will be output after last transmission. "
+       "When RP[] = 0xFF, output will always be on (0 - 0xFF, default "
+       "is 0x28[] = 4 seconds).";
+#endif
+
+static const char PROGMEM atcmd28_name[] = "1S";
+static const char PROGMEM atcmd28_desc[] = "sensor-sample";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd28_help[] =
+       "Forces a sample to be taken on an XBee Sensor device.";
+#endif
+
+static const char PROGMEM atcmd29_name[] = "D0";
+static const char PROGMEM atcmd29_desc[] = "dio0-ad0";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd29_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd30_name[] = "D1";
+static const char PROGMEM atcmd30_desc[] = "dio1-ad1";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd30_help[] =
+       "AD1/DIO1 Configuration. (0 - unmonitored input, "
+       "2 - analog input, 3 - digital input, 4 - digital output "
+       "low, 5 - digital output high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd31_name[] = "D2";
+static const char PROGMEM atcmd31_desc[] = "dio2-ad2";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd31_help[] =
+       "AD2/DIO2 Configuration. (0 - unmonitored input, "
+       "2 - analog input, 3 - digital input, 4 - digital output "
+       "low, 5 - digital output high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd32_name[] = "D3";
+static const char PROGMEM atcmd32_desc[] = "dio3-ad3";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd32_help[] =
+       "AD3/DIO3 Configuration. (0 - unmonitored input, "
+       "2 - analog input, 3 - digital input, 4 - digital output "
+       "low, 5 - digital output high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd33_name[] = "D4";
+static const char PROGMEM atcmd33_desc[] = "dio4-ad4";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd33_help[] =
+       "AD4/DIO4 Configuration. (0 - unmonitored input, "
+       "2 - analog input, 3 - digital input, 4 - digital output "
+       "low, 5 - digital output high). Default is 0.";
+#endif
+
+static const char PROGMEM atcmd34_name[] = "D5";
+static const char PROGMEM atcmd34_desc[] = "dio5-ad5";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd34_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd35_name[] = "D8";
+static const char PROGMEM atcmd35_desc[] = "dio8-sleep-rq";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd35_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd36_name[] = "D9";
+static const char PROGMEM atcmd36_desc[] = "dio9-on-sleep";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd36_help[] =
+       "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 ?.";
+#endif
+
+static const char PROGMEM atcmd37_name[] = "PR";
+static const char PROGMEM atcmd37_desc[] = "pull-up-resistor";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd37_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd38_name[] = "M0";
+static const char PROGMEM atcmd38_desc[] = "pwm0-out-level";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd38_help[] =
+       "PWM0 Output Level. The line should be configured as a PWM "
+       "output using the P0 command (0 to 0x3FF, default is 0).";
+#endif
+
+static const char PROGMEM atcmd39_name[] = "M1";
+static const char PROGMEM atcmd39_desc[] = "pwm1-out-level";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd39_help[] =
+       "PWM1 Output Level. The line should be configured as a PWM "
+       "output using the P1 command (0 to 0x3FF, default is 0).";
+#endif
+
+static const char PROGMEM atcmd40_name[] = "LT";
+static const char PROGMEM atcmd40_desc[] = "led-blink-time";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd40_help[] =
+       "Associate LED Blink Time (should be enabled through D5 ";
+#endif
+
+static const char PROGMEM atcmd41_name[] = "IS";
+static const char PROGMEM atcmd41_desc[] = "force-sample";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd41_help[] =
+       "Forces a read of all enabled digital and "
+       "analog input lines.";
+#endif
+
+static const char PROGMEM atcmd42_name[] = "IC";
+static const char PROGMEM atcmd42_desc[] = "digital-change-detect";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd42_help[] =
+       "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";
+#endif
+
+static const char PROGMEM atcmd43_name[] = "IR";
+static const char PROGMEM atcmd43_desc[] = "io-sample-rate";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd43_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd44_name[] = "CB";
+static const char PROGMEM atcmd44_desc[] = "comissioning-button";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd44_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd45_name[] = "VR";
+static const char PROGMEM atcmd45_desc[] = "firmware-version";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd45_help[] =
+       "Firmware version of the module (read only).";
+#endif
+
+static const char PROGMEM atcmd46_name[] = "HV";
+static const char PROGMEM atcmd46_desc[] = "hardware-version";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd46_help[] =
+       "Hardware version of the module (read only).";
+#endif
+
+static const char PROGMEM atcmd47_name[] = "CK";
+static const char PROGMEM atcmd47_desc[] = "config-code";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd47_help[] =
+       "Configuration Code, that can be used as a quick "
+       "check to determine if a node has been configured as "
+       "desired (read-only, 0-0xFFFFFFFF).";
+#endif
+
+static const char PROGMEM atcmd48_name[] = "ER";
+static const char PROGMEM atcmd48_desc[] = "rf-errors";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd48_help[] =
+       "Number of times a packet was received which contained errors "
+       "of some sort. Read-only, saturate at 0xFFFF.";
+#endif
+
+static const char PROGMEM atcmd49_name[] = "GD";
+static const char PROGMEM atcmd49_desc[] = "good-packets";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd49_help[] =
+       "Number of good received frames. Read-only, saturate at "
+       "0xFFFF.";
+#endif
+
+static const char PROGMEM atcmd50_name[] = "RP";
+static const char PROGMEM atcmd50_desc[] = "rssi-pwm-timer";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd50_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd51_name[] = "TR";
+static const char PROGMEM atcmd51_desc[] = "tx-errors";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd51_help[] =
+       "Transmission Errors, the number of MAC frames that "
+       "exhaust MAC retries without ever receiving a MAC "
+       "acknowledgement message. Read-only, saturate at 0xFFFF.";
+#endif
+
+static const char PROGMEM atcmd52_name[] = "TP";
+static const char PROGMEM atcmd52_desc[] = "temperature";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd52_help[] =
+       "Temperature. Read module temperature in (tenths of ?) "
+       "Celsius. Negatives temperatures can be returned (read-only, "
+       "from 0xff74 [-140] to 0x0258 [600]).";
+#endif
+
+static const char PROGMEM atcmd53_name[] = "DB";
+static const char PROGMEM atcmd53_desc[] = "rx-signal-strength";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd53_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd54_name[] = "DC";
+static const char PROGMEM atcmd54_desc[] = "duty-cycle";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd54_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd55_name[] = "RC";
+static const char PROGMEM atcmd55_desc[] = "rssi-for-channel";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd55_help[] =
+       "Reads the dBm level (RSSI) of the designated "
+       "channel.";
+#endif
+
+static const char PROGMEM atcmd56_name[] = "R#";
+static const char PROGMEM atcmd56_desc[] = "reset-number";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd56_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd57_name[] = "TA";
+static const char PROGMEM atcmd57_desc[] = "tx-ack-errors";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd57_help[] =
+       "Transmit Acknowlegement Errors. Incremented once for "
+       "each failed ack retry (read-only, from 0 to 0xFFFF).";
+#endif
+
+static const char PROGMEM atcmd58_name[] = "%V";
+static const char PROGMEM atcmd58_desc[] = "supply-voltage";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd58_help[] =
+       "Voltage on the Vcc pin in mV (read-only, from 0 to 0xF00).";
+#endif
+
+static const char PROGMEM atcmd59_name[] = "CT";
+static const char PROGMEM atcmd59_desc[] = "cmd-mode-timeout";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd59_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd60_name[] = "CN";
+static const char PROGMEM atcmd60_desc[] = "exit-cmd-mode";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd60_help[] =
+       "Exit Command Mode.";
+#endif
+
+static const char PROGMEM atcmd61_name[] = "GT";
+static const char PROGMEM atcmd61_desc[] = "guard-times";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd61_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd62_name[] = "CC";
+static const char PROGMEM atcmd62_desc[] = "command-chars";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd62_help[] =
+       "Command Character used between guard times of the AT Command "
+       "Mode Sequence (0 to 0xFF, default is 0x2B).";
+#endif
+
+static const char PROGMEM atcmd63_name[] = "ID";
+static const char PROGMEM atcmd63_desc[] = "network-id";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd63_help[] =
+       "Network ID. Nodes must have the same network identifier "
+       "to communicate (0 to 0x7FFF, default is 0x7FFF).";
+#endif
+
+static const char PROGMEM atcmd64_name[] = "NT";
+static const char PROGMEM atcmd64_desc[] = "ndisc-timeout";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd64_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd65_name[] = "NI";
+static const char PROGMEM atcmd65_desc[] = "node-id";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd65_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd66_name[] = "DN";
+static const char PROGMEM atcmd66_desc[] = "disc-node";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd66_help[] = /* XXX */
+       "Resolves a Node Identifier string to a physical address "
+       "(case sensitive). 0xFFFE and the 64bits extended address are "
+       "returned.";
+#endif
+
+static const char PROGMEM atcmd67_name[] = "ND";
+static const char PROGMEM atcmd67_desc[] = "network-discover";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd67_help[] = "Network Discovery, see doc"; /* XXX */
+#endif
+
+static const char PROGMEM atcmd68_name[] = "NO";
+static const char PROGMEM atcmd68_desc[] = "ndisc-options";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd68_help[] =
+       "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.";
+#endif
+
+static const char PROGMEM atcmd69_name[] = "EE";
+static const char PROGMEM atcmd69_desc[] = "security enable";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd69_help[] =
+       "Enable or disable 128-bit AES encryption (0 or 1, 0 is the "
+       "default).";
+#endif
+
+static const char PROGMEM atcmd70_name[] = "KY"; /* XXX */;
+static const char PROGMEM atcmd70_desc[] = "security-key";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd70_help[] =
+       "The 128bits security key (the command is write-only).";
+#endif
+
+static const char PROGMEM atcmd71_name[] = "MT";
+static const char PROGMEM atcmd71_desc[] = "bcast-multi-xmit";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd71_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd72_name[] = "RR";
+static const char PROGMEM atcmd72_desc[] = "unicast-retries";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd72_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd73_name[] = "PL";
+static const char PROGMEM atcmd73_desc[] = "power-level";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd73_help[] =
+       "Power Level of RF transmitter (0 - 1mW, 1 - 23mW, 2 - 100mW, "
+       "3 - 158 mW, 4 - 316 mW). Default is 4.";
+#endif
+
+static const char PROGMEM atcmd74_name[] = "SM";
+static const char PROGMEM atcmd74_desc[] = "sleep-mode";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd74_help[] =
+       "Sleep Mode (0 - disabled, 1 - pin sleep, 4 - async cyclic "
+       "sleep, 5 - async cyclic sleep with pin wakeup). Default "
+       "is 0.";
+#endif
+
+static const char PROGMEM atcmd75_name[] = "SO";
+static const char PROGMEM atcmd75_desc[] = "sleep-options";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd75_help[] =
+       "Sleep Options bitmask (bit8 - always wake for ST time). "
+       "Default is 0.";
+#endif
+
+static const char PROGMEM atcmd76_name[] = "ST";
+static const char PROGMEM atcmd76_desc[] = "wake-time";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd76_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd77_name[] = "SP";
+static const char PROGMEM atcmd77_desc[] = "sleep-period";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd77_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd78_name[] = "SN";
+static const char PROGMEM atcmd78_desc[] = "num-sleep-periods";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd78_help[] =
+       "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).";
+#endif
+
+static const char PROGMEM atcmd79_name[] = "WH";
+static const char PROGMEM atcmd79_desc[] = "wake-host";
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+static const char PROGMEM atcmd79_help[] = "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.";
+#endif
+
+const struct xbee_atcmd PROGMEM xbee_atcmd_list[] = {
+       {
+               /* "WR" */
+               atcmd0_name,
+               atcmd0_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd0_help,
+#endif
+       },
+       {
+               /* "RE" */
+               atcmd1_name,
+               atcmd1_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd1_help,
+#endif
+       },
+       {
+               /* "FR" */
+               atcmd2_name,
+               atcmd2_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd2_help,
+#endif
+       },
+       {
+               /* "AC" */
+               atcmd3_name,
+               atcmd3_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd3_help,
+#endif
+       },
+       {
+               /* "R1" */
+               atcmd4_name,
+               atcmd4_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd4_help,
+#endif
+       },
+       {
+               /* "VL" */
+               atcmd5_name,
+               atcmd5_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd5_help,
+#endif
+       },
+       {
+               /* "DH" */
+               atcmd6_name,
+               atcmd6_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd6_help,
+#endif
+       },
+       {
+               /* "DL" */
+               atcmd7_name,
+               atcmd7_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd7_help,
+#endif
+       },
+       {
+               /* "DD" */
+               atcmd8_name,
+               atcmd8_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd8_help,
+#endif
+       },
+       {
+               /* "SH" */
+               atcmd9_name,
+               atcmd9_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd9_help,
+#endif
+       },
+       {
+               /* "SL" */
+               atcmd10_name,
+               atcmd10_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd10_help,
+#endif
+       },
+       {
+               /* "SE" */
+               atcmd11_name,
+               atcmd11_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd11_help,
+#endif
+       },
+       {
+               /* "DE" */
+               atcmd12_name,
+               atcmd12_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd12_help,
+#endif
+       },
+       {
+               /* "CI" */
+               atcmd13_name,
+               atcmd13_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd13_help,
+#endif
+       },
+       {
+               /* "NP" */
+               atcmd14_name,
+               atcmd14_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd14_help,
+#endif
+       },
+       {
+               /* "CE" */
+               atcmd15_name,
+               atcmd15_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd15_help,
+#endif
+       },
+       {
+               /* "AP" */
+               atcmd16_name,
+               atcmd16_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd16_help,
+#endif
+       },
+       {
+               /* "AO" */
+               atcmd17_name,
+               atcmd17_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd17_help,
+#endif
+       },
+       {
+               /* "BD" */
+               atcmd18_name,
+               atcmd18_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd18_help,
+#endif
+       },
+       {
+               /* "RO" */
+               atcmd19_name,
+               atcmd19_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd19_help,
+#endif
+       },
+       {
+               /* "FT" */
+               atcmd20_name,
+               atcmd20_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd20_help,
+#endif
+       },
+       {
+               /* "NB" */
+               atcmd21_name,
+               atcmd21_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd21_help,
+#endif
+       },
+       {
+               /* "D7" */
+               atcmd22_name,
+               atcmd22_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd22_help,
+#endif
+       },
+       {
+               /* "D6" */
+               atcmd23_name,
+               atcmd23_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd23_help,
+#endif
+       },
+       {
+               /* "P0" */
+               atcmd24_name,
+               atcmd24_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd24_help,
+#endif
+       },
+       {
+               /* "P1" */
+               atcmd25_name,
+               atcmd25_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd25_help,
+#endif
+       },
+       {
+               /* "P2" */
+               atcmd26_name,
+               atcmd26_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd26_help,
+#endif
+       },
+       {
+               /* "RP" */
+               atcmd27_name,
+               atcmd27_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd27_help,
+#endif
+       },
+       {
+               /* "1S" */
+               atcmd28_name,
+               atcmd28_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd28_help,
+#endif
+       },
+       {
+               /* "D0" */
+               atcmd29_name,
+               atcmd29_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd29_help,
+#endif
+       },
+       {
+               /* "D1" */
+               atcmd30_name,
+               atcmd30_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd30_help,
+#endif
+       },
+       {
+               /* "D2" */
+               atcmd31_name,
+               atcmd31_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd31_help,
+#endif
+       },
+       {
+               /* "D3" */
+               atcmd32_name,
+               atcmd32_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd32_help,
+#endif
+       },
+       {
+               /* "D4" */
+               atcmd33_name,
+               atcmd33_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd33_help,
+#endif
+       },
+       {
+               /* "D5" */
+               atcmd34_name,
+               atcmd34_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd34_help,
+#endif
+       },
+       {
+               /* "D8" */
+               atcmd35_name,
+               atcmd35_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd35_help,
+#endif
+       },
+       {
+               /* "D9" */
+               atcmd36_name,
+               atcmd36_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd36_help,
+#endif
+       },
+       {
+               /* "PR" */
+               atcmd37_name,
+               atcmd37_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd37_help,
+#endif
+       },
+       {
+               /* "M0" */
+               atcmd38_name,
+               atcmd38_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd38_help,
+#endif
+       },
+       {
+               /* "M1" */
+               atcmd39_name,
+               atcmd39_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd39_help,
+#endif
+       },
+       {
+               /* "LT" */
+               atcmd40_name,
+               atcmd40_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd40_help,
+#endif
+       },
+       {
+               /* "IS" */
+               atcmd41_name,
+               atcmd41_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd41_help,
+#endif
+       },
+       {
+               /* "IC" */
+               atcmd42_name,
+               atcmd42_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd42_help,
+#endif
+       },
+       {
+               /* "IR" */
+               atcmd43_name,
+               atcmd43_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd43_help,
+#endif
+       },
+       {
+               /* "CB" */
+               atcmd44_name,
+               atcmd44_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd44_help,
+#endif
+       },
+       {
+               /* "VR" */
+               atcmd45_name,
+               atcmd45_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd45_help,
+#endif
+       },
+       {
+               /* "HV" */
+               atcmd46_name,
+               atcmd46_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd46_help,
+#endif
+       },
+       {
+               /* "CK" */
+               atcmd47_name,
+               atcmd47_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd47_help,
+#endif
+       },
+       {
+               /* "ER" */
+               atcmd48_name,
+               atcmd48_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd48_help,
+#endif
+       },
+       {
+               /* "GD" */
+               atcmd49_name,
+               atcmd49_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd49_help,
+#endif
+       },
+       {
+               /* "RP" */
+               atcmd50_name,
+               atcmd50_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd50_help,
+#endif
+       },
+       {
+               /* "TR" */
+               atcmd51_name,
+               atcmd51_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd51_help,
+#endif
+       },
+       {
+               /* "TP" */
+               atcmd52_name,
+               atcmd52_desc,
+               XBEE_ATCMD_F_PARAM_S16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd52_help,
+#endif
+       },
+       {
+               /* "DB" */
+               atcmd53_name,
+               atcmd53_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd53_help,
+#endif
+       },
+       {
+               /* "DC" */
+               atcmd54_name,
+               atcmd54_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd54_help,
+#endif
+       },
+       {
+               /* "RC" */
+               atcmd55_name,
+               atcmd55_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd55_help,
+#endif
+       },
+       {
+               /* "R#" */
+               atcmd56_name,
+               atcmd56_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd56_help,
+#endif
+       },
+       {
+               /* "TA" */
+               atcmd57_name,
+               atcmd57_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd57_help,
+#endif
+       },
+       {
+               /* "%V" */
+               atcmd58_name,
+               atcmd58_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd58_help,
+#endif
+       },
+       {
+               /* "CT" */
+               atcmd59_name,
+               atcmd59_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd59_help,
+#endif
+       },
+       {
+               /* "CN" */
+               atcmd60_name,
+               atcmd60_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd60_help,
+#endif
+       },
+       {
+               /* "GT" */
+               atcmd61_name,
+               atcmd61_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd61_help,
+#endif
+       },
+       {
+               /* "CC" */
+               atcmd62_name,
+               atcmd62_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd62_help,
+#endif
+       },
+       {
+               /* "ID" */
+               atcmd63_name,
+               atcmd63_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd63_help,
+#endif
+       },
+       {
+               /* "NT" */
+               atcmd64_name,
+               atcmd64_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd64_help,
+#endif
+       },
+       {
+               /* "NI" */
+               atcmd65_name,
+               atcmd65_desc,
+               XBEE_ATCMD_F_PARAM_STRING_20B | XBEE_ATCMD_F_READ |
+               XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd65_help,
+#endif
+       },
+       {
+               /* "DN" */
+               atcmd66_name,
+               atcmd66_desc,
+               XBEE_ATCMD_F_PARAM_STRING_20B | XBEE_ATCMD_F_READ |
+               XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd66_help,
+#endif
+       },
+       {
+               /* "ND" */
+               atcmd67_name,
+               atcmd67_desc,
+               XBEE_ATCMD_F_PARAM_NONE | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd67_help,
+#endif
+       },
+       {
+               /* "NO" */
+               atcmd68_name,
+               atcmd68_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd68_help,
+#endif
+       },
+       {
+               /* "EE" */
+               atcmd69_name,
+               atcmd69_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd69_help,
+#endif
+       },
+       {
+               /* "KY"  XXX */
+               atcmd70_name,
+               atcmd70_desc,
+               XBEE_ATCMD_F_PARAM_HEXBUF_16B | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd70_help,
+#endif
+       },
+       {
+               /* "MT" */
+               atcmd71_name,
+               atcmd71_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd71_help,
+#endif
+       },
+       {
+               /* "RR" */
+               atcmd72_name,
+               atcmd72_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd72_help,
+#endif
+       },
+       {
+               /* "PL" */
+               atcmd73_name,
+               atcmd73_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd73_help,
+#endif
+       },
+       {
+               /* "SM" */
+               atcmd74_name,
+               atcmd74_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd74_help,
+#endif
+       },
+       {
+               /* "SO" */
+               atcmd75_name,
+               atcmd75_desc,
+               XBEE_ATCMD_F_PARAM_U8 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd75_help,
+#endif
+       },
+       {
+               /* "ST" */
+               atcmd76_name,
+               atcmd76_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd76_help,
+#endif
+       },
+       {
+               /* "SP" */
+               atcmd77_name,
+               atcmd77_desc,
+               XBEE_ATCMD_F_PARAM_U32 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd77_help,
+#endif
+       },
+       {
+               /* "SN" */
+               atcmd78_name,
+               atcmd78_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd78_help,
+#endif
+       },
+       {
+               /* "WH" */
+               atcmd79_name,
+               atcmd79_desc,
+               XBEE_ATCMD_F_PARAM_U16 | XBEE_ATCMD_F_READ | XBEE_ATCMD_F_WRITE,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               atcmd79_help,
+#endif
+       },
+       {
+               NULL,
+               NULL,
+               0,
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+               NULL,
+#endif
+       },
+};
+
+const struct xbee_atcmd *xbee_atcmd_lookup_name(const char *atcmd_str)
+{
+       const struct xbee_atcmd *cmd;
+       struct xbee_atcmd copy;
+
+       for (cmd = &xbee_atcmd_list[0], memcpy_P(&copy, cmd, sizeof(copy));
+            copy.name != NULL;
+            cmd++, memcpy_P(&copy, cmd, sizeof(copy))) {
+
+               if (!strcmp_P(atcmd_str, copy.name))
+                       break;
+       }
+
+       if (copy.name == NULL) /* not found */
+               return NULL;
+
+       return cmd;
+}
+
+const struct xbee_atcmd *xbee_atcmd_lookup_desc(const char *desc)
+{
+       const struct xbee_atcmd *cmd;
+       struct xbee_atcmd copy;
+
+       for (cmd = &xbee_atcmd_list[0], memcpy_P(&copy, cmd, sizeof(copy));
+            copy.name != NULL;
+            cmd++, memcpy_P(&copy, cmd, sizeof(copy))) {
+               if (!strcmp_P(desc, copy.desc))
+                       break;
+       }
+       if (copy.name == NULL) /* not found */
+               return NULL;
+
+       return cmd;
+}
diff --git a/modules/devices/radio/xbee/xbee_atcmd.h b/modules/devices/radio/xbee/xbee_atcmd.h
new file mode 100644 (file)
index 0000000..0bde226
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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 {
+       PGM_P name;
+       PGM_P desc;
+       unsigned int flags;
+#ifdef CONFIG_MODULE_XBEE_ATCMD_HELP
+       PGM_P help;
+#endif
+};
+
+extern const struct xbee_atcmd PROGMEM xbee_atcmd_list[];
+
+const struct xbee_atcmd *xbee_atcmd_lookup_name(const char *atcmd_str);
+const struct xbee_atcmd *xbee_atcmd_lookup_desc(const char *desc);
+
+#endif /* _xBEE_ATCMD_H_ */
diff --git a/modules/devices/radio/xbee/xbee_neighbor.c b/modules/devices/radio/xbee/xbee_neighbor.c
new file mode 100644 (file)
index 0000000..46ea014
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <aversive.h>
+#include <aversive/queue.h>
+#include <aversive/pgmspace.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_atcmd.h"
+#include "xbee_stats.h"
+#include "xbee_rxtx.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))
+                       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)
+                       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_P(neigh->name, sizeof(neigh->name), PSTR("%s"), name);
+       LIST_INSERT_HEAD(&dev->neigh_list, neigh, next);
+
+       return neigh;
+}
+
+void xbee_neigh_del(struct xbee_dev *dev, struct xbee_neigh *neigh)
+{
+       dev = dev; /* silent compiler */
+       LIST_REMOVE(neigh, next);
+       free(neigh);
+}
diff --git a/modules/devices/radio/xbee/xbee_neighbor.h b/modules/devices/radio/xbee/xbee_neighbor.h
new file mode 100644 (file)
index 0000000..70d7585
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XBEE_NEIGHBOR_H_
+#define _XBEE_NEIGHBOR_H_
+
+#include <aversive/queue.h>
+
+struct xbee_neigh {
+       LIST_ENTRY(xbee_neigh) next;
+       char name[21];
+       uint64_t addr;
+};
+
+struct xbee_dev;
+
+/* define struct xbee_neigh_list */
+LIST_HEAD(xbee_neigh_list, xbee_neigh);
+
+/* init neighbor list of an xbee device */
+void xbee_neigh_init(struct xbee_dev *dev);
+
+/* return a neighbor from its name */
+struct xbee_neigh *xbee_neigh_lookup(struct xbee_dev *dev, const char *name);
+
+/* return a neighbor from its address (in host order) */
+struct xbee_neigh *xbee_neigh_rlookup(struct xbee_dev *dev, uint64_t addr);
+
+/* add a neighbor */
+struct xbee_neigh *xbee_neigh_add(struct xbee_dev *dev, const char *name,
+                                 uint64_t addr);
+
+/* del a neighbor from list */
+void xbee_neigh_del(struct xbee_dev *dev, struct xbee_neigh *neigh);
+
+#endif /* _XBEE_NEIGHBOR_H_ */
diff --git a/modules/devices/radio/xbee/xbee_rxtx.c b/modules/devices/radio/xbee/xbee_rxtx.c
new file mode 100644 (file)
index 0000000..88699a8
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * 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 <aversive.h>
+#include <aversive/pgmspace.h>
+#include <aversive/queue.h>
+#include <aversive/endian.h>
+
+#include <uart.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_rxtx.h"
+#include "xbee.h"
+
+/* Return -1 if the frame is invalid. The arguments buf and len correspond to
+ * the whole xbee frame, from delimiter to cksum.  */
+static int xbee_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. The arguments buf and len correspond to
+ * the whole xbee frame, from delimiter to cksum.  */
+static int xbee_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;
+}
+
+/* Parse the reception of a "xmit status message". The arguments buf and len
+ * correspond to the whole xbee frame, from delimiter to cksum. Return -1 if the
+ * frame is invalid */
+static int xbee_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 the frame stored in the xbee_dev structure: return 0 if the frame is
+ * valid, else a negative value */
+static void xbee_parse_frame(struct xbee_dev *dev)
+{
+       void *buf = dev->frame;
+       uint8_t len = dev->frame_len;
+       uint8_t hdrlen;
+       struct xbee_hdr *hdr = buf;
+       int i;
+       uint8_t cksum = 0;
+       int channel = XBEE_DEFAULT_CHANNEL;
+
+       dev->stats.rx_frame++;
+
+       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_P(stderr, PSTR("Frame too small\r\n"));
+               return;
+       }
+
+       /* 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_P(stderr, PSTR("Invalid cksum\r\n"));
+               dev->stats.rx_invalid_cksum++;
+               return;
+       }
+
+       /* 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_parse_atresp(dev, buf, len) < 0)
+                               return;
+                       channel = hdr->id;
+                       break;
+               case XBEE_TYPE_RMT_ATRESP:
+                       if (xbee_parse_rmt_atresp(dev, buf, len) < 0)
+                               return;
+                       channel = hdr->id;
+                       break;
+               case XBEE_TYPE_XMIT_STATUS:
+                       if (xbee_parse_xmit_status(dev, buf, len) < 0)
+                               return;
+                       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)
+               return;
+       if (dev->channel[channel].rx_cb(dev, channel, hdr->type,
+                                       buf + hdrlen,
+                                       len - hdrlen - 1,
+                                       dev->channel[channel].arg) < 0)
+               dev->stats.rx_usr_error++;
+}
+
+int xbee_tx_iovec(struct xbee_dev *dev, uint8_t channel_id, uint8_t type,
+       const struct xbee_msg *msg)
+{
+       struct xbee_hdr hdr;
+       unsigned i, j;
+       uint8_t cksum = 0;
+       unsigned len = 0;
+
+       for (i = 0; i < msg->iovlen; i++)
+               len += msg->iov[i].len;
+
+       /* 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;
+
+       if (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 < msg->iovlen; i++) {
+               for (j = 0; j < msg->iov[i].len; j++)
+                       cksum += ((uint8_t *)msg->iov[i].buf)[j];
+       }
+       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_P(stderr, PSTR("unhandled xmit type=%x\r\n"),
+                                 hdr.type);
+                       return -1;
+       }
+
+       /* send the frame on the wire */
+       fwrite(&hdr, 1, sizeof(hdr), dev->file);
+       for (i = 0; i < msg->iovlen; i++)
+               fwrite(msg->iov[i].buf, 1, msg->iov[i].len, dev->file);
+       fwrite(&cksum, 1, 1, dev->file);
+
+       return 0;
+}
+
+int xbee_tx(struct xbee_dev *dev, uint8_t channel_id, uint8_t type,
+       char *buf, unsigned len)
+{
+       struct xbee_msg msg;
+       msg.iovlen = 1;
+       msg.iov[0].buf = buf;
+       msg.iov[0].len = len;
+       return xbee_tx_iovec(dev, channel_id, type, &msg);
+}
+
+void xbee_rx(struct xbee_dev *dev)
+{
+       uint8_t framelen;
+       struct xbee_hdr *hdr = (struct xbee_hdr *)dev->frame;
+       int c;
+
+       while (1) {
+
+               /* read from UART */
+               c = fgetc(dev->file);
+               if (c == EOF)
+                       break;
+
+               /* frame too long XXX stats */
+               if (dev->frame_len >= XBEE_MAX_FRAME_LEN) {
+                       dev->frame_len = 0;
+                       continue;
+               }
+
+               if (dev->frame_len == 0 && c != XBEE_DELIMITER)
+                       continue;
+
+               dev->frame[dev->frame_len++] = c;
+
+               /* not enough data to read len */
+               if (dev->frame_len < sizeof(*hdr))
+                       continue;
+
+               framelen = ntohs(hdr->len);
+               framelen += 4; /* 1 for delimiter, 2 for len, 1 for cksum */
+
+               /* frame too long XXX stats */
+               if (framelen >= XBEE_MAX_FRAME_LEN) {
+                       dev->frame_len = 0;
+                       dev->stats.rx_frame++;
+                       dev->stats.rx_frame_too_large++;
+                       continue;
+               }
+
+               /* not enough data */
+               if (dev->frame_len < framelen)
+                       continue;
+
+               xbee_parse_frame(dev);
+               dev->frame_len = 0;
+       }
+}
diff --git a/modules/devices/radio/xbee/xbee_rxtx.h b/modules/devices/radio/xbee/xbee_rxtx.h
new file mode 100644 (file)
index 0000000..67e175f
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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_RXTX_H_
+#define _XBEE_RXTX_H_
+
+/* protocol headers */
+
+#define XBEE_DELIMITER 0x7E
+#define XBEE_MAX_FRAME_LEN 0x50
+
+struct xbee_hdr {
+       uint8_t delimiter;
+       uint16_t len;
+       uint8_t type;
+       uint8_t id;
+} __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;
+
+struct xbee_iovec {
+       void *buf;     /* Buffer */
+       unsigned len;  /* Number of bytes in the buffer */
+};
+
+#define XBEE_MSG_MAXIOV 4
+struct xbee_msg {
+       struct xbee_iovec iov[XBEE_MSG_MAXIOV]; /* scatter/gather array */
+       unsigned iovlen;                        /* number of valid iov */
+};
+
+/* send a frame */
+int xbee_tx(struct xbee_dev *dev, uint8_t id, uint8_t type,
+       char *buf, unsigned len);
+
+/* send a frame using an iovec */
+int xbee_tx_iovec(struct xbee_dev *dev, uint8_t id, uint8_t type,
+       const struct xbee_msg *msg);
+
+/* process the content of the rx buffer and decode incoming frames */
+void xbee_rx(struct xbee_dev *dev);
+
+#endif /* _XBEE_RXTX_H_ */
diff --git a/modules/devices/radio/xbee/xbee_stats.c b/modules/devices/radio/xbee/xbee_stats.c
new file mode 100644 (file)
index 0000000..c47f185
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 <aversive.h>
+#include <aversive/pgmspace.h>
+#include <aversive/queue.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "xbee_neighbor.h"
+#include "xbee_stats.h"
+#include "xbee_rxtx.h"
+#include "xbee.h"
+
+struct xbee_stats *xbee_get_stats(struct xbee_dev *dev)
+{
+#ifdef CONFIG_MODULE_XBEE_STATS
+       return &dev->stats;
+#else
+       (void)dev;
+       return NULL;
+#endif
+}
+
+void xbee_reset_stats(struct xbee_dev *dev)
+{
+       (void)dev;
+#ifdef CONFIG_MODULE_XBEE_STATS
+       memset(&dev->stats, 0, sizeof(dev->stats));
+#endif
+}
+
+void xbee_dump_stats(struct xbee_dev *dev)
+{
+#ifdef CONFIG_MODULE_XBEE_STATS
+       printf_P(PSTR("statistics on xbee_dev %p:\r\n"), dev);
+       printf_P(PSTR(" rx_frame: %"PRIu32"\r\n"), dev->stats.rx_frame);
+       printf_P(PSTR(" rx_atresp: %"PRIu32"\r\n"), dev->stats.rx_atresp);
+       printf_P(PSTR(" rx_atresp_error: %"PRIu32"\r\n"), dev->stats.rx_atresp_error);
+       printf_P(PSTR(" rx_modem_status: %"PRIu32"\r\n"), dev->stats.rx_modem_status);
+       printf_P(PSTR(" rx_xmit_status: %"PRIu32"\r\n"), dev->stats.rx_xmit_status);
+       printf_P(PSTR(" rx_xmit_status_error: %"PRIu32"\r\n"), dev->stats.rx_xmit_status_error);
+       printf_P(PSTR(" rx_data: %"PRIu32"\r\n"), dev->stats.rx_data);
+       printf_P(PSTR(" rx_expl_data: %"PRIu32"\r\n"), dev->stats.rx_expl_data);
+       printf_P(PSTR(" rx_node_id: %"PRIu32"\r\n"), dev->stats.rx_node_id);
+       printf_P(PSTR(" rx_rmt_atresp: %"PRIu32"\r\n"), dev->stats.rx_rmt_atresp);
+       printf_P(PSTR(" rx_rmt_atresp_error: %"PRIu32"\r\n"), dev->stats.rx_rmt_atresp_error);
+       printf_P(PSTR(" rx_frame_too_small: %"PRIu32"\r\n"), dev->stats.rx_frame_too_small);
+       printf_P(PSTR(" rx_frame_too_large: %"PRIu32"\r\n"), dev->stats.rx_frame_too_large);
+       printf_P(PSTR(" rx_invalid_cksum: %"PRIu32"\r\n"), dev->stats.rx_invalid_cksum);
+       printf_P(PSTR(" rx_invalid_type: %"PRIu32"\r\n"), dev->stats.rx_invalid_type);
+       printf_P(PSTR(" rx_no_delim: %"PRIu32"\r\n"), dev->stats.rx_no_delim);
+       printf_P(PSTR(" rx_usr_error: %"PRIu32"\r\n"), dev->stats.rx_usr_error);
+       printf_P(PSTR(" tx_frame: %"PRIu32"\r\n"), dev->stats.tx_frame);
+       printf_P(PSTR(" tx_atcmd: %"PRIu32"\r\n"), dev->stats.tx_atcmd);
+       printf_P(PSTR(" tx_atcmd_q: %"PRIu32"\r\n"), dev->stats.tx_atcmd_q);
+       printf_P(PSTR(" tx_data: %"PRIu32"\r\n"), dev->stats.tx_data);
+       printf_P(PSTR(" tx_expl_data: %"PRIu32"\r\n"), dev->stats.tx_expl_data);
+       printf_P(PSTR(" tx_xmit_retries: %"PRIu32"\r\n"), dev->stats.tx_xmit_retries);
+       printf_P(PSTR(" tx_rmt_atcmd: %"PRIu32"\r\n"), dev->stats.tx_rmt_atcmd);
+       printf_P(PSTR(" tx_invalid_type: %"PRIu32"\r\n"), dev->stats.tx_invalid_type);
+       printf_P(PSTR(" tx_invalid_channel: %"PRIu32"\r\n"), dev->stats.tx_invalid_channel);
+#else
+       (void)dev;
+       printf_P(PSTR("Statistics not enabled\r\n"));
+#endif
+}
diff --git a/modules/devices/radio/xbee/xbee_stats.h b/modules/devices/radio/xbee/xbee_stats.h
new file mode 100644 (file)
index 0000000..fc95aff
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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_STATS_H_
+#define _XBEE_STATS_H_
+
+/* per-device statistics */
+struct xbee_stats {
+       uint32_t rx_frame;
+       uint32_t rx_atresp;
+       uint32_t rx_atresp_error;
+       uint32_t rx_modem_status;
+       uint32_t rx_xmit_status;
+       uint32_t rx_xmit_status_error;
+       uint32_t rx_data;
+       uint32_t rx_expl_data;
+       uint32_t rx_node_id;
+       uint32_t rx_rmt_atresp;
+       uint32_t rx_rmt_atresp_error;
+       uint32_t rx_frame_too_small;
+       uint32_t rx_frame_too_large;
+       uint32_t rx_invalid_cksum;
+       uint32_t rx_invalid_type;
+       uint32_t rx_no_delim;
+       uint32_t rx_usr_error;
+
+       uint32_t tx_frame;
+       uint32_t tx_atcmd;
+       uint32_t tx_atcmd_q;
+       uint32_t tx_data;
+       uint32_t tx_expl_data;
+       uint32_t tx_xmit_retries;
+       uint32_t tx_rmt_atcmd;
+       uint32_t tx_invalid_type;
+       uint32_t 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 stdout */
+void xbee_dump_stats(struct xbee_dev *dev);
+
+#endif /* _XBEE_STATS_H_ */