aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbee/Makefile33
-rw-r--r--xbee/max2pd.h19
-rw-r--r--xbee/xbee.c340
-rw-r--r--xbee/xbee.h261
-rw-r--r--xbee/xbee_internal.h248
-rw-r--r--xbee/xbee_io.c268
-rw-r--r--xbee/xbee_io.h34
-rw-r--r--xbee/xbee_protocol.h292
-rw-r--r--xbee/xbee_test-help.pd2
-rw-r--r--xbee/xbee_test.c457
10 files changed, 1954 insertions, 0 deletions
diff --git a/xbee/Makefile b/xbee/Makefile
new file mode 100644
index 0000000..e222c9b
--- /dev/null
+++ b/xbee/Makefile
@@ -0,0 +1,33 @@
+TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|')
+EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|')
+
+default:
+ make -C $(EXTERNALS_ROOT) $(TARGET)
+
+install:
+ make -C $(EXTERNALS_ROOT) $(TARGET)_install
+
+clean:
+ make -C $(EXTERNALS_ROOT) $(TARGET)_clean
+
+test_locations:
+ make -C $(EXTERNALS_ROOT) test_locations
+
+# for emacs
+etags:
+ etags ../../../pd/src/*.h *.[ch]
+ make etags_`uname -s`
+
+etags_Darwin:
+ etags -a \
+ /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \
+ /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \
+ /System/Library/Frameworks/Carbon.framework/Headers/*.h \
+ /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[ch]
+
+etags_Linux:
+ etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
+
+etags_MINGW:
+ etags -a /usr/include/*.h /usr/include/sys/*.h \
+ /usr/local/include/*.h /usr/local/include/sys/*.h
diff --git a/xbee/max2pd.h b/xbee/max2pd.h
new file mode 100644
index 0000000..6f09500
--- /dev/null
+++ b/xbee/max2pd.h
@@ -0,0 +1,19 @@
+/*
+ * this header aims to make it easy to port Max objects to Pd
+ */
+
+/* name changes */
+#define SETSYM SETSYMBOL
+
+/* Pd doesn't have longs */
+#define SETLONG SETFLOAT
+
+/* allocate memory */
+#define sysmem_newptr(size) getbytes(128)
+#define sysmem_freeptr(ptr) freebytes(ptr, 128)
+
+
+#define atom_getlong(atom) atom_getfloatarg(0, 1, atom)
+#define atom_getsym(atom) atom_getsymbolarg(0, 1, atom)
+#define object_alloc(obj_class) pd_new(obj_class)
+#define object_free(obj) pd_free((t_pd*)obj)
diff --git a/xbee/xbee.c b/xbee/xbee.c
new file mode 100644
index 0000000..c243b5f
--- /dev/null
+++ b/xbee/xbee.c
@@ -0,0 +1,340 @@
+/*
+ * xbee.c:
+ * XBee Zigbee module interface functions
+ *
+ * (c) 2006-2008 Tymm Twillman <tymm@booyaka.com>
+ *
+ */
+
+#include <stdint.h>
+#include <string.h> /* for memcpy, memset, etc. */
+
+#include "xbee_protocol.h"
+#include "xbee.h"
+
+
+#ifndef MIN
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+/* In case we need to serialize access for transmission;
+ * reception is made to always come from one XBee module so
+ * shouldn't need to serialize that.
+ */
+
+#ifndef CONFIG_XBEE_REENTRANT_TX
+# define xbee_lock_frame_id(xbee) do {} while(0)
+# define xbee_unlock_frame_id(xbee) do {} while(0)
+#endif
+
+
+/* Error counters can be added later if desired */
+#define xbee_rx_crc_err(xbee) do {} while(0)
+#define xbee_rx_err(xbee) do {} while(0)
+#define xbee_rx_dropped(xbee) do {} while(0)
+#define xbee_tx_err(xbee) do {} while(0)
+#define xbee_tx_dropped(xbee) do {} while(0)
+
+
+# ifdef CONFIG_XBEE_REENTRANT_TX
+# error CONFIG_XBEE_REENTRANT_TX requires XBEE_ALLOC to be set!
+# endif
+
+#ifndef ENOMEM
+# define ENOMEM 12
+#endif
+
+
+
+/* Generate & return next 8-bit frame ID */
+static inline uint8_t xbee_next_frame_id(xbee_t *xbee)
+{
+ uint8_t frame_id;
+
+
+ xbee_lock_frame_id(xbee);
+ if (++xbee->out.frame_id == 0)
+ ++xbee->out.frame_id;
+ frame_id = xbee->out.frame_id;
+ xbee_unlock_frame_id(xbee);
+
+ return frame_id;
+}
+
+
+/* Generate CRC for an XBee packet */
+uint8_t xbee_crc(const xbee_pkt_t *pkt)
+{
+ uint8_t *pkt_data = ((uint8_t *)pkt) + sizeof(xbee_pkt_hdr_t);
+ uint16_t i;
+ uint8_t crc = 0;
+
+
+ for (i = 0; i < ntohs(((xbee_pkt_hdr_t *)pkt)->len); i++)
+ crc += *(pkt_data++);
+
+ return ~crc;
+}
+
+
+/* Accept data from an XBee module & build into valid XBEE
+ * packets
+ */
+void xbee_in(xbee_t *xbee, const void *buf, uint8_t len)
+{
+ uint8_t *data = (uint8_t *)buf;
+
+
+ while(len) {
+ switch(xbee->in.bytes_rcvd) {
+ case 0:
+ while (*data != XBEE_PKT_START) {
+ if (!--len)
+ return;
+ data++;
+ }
+
+ xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++;
+ if (!--len)
+ return;
+
+ /* Fall thru */
+
+ case 1:
+ xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++;
+ if (!--len)
+ return;
+
+ /* Fall thru */
+
+ case 2:
+ xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++;
+
+ /* Got enough to get packet length */
+
+ xbee->in.bytes_left = ntohs(((xbee_pkt_hdr_t *)xbee->in.hdr_data)->len);
+
+ if (xbee->in.bytes_left > XBEE_MAX_DATA_LEN
+ || ((xbee->in.packet
+ = xbee_alloc_pkt_mem(XBEE_RECV, xbee->in.bytes_left + 4)) == NULL)
+ )
+ {
+ xbee->in.bytes_left = 0;
+ xbee_rx_err(xbee);
+ continue;
+ }
+
+ xbee->in.bytes_left++; /* Extra for crc (alloc_pkt already accounts for it) */
+
+ memcpy(&(xbee->in.packet->hdr), &(xbee->in.hdr_data),
+ sizeof(xbee->in.hdr_data));
+
+ if (!--len)
+ return;
+
+ /* Fall thru */
+
+ default:
+ while (xbee->in.bytes_left--) {
+ ((uint8_t *)xbee->in.packet)[xbee->in.bytes_rcvd++] = *data++;
+ if (!--len && xbee->in.bytes_left)
+ return;
+ }
+ }
+
+ if (xbee_crc(xbee->in.packet)
+ != ((uint8_t *)xbee->in.packet)[xbee->in.bytes_rcvd - 1])
+ {
+ xbee->in.bytes_rcvd = 0;
+ xbee_rx_crc_err(xbee);
+ continue;
+ }
+
+ if (xbee_recv_pkt(xbee, xbee->in.packet, xbee->in.bytes_rcvd)) {
+ xbee_free_pkt_mem(xbee->in.packet);
+ xbee_rx_dropped(xbee);
+ }
+
+ xbee->in.bytes_rcvd = 0;
+ }
+}
+
+
+/* Send a command to an XBee module */
+
+int xbee_send_at_cmd(xbee_t *xbee,
+ const char cmd[],
+ uint8_t param_len,
+ const uint8_t params[])
+{
+ xbee_at_cmd_pkt_t *pkt;
+ uint8_t frame_id;
+ int ret;
+
+
+ pkt = (xbee_at_cmd_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, param_len + 8);
+ if (pkt == NULL) {
+ xbee_tx_err();
+ return -ENOMEM;
+ }
+
+ xbee_hdr_init(pkt->hdr, param_len + 4);
+
+ pkt->type = XBEE_PKT_TYPE_ATCMD;
+
+ frame_id = xbee_next_frame_id(xbee);
+
+ pkt->frame_id = frame_id;
+
+ pkt->command[0] = cmd[0];
+ pkt->command[1] = cmd[1];
+
+ memcpy(pkt->param, params, param_len);
+ pkt->param[param_len] = xbee_crc((xbee_pkt_t *)pkt);
+
+ ret = xbee_out(xbee, (xbee_pkt_t *)pkt,
+ sizeof(xbee_at_cmd_pkt_t) + param_len + 1);
+
+ if (ret >= 0)
+ return frame_id;
+
+ xbee_free_pkt_mem((xbee_pkt_t *)pkt);
+
+ xbee_tx_err();
+
+ return ret;
+}
+
+
+/* Send a command to a remote XBee module */
+
+int xbee_send_remote_at_cmd(xbee_t *xbee,
+ const char cmd[],
+ uint8_t param_len,
+ uint8_t apply,
+ const uint8_t params[],
+ const uint8_t addr64[8],
+ const uint8_t addr16[2])
+{
+ xbee_remote_at_cmd_pkt_t *pkt;
+ uint8_t frame_id;
+ int ret;
+
+
+ pkt = (xbee_remote_at_cmd_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, param_len + 19);
+ if (pkt == NULL) {
+ xbee_tx_err();
+ return -ENOMEM;
+ }
+
+ xbee_hdr_init(pkt->hdr, param_len + 15);
+
+ pkt->type = XBEE_PKT_TYPE_REMOTE_ATCMD;
+
+ frame_id = xbee_next_frame_id(xbee);
+ pkt->frame_id = frame_id;
+
+ memcpy(pkt->dest64, addr64, 8);
+ memcpy(pkt->dest16, addr16, 2);
+
+ pkt->apply = apply ? 2:0;
+
+ pkt->command[0] = cmd[0];
+ pkt->command[1] = cmd[1];
+
+ memcpy(pkt->param, params, param_len);
+ pkt->param[param_len] = xbee_crc((xbee_pkt_t *)pkt);
+
+ ret = xbee_out(xbee, (xbee_pkt_t *)pkt,
+ sizeof(xbee_remote_at_cmd_pkt_t) + param_len + 1);
+
+ if (ret >= 0)
+ return frame_id;
+
+ xbee_free_pkt_mem((xbee_pkt_t *)pkt);
+
+ xbee_tx_err();
+
+ return ret;
+}
+
+
+/* Send a data packet to another module using its 64-bit unique ID */
+int xbee_send64(xbee_t *xbee, const void *data, uint8_t len, uint8_t opt, const uint8_t addr[8])
+{
+ xbee_a64_tx_pkt_t *pkt;
+ int ret;
+ uint8_t frame_id;
+
+
+ pkt = (xbee_a64_tx_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, len + 15);
+ if (pkt == NULL) {
+ xbee_tx_err(xbee);
+ return -ENOMEM;
+ }
+
+ xbee_hdr_init(pkt->hdr, len + 11);
+
+ pkt->type = XBEE_PKT_TYPE_TX64;
+ memcpy(pkt->dest, addr, 8);
+ pkt->opt = opt;
+ frame_id = xbee_next_frame_id(xbee);
+ pkt->frame_id = frame_id;
+ memcpy(pkt->data, data, len);
+ pkt->data[len] = xbee_crc((xbee_pkt_t *)pkt);
+
+ ret = xbee_out(xbee, (xbee_pkt_t *)pkt, len + sizeof(xbee_a64_tx_pkt_t) + 1);
+
+ if (ret >= 0)
+ return frame_id;
+
+ xbee_tx_err(xbee);
+
+ xbee_free_pkt_mem((xbee_pkt_t *)pkt);
+
+ return ret;
+}
+
+
+/* Send a data packet to another module using its 16-bit ID */
+int xbee_send16(xbee_t *xbee, const void *data, uint8_t len, uint8_t opt, const uint8_t addr[2])
+{
+ xbee_a16_tx_pkt_t *pkt;
+ uint8_t frame_id;
+ int ret;
+
+
+ pkt = (xbee_a16_tx_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, len + 9);
+ if (pkt == NULL) {
+ xbee_tx_err(xbee);
+ return -ENOMEM;
+ }
+
+ xbee_hdr_init(pkt->hdr, len + 5);
+
+ pkt->type = XBEE_PKT_TYPE_TX16;
+ memcpy(pkt->dest, addr, 2);
+ pkt->opt = opt;
+ frame_id = xbee_next_frame_id(xbee);
+ pkt->frame_id = frame_id;
+ memcpy(pkt->data, (uint8_t *)data, len);
+ pkt->data[len] = xbee_crc((xbee_pkt_t *)pkt);
+
+ ret = xbee_out(xbee, (xbee_pkt_t *)pkt, len + sizeof(xbee_a16_tx_pkt_t) + 1);
+
+ if (ret >= 0)
+ return frame_id;
+
+ xbee_tx_err();
+
+ xbee_free_pkt_mem((xbee_pkt_t *)pkt);
+
+ return ret;
+}
+
+
+/* Initialize this package */
+void xbee_init(xbee_t *xbee)
+{
+ memset(xbee, 0, sizeof(xbee_t));
+}
diff --git a/xbee/xbee.h b/xbee/xbee.h
new file mode 100644
index 0000000..a40487e
--- /dev/null
+++ b/xbee/xbee.h
@@ -0,0 +1,261 @@
+/*
+ * xbee.h:
+ * Maxstream XBee module Interface Header
+ *
+ * (c) 2006-2008 Tymm Twillman <tymm@booyaka.com>
+ *
+ *
+ * NOTE: This doesn't touch hardware; it's up to developers to link in functions
+ * that handle hardware communication.
+ *
+ * DEVELOPERS: Pieces you need to implement (see prototypes, below):
+ * xbee_alloc_pkt_mem (can just return static data)
+ * xbee_free_pkt_mem (can do nothing if not dynamic)
+ *
+ * xbee_out
+ * xbee_recv_pkt
+ *
+ * What you need to call from wherever you read data from UART, etc:
+ * xbee_in
+ *
+ * Incoming data from UART, etc. should be passed to xbee_in; it will
+ * be built into well-formed packets and passed to xbee_recv_pkt
+ * for further processing.
+ *
+ * Outgoing data will be passed to xbee_out to be passed off to
+ * the XBee hardware.
+ *
+ *
+ */
+
+#ifndef XBEE_H
+#define XBEE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <errno.h>
+
+/*----------------------------------------------------------------------------
+ Definitions for commands the XBee recognizes
+ ----------------------------------------------------------------------------*/
+
+/* Basic communication parameters/values */
+
+#define XBEE_CMD_CHANNEL "CH"
+#define XBEE_CMD_PAN_ID "ID"
+#define XBEE_CMD_DEST_ADDR64_HI "DH"
+#define XBEE_CMD_DEST_ADDR64_LO "DL"
+#define XBEE_CMD_SRC_ADDR16 "MY"
+#define XBEE_CMD_SER_HI "SH"
+#define XBEE_CMD_SER_LO "SL"
+#define XBEE_CMD_RAND_DLY_SLOTS "RN"
+#define XBEE_CMD_MAC_MODE "MM"
+#define XBEE_CMD_COORD_ENA "CE"
+#define XBEE_CMD_SCAN "SC"
+#define XBEE_CMD_SCAN_DURATION "SD"
+#define XBEE_CMD_ASSOC_END "A1"
+#define XBEE_CMD_ASSOC_COORD "A2"
+#define XBEE_CMD_ASSOC_STATUS "AI"
+#define XBEE_CMD_RSSI "DB"
+
+/* Transceiver Control */
+
+#define XBEE_CMD_PWR_LEVEL "PL"
+#define XBEE_CMD_CCA_THRESH "CA"
+
+/* Sleep Parameters */
+
+#define XBEE_CMD_SLEEP_MODE "SM"
+#define XBEE_CMD_SLEEP_TIMEOUT "ST"
+#define XBEE_CMD_SLEEP_PERIOD "SP"
+#define XBEE_CMD_SLEEP_PERIOD_DISASSOC "DP"
+
+/* Interface parameters */
+
+#define XBEE_CMD_DATA_RATE "BD"
+#define XBEE_CMD_PACKETIZATION_TIMEOUT "RO"
+#define XBEE_CMD_DIO7_CONFIG "D7"
+#define XBEE_CMD_DIO6_CONFIG "D6"
+#define XBEE_CMD_DIO5_CONFIG "D5"
+#define XBEE_CMD_PWM0_CONFIG "PO"
+#define XBEE_CMD_API_ENA "AP"
+#define XBEE_CMD_PULLUP_ENA "PR"
+
+/* Version Info */
+
+#define XBEE_CMD_VERS_FIRMWARE "VR"
+#define XBEE_CMD_VERS_HARDWARE "HV"
+#define XBEE_CMD_VERS_FIRM_VERBOSE "VL"
+
+/* Received Signal Strength */
+
+#define XBEE_CMD_RSSI_PWM_TIMER "RP"
+#define XBEE_CMD_RSS "DB"
+
+/* Error counters */
+
+#define XBEE_CMD_CCA_FAILS "EC"
+#define XBEE_CMD_ACK_FAILS "EA"
+
+/* AT Command Params */
+
+#define XBEE_CMD_AT_MODE_TIMEOUT "CT"
+#define XBEE_CMD_AT_GUARD_TIME "GT"
+#define XBEE_CMD_AT_CMD_CHAR "CC"
+#define XBEE_CMD_AT_EXIT "CN"
+
+/* XBEE specific routing */
+
+#define XBEE_CMD_NODE_FIND_DEST "DN"
+#define XBEE_CMD_NODE_DISCOVER "ND"
+#define XBEE_CMD_NODE_ID "NI"
+#define XBEE_CMD_ACTIVE_SCAN "AS"
+#define XBEE_CMD_FORCE_DISASSOC "DA"
+#define XBEE_CMD_ENERGY_SCAN "ED"
+#define XBEE_CMD_FORCE_POLL "FP"
+
+/* Misc */
+
+#define XBEE_CMD_WRITE_PARAMS "WR"
+#define XBEE_CMD_RESET_SOFT "FR"
+#define XBEE_CMD_APPLY_CHANGES "AC"
+#define XBEE_CMD_RESTORE_DEFAULTS "RE"
+
+
+/*----------------------------------------------------------------------------
+ Structures usefull for communicating with the XBee in API mode
+ ----------------------------------------------------------------------------*/
+
+/* Packets are wrapped with a start & length */
+typedef struct {
+ uint8_t start; /* 0x7e */
+ uint16_t len;
+} __attribute__ ((__packed__)) xbee_pkt_hdr_t;
+
+
+/* Packets can be broken up into headers, a packet type, a number of data
+ * bytes and a crc (at the end of the data)
+ */
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t data[0];
+ /* uint8_t crc; */
+} __attribute__ ((__packed__)) xbee_pkt_t;
+
+
+/* Context for tracking current state of communication with an
+ * XBee module
+ */
+typedef struct {
+ struct {
+ uint8_t bytes_left;
+ uint8_t bytes_rcvd;
+ xbee_pkt_t *packet;
+ uint8_t hdr_data[sizeof(xbee_pkt_hdr_t)];
+ } in;
+ struct {
+ uint8_t frame_id;
+ } out;
+ void *user_context; // yours to pass data around with
+} __attribute__ ((__packed__)) xbee_t;
+
+/* This is used for keeping track of your data as things get passed around
+ * through the xbee interface
+ */
+#define xbee_user_context(xbee) ((xbee).user_context)
+
+/*----------------------------------------------------------------------------
+ Internal calls
+ ----------------------------------------------------------------------------*/
+
+/* Calculate CRC on an xbee packet */
+uint8_t xbee_crc(const xbee_pkt_t *pkt);
+
+
+/*----------------------------------------------------------------------------
+ Generally all the functions you need to call
+ ----------------------------------------------------------------------------*/
+
+/* Receive data, calling xbee_recv_pkt on each packet when it's done
+ * assembling; this should be called with raw data from UART, etc.
+ * as it comes in. *** YOU NEED TO CALL THIS ***
+ */
+void xbee_in(xbee_t *xbee, const void *data, uint8_t len);
+
+/* Send a packet with a 64-bit destination address (Series 1) */
+int xbee_send64(xbee_t *xbee,
+ const void *data,
+ uint8_t len,
+ uint8_t opt,
+ const uint8_t addr[8]);
+
+/* Send a packet with a 16-bit destination address (Series 1) */
+int xbee_send16(xbee_t *xbee,
+ const void *data,
+ uint8_t len,
+ uint8_t opt,
+ const uint8_t addr[2]);
+
+/* Send a command to the xbee modem */
+int xbee_send_at_cmd(xbee_t *xbee,
+ const char cmd[],
+ uint8_t param_len,
+ const uint8_t *params);
+
+/* Send a command to a remote xbee modem (Series 2 & Newer Series 1 only) */
+int xbee_send_remote_at_cmd(xbee_t *xbee,
+ const char cmd[],
+ uint8_t param_len,
+ uint8_t apply,
+ const uint8_t params[],
+ const uint8_t addr64[8],
+ const uint8_t addr16[2]);
+
+/* Initialize the XBee interface */
+void xbee_init(xbee_t *xbee);
+
+/*----------------------------------------------------------------------------
+ MUST be provided externally to this package
+ ----------------------------------------------------------------------------*/
+
+/* Queue a packet for transmission (needs to queue packet to be sent to XBEE
+ * module; e.g. copy the packet to a UART buffer).
+ * On error, -1 should be returned and the packet should NOT be freed.
+ * On success, 0 should be returned; if XBEE_ALLOC is set, this function or
+ * someone downstream is responsible for freeing it -- the packet has been
+ * handed off. This is to minimize copying of data.
+ */
+int xbee_out(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len);
+
+/* Handle an incoming packet; the packet will be fully formed and verified
+ * for proper construction before being passed off to this function. This
+ * function should dig into the packet & process based on its contents.
+ */
+int xbee_recv_pkt(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len);
+
+
+/*----------------------------------------------------------------------------
+ Must be provided externally only if using dynamic memory (which allows more
+ than one packet to be queued at a time)
+ ----------------------------------------------------------------------------*/
+
+/* Return a buffer for an xbee packet; at least <len> bytes need to be allocated
+ *
+ * Direction since we may want to have different allocations mechanisms/etc
+ * for xmit vs recv.
+ */
+void *xbee_alloc_pkt_mem(uint8_t direction, uint8_t len);
+
+/* Free up an allocated packet */
+void xbee_free_pkt_mem(xbee_pkt_t *pkt);
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* #ifndef XBEE_H ... */
diff --git a/xbee/xbee_internal.h b/xbee/xbee_internal.h
new file mode 100644
index 0000000..83273d4
--- /dev/null
+++ b/xbee/xbee_internal.h
@@ -0,0 +1,248 @@
+#ifndef XBEE_INTERNAL_H
+#define XBEE_INTERNAL_H
+
+#ifdef AVR
+# define __LITTLE_ENDIAN 1234
+# define BYTE_ORDER LITTLE_ENDIAN
+#elif defined(ARM)
+# include <endian.h>
+#else
+# include <arpa/inet.h>
+#endif
+
+#include <stdint.h>
+
+#include "xbee.h"
+
+#if !defined(ntohs) && (BYTE_ORDER == LITTLE_ENDIAN)
+# define ntohs(n) ((((short)(n)) & 0xff00) >> 8 | (((short)(n)) & 0xff) << 8)
+# define htons(n) ntohs(n)
+#elif !defined(ntohs)
+# define ntohs(n) ((short)(n))
+# define htons(n) ntohs(n)
+#endif
+
+#if !defined(ntohl) && (BYTE_ORDER == LITTLE_ENDIAN)
+# define ntohl(x) ((((x)&0xff000000)>>24) \
+ |(((x)&0x00ff0000)>>8) \
+ |(((x)&0x0000ff00)<<8) \
+ |(((x)&0x000000ff)<<24))
+# define htonl(n) ntohl(n)
+#elif !defined(ntohl)
+# define ntohl(n) ((long)(n))
+# define htonl(n) ntohs(n)
+#endif
+
+/* p2p CE=0 (end devices) A1=0 (no end dev assoc) same ID/CH
+ * coordinator: CE=1, A2=n (coordinator assoc)
+ * SP= sleep perd ST= time betw sleep (should be same on
+ * coord/noncoord)
+ * assoc - coord'd only; comm between modules thru coord'r
+ * PAN's - need coordinator. A1 allows totally dynamic assoc
+ */
+
+
+/* --- General XBee Definitions --- */
+
+/* "Start of packet" byte; always sent as the first
+ * byte of each packet
+ */
+#define XBEE_PKT_START 0x7e
+
+
+/* Maximum packet size; datasheet basically says 100 payload bytes max */
+#define XBEE_MAX_DATA_LEN 128
+
+
+/* --- Bits in packets --- */
+
+/* Communication status bits */
+
+#define XBEE_STATUS_HW_RESET 0x01
+#define XBEE_STATUS_WD_RESET 0x02
+#define XBEE_STATUS_ASSOC 0x04
+#define XBEE_STATUS_DISASSOC 0x08
+#define XBEE_STATUS_SYNC_LOST 0x10
+#define XBEE_STATUS_COORD_REALIGN 0x20
+#define XBEE_STATUS_COORD_RESET 0x40
+
+/* Command status bits */
+
+#define XBEE_CMDSTATUS_OK 0
+#define XBEE_CMDSTATUS_ERR 1
+
+/* Transmit options */
+
+#define XBEE_TX_FLAG_NO_ACK 0x01
+#define XBEE_TX_FLAG_SEND_BCAST_PAN_ID 0x04
+
+/* Transmit status bits */
+
+#define XBEE_TXSTATUS_SUCCESS 0x00
+#define XBEE_TXSTATUS_NO_ACK 0x01
+#define XBEE_TXSTATUS_CCA_FAIL 0x02
+#define XBEE_TXSTATUS_PURGES 0x03
+
+/* Received options */
+
+#define XBEE_RX_FLAG_ADDR_BCAST 0x02
+#define XBEE_RX_FLAG_PAN_BCAST 0x04
+
+
+/* --- Definitions & macros for library use --- */
+
+/* For tracking memory allocations */
+#define XBEE_RECV 0x00
+#define XBEE_XMIT 0x01
+
+/* Initialize an XBee header */
+#define xbee_hdr_init(hdr, data_len) \
+ ((hdr).start = 0x7e, (hdr).len = htons(data_len))
+
+/* To get the length of the data portion of a received packet */
+
+#define xbee_recv_a64_data_len(pkt) (ntohs(pkt->hdr.len) - 11)
+#define xbee_recv_a16_data_len(pkt) (ntohs(pkt->hdr.len) - 5)
+#define xbee_cmd_resp_param_len(pkt) (ntohs(pkt->hdr.len) - 5)
+
+#ifdef XBEE_ALLOC
+# define xbee_alloc_pkt(dir, data_len) \
+ (xbee_pkt_t *)xbee_alloc_buf((dir), (data_len) + sizeof(xbee_pkt_hdr_t) + 1)
+#endif
+
+/* Types of packets from/to xbee modules; these are used
+ * in the "type" field of each packet structure
+ */
+
+typedef enum {
+ XBEE_PKT_TYPE_TX64 = 0x00,
+ XBEE_PKT_TYPE_TX16 = 0x01,
+ XBEE_PKT_TYPE_ATCMD = 0x08,
+ XBEE_PKT_TYPE_QATCMD = 0x09, /* wait til an immed param or apply cmd */
+ XBEE_PKT_TYPE_REMOTE_ATCMD = 0x17,
+ XBEE_PKT_TYPE_RX64 = 0x80,
+ XBEE_PKT_TYPE_RX16 = 0x81,
+ XBEE_PKT_TYPE_RX64_IO = 0x82,
+ XBEE_PKT_TYPE_RX16_IO = 0x83,
+ XBEE_PKT_TYPE_ATCMD_RESP = 0x88,
+ XBEE_PKT_TYPE_TX_STATUS = 0x89,
+ XBEE_PKT_TYPE_MODEM_STATUS= 0x8a,
+} xbee_pkt_type_t;
+
+
+/* --- Packet layouts --- */
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t command[2];
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_at_cmd_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest64[8];
+ uint8_t dest16[2];
+ uint8_t apply;
+ uint8_t command[2];
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_remote_at_cmd_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest[8];
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a64_tx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest[2];
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a16_tx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t status;
+} __attribute__ ((__packed__)) xbee_tx_status_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t status;
+} __attribute__ ((__packed__)) xbee_modem_status_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t command[2];
+ uint8_t status;
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_cmd_resp_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[8];
+ uint8_t rssi; /* signal strength */
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a64_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[2];
+ uint8_t rssi;
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a16_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[8];
+ uint8_t rssi; /* signal strength */
+ uint8_t opt;
+ uint8_t num_samples;
+ uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */
+ uint16_t data[0]; /* First sample digital if any digital chan active
+ rest are 16-bit analog rdgs */
+} __attribute__ ((__packed__)) xbee_io_a64_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[2];
+ uint8_t rssi;
+ uint8_t opt;
+ uint8_t num_samples;
+ uint8_t achan;
+ uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */
+ uint16_t data[0]; /* First sample digital if any digital chan active
+ rest are 16-bit analog rdgs */
+} __attribute__ ((__packed__)) xbee_io_a16_rx_pkt_t;
+
+#endif /* #ifndef XBEE_INTERNAL_H ... */
+
diff --git a/xbee/xbee_io.c b/xbee/xbee_io.c
new file mode 100644
index 0000000..d3fe323
--- /dev/null
+++ b/xbee/xbee_io.c
@@ -0,0 +1,268 @@
+/*
+ * xbee_io.c
+ * xbee_test
+ *
+ * Created by Tymm on 11/20/08.
+ * Copyright 2008 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/select.h>
+#include <pthread.h>
+
+#ifdef PD
+#include "m_pd.h"
+#include "max2pd.h"
+#else
+#include "ext.h"
+#endif /* PD */
+
+#include "xbee.h"
+#include "xbee_io.h"
+
+
+#ifndef MIN
+# define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+
+void xbee_io_read(xbee_t *xbee)
+{
+ int r;
+ char data[128];
+ xbee_io_context_t *ctx = xbee_user_context(*xbee);
+ int xbee_fd = ctx->fd;
+
+
+ r = read(xbee_fd, data, sizeof(data));
+ if (r <= 0) {
+ return;
+ }
+
+ xbee_in(xbee, data, r);
+}
+
+
+void xbee_io_write(xbee_t *xbee)
+{
+ int r;
+ int max_bytes_to_write;
+ xbee_io_context_t *ctx = xbee_user_context(*xbee);
+ int xbee_fd = ctx->fd;
+ int tmp_start = ctx->out_buffer_start;
+
+
+ if (tmp_start != ctx->out_buffer_end) {
+ max_bytes_to_write = (ctx->out_buffer_end + XBEE_IO_BUFSIZ - ctx->out_buffer_start) % XBEE_IO_BUFSIZ;
+
+ //for (r = 0; r < MIN(max_bytes_to_write, XBEE_IO_BUFSIZ - tmp_start); r++) {
+ // post("%02x", (unsigned char)ctx->out_buffer[tmp_start + r]);
+ //}
+
+ r = write(xbee_fd, (char *)(ctx->out_buffer + tmp_start), MIN(max_bytes_to_write, XBEE_IO_BUFSIZ - tmp_start));
+
+ if (r < 0) {
+ return;
+ }
+
+ tmp_start += r;
+ tmp_start %= XBEE_IO_BUFSIZ;
+
+ ctx->out_buffer_start = tmp_start;
+
+ if (tmp_start == 0) {
+ max_bytes_to_write -= r;
+
+ r = write(xbee_fd, (char *)(ctx->out_buffer), max_bytes_to_write);
+
+ if (r < 0) {
+ return;
+ }
+
+ tmp_start += r;
+ tmp_start %= XBEE_IO_BUFSIZ;
+ }
+
+ ctx->out_buffer_start = tmp_start;
+ }
+}
+
+
+int xbee_put_data(xbee_io_context_t *ctx, char *data, int len)
+{
+ int byte_count = 0;
+ int max_bytes;
+ int tmp_end = ctx->out_buffer_end;
+
+
+ max_bytes = MIN((ctx->out_buffer_start + XBEE_IO_BUFSIZ - tmp_end - 1) % XBEE_IO_BUFSIZ, len);
+ byte_count = MIN(max_bytes, XBEE_IO_BUFSIZ - tmp_end);
+
+ memcpy((char *)(ctx->out_buffer + tmp_end), data, byte_count);
+
+ if (byte_count != max_bytes) {
+ memcpy((char *)(ctx->out_buffer), data + byte_count, max_bytes - byte_count);
+ }
+
+ tmp_end += max_bytes;
+ tmp_end %= XBEE_IO_BUFSIZ;
+ ctx->out_buffer_end = tmp_end;
+
+ return max_bytes;
+}
+
+
+void *xbee_io_loop(void *param)
+{
+ int xbee_fd;
+ fd_set r_fds, w_fds;
+ int nfds = 0;
+ struct timeval timeout;
+ struct timeval timeout_orig = { .tv_sec = 1, .tv_usec = 0 };
+ xbee_t *xbee = param;
+ xbee_io_context_t *ctx = xbee_user_context(*xbee);
+ int notif_fd;
+ int maxfd;
+
+
+ xbee_fd = ctx->fd;
+ notif_fd = ctx->pipe_fds[0];
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+
+ while(1) {
+ if (ctx->io_done) {
+ break;
+ }
+
+ nfds = 0;
+
+ FD_SET(notif_fd, &r_fds);
+ maxfd = notif_fd;
+
+ FD_SET(xbee_fd, &r_fds);
+ if (xbee_fd > maxfd)
+ maxfd = xbee_fd;
+
+ FD_CLR(xbee_fd, &w_fds);
+ if (ctx->out_buffer_start != ctx->out_buffer_end) {
+ FD_SET(xbee_fd, &w_fds);
+ }
+
+ // For Linux compat
+ timeout = timeout_orig;
+
+ nfds = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+
+ if (nfds >= 1) {
+ if (FD_ISSET(notif_fd, &r_fds)) {
+ // We've been notified that there's data to be read, or need to exit
+ char blah;
+ read(notif_fd, &blah, 1);
+ }
+
+ if (FD_ISSET(xbee_fd, &r_fds)) {
+ xbee_io_read(xbee);
+ }
+
+ if (FD_ISSET(xbee_fd, &w_fds)) {
+ xbee_io_write(xbee);
+ }
+ }
+ }
+
+ ctx->io_running = 0;
+
+ return NULL;
+}
+
+
+int xbee_kill_io_thread(xbee_t *xbee)
+{
+ xbee_io_context_t *ctx;
+ void *val;
+
+
+ ctx = xbee_user_context(*xbee);
+
+ if (ctx != NULL) {
+ if (ctx->io_running) {
+ ctx->io_done = 1;
+
+ write(ctx->pipe_fds[1], "!", 1);
+
+ if (pthread_join(ctx->io_thread, &val) < 0) {
+ return -1;
+ }
+
+ post("xbee_test: xbee io thread stopped.");
+ }
+ }
+
+ return 0;
+}
+
+
+int xbee_new_io_thread(xbee_t *xbee)
+{
+ xbee_io_context_t *ctx = xbee_user_context(*xbee);
+ int r;
+
+
+ if (!ctx->io_running) {
+ ctx->io_running = 1;
+
+ r = pthread_create(&ctx->io_thread, NULL, &xbee_io_loop, (void *)xbee);
+ if (r < 0) {
+ ctx->io_running = 0;
+ return -1;
+ }
+
+ post("xbee_test: xbee io thread started.");
+ }
+
+ return 0;
+}
+
+
+int xbee_out(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len)
+{
+ xbee_io_context_t *ctx = xbee_user_context(*xbee);
+ int r;
+
+
+ r = xbee_put_data(ctx, (void *)pkt, len);
+ xbee_free_pkt_mem(pkt);
+
+ return r;
+}
+
+
+int xbee_recv_pkt(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len)
+{
+ //int i;
+
+
+ //for (i = 0; i < len; i++) {
+ // post("GOT %02x", ((unsigned char *)pkt)[i]);
+ //}
+
+ xbee_free_pkt_mem(pkt);
+ return 0;
+}
+
+
+void *xbee_alloc_pkt_mem(uint8_t direction, uint8_t len)
+{
+ return sysmem_newptr(128);
+}
+
+
+void xbee_free_pkt_mem(xbee_pkt_t *pkt)
+{
+ sysmem_freeptr(pkt);
+}
diff --git a/xbee/xbee_io.h b/xbee/xbee_io.h
new file mode 100644
index 0000000..a7f5363
--- /dev/null
+++ b/xbee/xbee_io.h
@@ -0,0 +1,34 @@
+/*
+ * xbee_io.h
+ * xbee_test
+ *
+ * Created by Tymm on 11/24/08.
+ * Copyright 2008 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#ifndef XBEE_IO_H
+#define XBEE_IO_H
+
+#include <pthread.h>
+
+#include "xbee.h"
+
+
+#define XBEE_IO_BUFSIZ 16384
+
+typedef struct {
+ int fd;
+ int pipe_fds[2]; // For indicating new data ready
+ pthread_t io_thread;
+ int io_done;
+ int io_running;
+ int out_buffer_start;
+ int out_buffer_end;
+ char out_buffer[XBEE_IO_BUFSIZ];
+} xbee_io_context_t;
+
+int xbee_new_io_thread(xbee_t *xbee);
+int xbee_kill_io_thread(xbee_t *xbee);
+
+#endif /* #ifndef XBEE_IO_H ... */
diff --git a/xbee/xbee_protocol.h b/xbee/xbee_protocol.h
new file mode 100644
index 0000000..bb80a60
--- /dev/null
+++ b/xbee/xbee_protocol.h
@@ -0,0 +1,292 @@
+#ifndef XBEE_PROTOCOL_H
+#define XBEE_PROTOCOL_H
+
+#ifdef AVR
+# define __LITTLE_ENDIAN 1234
+# define BYTE_ORDER LITTLE_ENDIAN
+#elif defined(ARM)
+# include <endian.h>
+#else
+# include <arpa/inet.h>
+#endif
+
+#include <stdint.h>
+
+#include "xbee.h"
+
+#if !defined(ntohs) && (BYTE_ORDER == LITTLE_ENDIAN)
+# define ntohs(n) ((((short)(n)) & 0xff00) >> 8 | (((short)(n)) & 0xff) << 8)
+# define htons(n) ntohs(n)
+#elif !defined(ntohs)
+# define ntohs(n) ((short)(n))
+# define htons(n) ntohs(n)
+#endif
+
+#if !defined(ntohl) && (BYTE_ORDER == LITTLE_ENDIAN)
+# define ntohl(x) ((((x)&0xff000000)>>24) \
+ |(((x)&0x00ff0000)>>8) \
+ |(((x)&0x0000ff00)<<8) \
+ |(((x)&0x000000ff)<<24))
+# define htonl(n) ntohl(n)
+#elif !defined(ntohl)
+# define ntohl(n) ((long)(n))
+# define htonl(n) ntohs(n)
+#endif
+
+/* p2p CE=0 (end devices) A1=0 (no end dev assoc) same ID/CH
+ * coordinator: CE=1, A2=n (coordinator assoc)
+ * SP= sleep perd ST= time betw sleep (should be same on
+ * coord/noncoord)
+ * assoc - coord'd only; comm between modules thru coord'r
+ * PAN's - need coordinator. A1 allows totally dynamic assoc
+ */
+
+
+/* --- General XBee Definitions --- */
+
+/* "Start of packet" byte; always sent as the first
+ * byte of each packet
+ */
+#define XBEE_PKT_START 0x7e
+
+
+/* Maximum packet size; datasheet basically says 100 payload bytes max */
+#define XBEE_MAX_DATA_LEN 128
+
+
+/* --- Bits in packets --- */
+
+/* Communication status bits */
+
+#define XBEE_STATUS_HW_RESET 0x01
+#define XBEE_STATUS_WD_RESET 0x02
+#define XBEE_STATUS_ASSOC 0x04
+#define XBEE_STATUS_DISASSOC 0x08
+#define XBEE_STATUS_SYNC_LOST 0x10
+#define XBEE_STATUS_COORD_REALIGN 0x20
+#define XBEE_STATUS_COORD_RESET 0x40
+
+/* Command status bits */
+
+#define XBEE_CMDSTATUS_OK 0
+#define XBEE_CMDSTATUS_ERR 1
+
+/* Transmit options */
+
+#define XBEE_TX_FLAG_NO_ACK 0x01
+#define XBEE_TX_FLAG_SEND_BCAST_PAN_ID 0x04
+
+/* Transmit status bits */
+
+#define XBEE_TXSTATUS_SUCCESS 0x00
+#define XBEE_TXSTATUS_NO_ACK 0x01
+#define XBEE_TXSTATUS_CCA_FAIL 0x02
+#define XBEE_TXSTATUS_PURGES 0x03
+
+/* Received options */
+
+#define XBEE_RX_FLAG_ADDR_BCAST 0x02
+#define XBEE_RX_FLAG_PAN_BCAST 0x04
+
+
+/* --- Definitions & macros for library use --- */
+
+/* For tracking memory allocations */
+#define XBEE_RECV 0x00
+#define XBEE_XMIT 0x01
+
+/* Initialize an XBee header */
+#define xbee_hdr_init(hdr, data_len) \
+ ((hdr).start = 0x7e, (hdr).len = htons(data_len))
+
+/* To get the length of the data portion of a received packet */
+
+#define xbee_recv_a64_data_len(pkt) (ntohs(pkt->hdr.len) - 11)
+#define xbee_recv_a16_data_len(pkt) (ntohs(pkt->hdr.len) - 5)
+#define xbee_cmd_resp_param_len(pkt) (ntohs(pkt->hdr.len) - 5)
+
+#ifdef XBEE_ALLOC
+# define xbee_alloc_pkt(dir, data_len) \
+ (xbee_pkt_t *)xbee_alloc_buf((dir), (data_len) + sizeof(xbee_pkt_hdr_t) + 1)
+#endif
+
+/* Types of packets from/to xbee modules; these are used
+ * in the "type" field of each packet structure
+ */
+
+typedef enum {
+ XBEE_PKT_TYPE_TX64 = 0x00,
+ XBEE_PKT_TYPE_TX16 = 0x01,
+ XBEE_PKT_TYPE_ATCMD = 0x08,
+ XBEE_PKT_TYPE_QATCMD = 0x09, /* wait til an immed param or apply cmd */
+ XBEE_PKT_TYPE_ZB_TX_REQ = 0x10,
+ XBEE_PKT_TYPE_ZB_CMD_FRAME = 0x11, /* Not yet impl */
+ XBEE_PKT_TYPE_REMOTE_ATCMD = 0x17,
+ XBEE_PKT_TYPE_RX64 = 0x80,
+ XBEE_PKT_TYPE_RX16 = 0x81,
+ XBEE_PKT_TYPE_RX64_IO = 0x82,
+ XBEE_PKT_TYPE_RX16_IO = 0x83,
+ XBEE_PKT_TYPE_ATCMD_RESP = 0x88,
+ XBEE_PKT_TYPE_TX_STATUS = 0x89,
+ XBEE_PKT_TYPE_MODEM_STATUS = 0x8a,
+ XBEE_PKT_TYPE_ZB_TX_STATUS = 0x8b, /* Not yet impl */
+ XBEE_PKT_TYPE_ADV_MODEM_STATUS = 0x8c, /* Not yet impl */
+ XBEE_PKT_TYPE_ZB_RX = 0x90,
+ XBEE_PKT_TYPE_ZB_RX_IO = 0x92, /* Not yet impl */
+ XBEE_PKT_TYPE_RX_SENSOR = 0x94, /* Not yet impl */
+ XBEE_PKT_TYPE_NODE_IDENT = 0x95, /* Not yet impl */
+ XBEE_PKT_TYPE_REMOTE_ATCMD_RESP = 0x97,
+} xbee_pkt_type_t;
+
+
+/* --- Packet layouts --- */
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t command[2];
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_at_cmd_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest64[8];
+ uint8_t dest16[2];
+ uint8_t apply;
+ uint8_t command[2];
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_remote_at_cmd_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest[8];
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a64_tx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest[2];
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a16_tx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t status;
+} __attribute__ ((__packed__)) xbee_tx_status_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t status;
+} __attribute__ ((__packed__)) xbee_modem_status_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t command[2];
+ uint8_t status;
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_cmd_resp_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t src64[8];
+ uint8_t src16[2];
+ uint8_t command[2];
+ uint8_t status;
+ uint8_t param[0];
+} __attribute__ ((__packed__)) xbee_remote_cmd_resp_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[8];
+ uint8_t rssi; /* signal strength */
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a64_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[2];
+ uint8_t rssi;
+ uint8_t opt;
+ uint8_t data[0];
+} __attribute__ ((__packed__)) xbee_a16_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[8];
+ uint8_t rssi; /* signal strength */
+ uint8_t opt;
+ uint8_t num_samples;
+ uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */
+ uint16_t data[0]; /* First sample digital if any digital chan active
+ rest are 16-bit analog rdgs */
+} __attribute__ ((__packed__)) xbee_io_a64_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src[2];
+ uint8_t rssi;
+ uint8_t opt;
+ uint8_t num_samples;
+ uint8_t achan;
+ uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */
+ uint16_t data[0]; /* First sample digital if any digital chan active
+ rest are 16-bit analog rdgs */
+} __attribute__ ((__packed__)) xbee_io_a16_rx_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t frame_id;
+ uint8_t dest64[8];
+ uint8_t dest16[2];
+ uint8_t radius;
+ uint8_t opt; /* Multicast = bit 3 */
+ uint8_t data[0]; /* Up to 72 bytes/pkt */
+} __attribute__ ((__packed__)) xbee_zb_tx_req_pkt_t;
+
+
+typedef struct {
+ xbee_pkt_hdr_t hdr;
+ uint8_t type;
+ uint8_t src64[8];
+ uint8_t src16[2];
+ uint8_t opt;
+ uint8_t data[0]; /* Up to 72 bytes/pkt */
+} __attribute__ ((__packed__)) xbee_zb_rx_pkt_t;
+
+
+#endif /* #ifndef XBEE_PROTOCOL_H ... */
+
diff --git a/xbee/xbee_test-help.pd b/xbee/xbee_test-help.pd
new file mode 100644
index 0000000..f00c516
--- /dev/null
+++ b/xbee/xbee_test-help.pd
@@ -0,0 +1,2 @@
+#N canvas 191 22 450 300 10;
+#X obj 157 89 xbee_test /dev/tty.Bluetooth-Modem;
diff --git a/xbee/xbee_test.c b/xbee/xbee_test.c
new file mode 100644
index 0000000..7408b57
--- /dev/null
+++ b/xbee/xbee_test.c
@@ -0,0 +1,457 @@
+/**
+ @file
+ xbee_test - test xbee communication
+
+ @ingroup examples
+*/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <termios.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef PD
+#include "m_pd.h"
+#include "max2pd.h"
+#else
+#include "ext.h" // standard Max include, always required
+#include "ext_obex.h" // required for new style Max object
+
+# ifdef MAC_VERSION
+# include "ext_strings.h"
+# endif
+#endif /* PD */
+
+#include "xbee.h"
+#include "xbee_io.h"
+
+////////////////////////// object struct
+typedef struct _xbee_test
+{
+ t_object a_ob; // the object itself (must be first)
+ long baud;
+ uint8_t dest_addr64[8];
+ uint8_t dest_addr16[2];
+ xbee_t *xbee;
+} t_xbee_test;
+
+
+///////////////////////// function prototypes
+//// standard set
+void *xbee_test_new(t_symbol *s, long argc, t_atom *argv);
+void xbee_test_free(t_xbee_test *x);
+void xbee_test_assist(t_xbee_test *x, void *b, long m, long a, char *s);
+//// additional methods
+void xbee_test_bang(t_xbee_test *x); // incoming bang message
+void xbee_test_close(t_xbee_test *x);
+int xbee_test_open_device(t_xbee_test *x, t_symbol *s);
+void xbee_test_dest64(t_xbee_test *x, t_symbol *s);
+void xbee_test_dest16(t_xbee_test *x, t_symbol *s);
+static void xbee_test_on(t_xbee_test *x, long dpin);
+static void xbee_test_off(t_xbee_test *x, long dpin);
+
+
+//////////////////////// global class pointer variable
+void *xbee_test_class;
+
+
+static int set_baud(int fd, int baud_rate)
+{
+ struct termios termios;
+ speed_t speed;
+
+
+ switch(baud_rate) {
+ case 50:
+ speed = B50;
+ break;
+ case 75:
+ speed = B75;
+ break;
+ case 110:
+ speed = B110;
+ break;
+ case 300:
+ speed = B300;
+ break;
+ case 600:
+ speed = B600;
+ break;
+ case 1200:
+ speed = B1200;
+ break;
+ case 2400:
+ speed = B2400;
+ break;
+ case 4800:
+ speed = B4800;
+ break;
+ case 9600:
+ speed = B9600;
+ break;
+ case 19200:
+ speed = B19200;
+ break;
+ case 38400:
+ speed = B38400;
+ break;
+ case 57600:
+ speed = B57600;
+ break;
+ case 115200:
+ speed = B115200;
+ break;
+ case 230400:
+ speed = B230400;
+ break;
+#ifdef B256000
+ case 256000:
+ speed = B256000;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ if (tcgetattr(fd, &termios) < 0) {
+ error("xbee_test: tcgetattr failed (%d)", errno);
+ return -1;
+ }
+
+ termios.c_cflag |= CLOCAL;
+
+ if (cfsetispeed(&termios, speed) < 0) {
+ error("xbee_test: cfsetispeed failed (%d)", errno);
+ return -1;
+ }
+
+ if (cfsetospeed(&termios, speed) < 0) {
+ error("xbee_test: cfsetospeed failed (%d)", errno);
+ return -1;
+ }
+
+ if (tcsetattr(fd, TCSANOW, &termios) < 0) {
+ error("xbee_test: tcsetattr failed (%d)", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifdef PD
+
+void xbee_test_setup(void)
+{
+ xbee_test_class = class_new(gensym("xbee_test"),
+ (t_newmethod)xbee_test_new,
+ (t_method)xbee_test_free,
+ sizeof(t_xbee_test),
+ CLASS_DEFAULT,
+ A_GIMME,0);
+ class_addbang(xbee_test_class, (t_method)xbee_test_bang);
+ class_addmethod(xbee_test_class, (t_method)xbee_test_dest64, gensym("dest64"), A_DEFSYMBOL, 0);
+ class_addmethod(xbee_test_class, (t_method)xbee_test_dest16, gensym("dest16"), A_DEFSYMBOL, 0);
+ class_addmethod(xbee_test_class, (t_method)xbee_test_on, gensym("on"), A_DEFFLOAT, 0);
+ class_addmethod(xbee_test_class, (t_method)xbee_test_off, gensym("off"), A_DEFFLOAT, 0);
+}
+#else
+int main(void)
+{
+ t_class *c;
+
+
+ c = class_new("xbee_test", (method)xbee_test_new, (method)xbee_test_free, (long)sizeof(t_xbee_test), 0L, A_GIMME, 0);
+
+ class_addmethod(c, (method)xbee_test_bang, "bang", 0);
+ class_addmethod(c, (method)xbee_test_assist, "assist", A_CANT, 0);
+ class_addmethod(c, (method)xbee_test_dest64, "dest64", A_DEFSYM, 0);
+ class_addmethod(c, (method)xbee_test_dest16, "dest16", A_DEFSYM, 0);
+ class_addmethod(c, (method)xbee_test_on, "on", A_LONG, 0);
+ class_addmethod(c, (method)xbee_test_off, "off", A_LONG, 0);
+
+ class_register(CLASS_BOX, c);
+ xbee_test_class = c;
+
+ return 0;
+}
+#endif /* PD */
+
+static void xbee_test_on(t_xbee_test *x, long dpin)
+{
+ char cmd[2] = "Dx";
+ uint8_t param[] = {5};
+ xbee_io_context_t *ctx;
+ int r;
+
+
+ if (!x->xbee)
+ return;
+
+ ctx = xbee_user_context(*(x->xbee));
+ if (!ctx)
+ return;
+
+ if (dpin >= 0 && dpin <= 7) {
+ cmd[1] = dpin + '0';
+
+ r = xbee_send_remote_at_cmd(x->xbee, cmd, 1, 2, param, x->dest_addr64, x->dest_addr16);
+ if (r < 0) {
+ post("xbee_test: xbee_send_remote_at_cmd failed (%d)", errno);
+ }
+ }
+
+ // Nudge IO thread
+ write(ctx->pipe_fds[1], "!", 1);
+}
+
+
+static void xbee_test_off(t_xbee_test *x, long dpin)
+{
+ char cmd[2] = "Dx";
+ uint8_t param[] = {4};
+ xbee_io_context_t *ctx;
+ int r;
+
+
+ if (!x->xbee)
+ return;
+
+ ctx = xbee_user_context(*(x->xbee));
+ if (!ctx)
+ return;
+
+ if (dpin >= 0 && dpin <= 7) {
+ cmd[1] = dpin + '0';
+
+ r = xbee_send_remote_at_cmd(x->xbee, cmd, 1, 2, param, x->dest_addr64, x->dest_addr16);
+ if (r < 0) {
+ post ("xbee_test: xbee_send_remote_at_cmd failed (%d)", errno);
+ }
+ }
+
+ // Nudge IO thread
+ write(ctx->pipe_fds[1], "!", 1);
+}
+
+#ifndef PD
+void xbee_test_assist(t_xbee_test *x, void *b, long m, long a, char *s)
+{
+ if (m == ASSIST_INLET) { //inlet
+ sprintf(s, "I am inlet %ld", a);
+ }
+ else { // outlet
+ sprintf(s, "I am outlet %ld", a);
+ }
+}
+#endif /* NOT PD */
+
+void xbee_test_bang(t_xbee_test *x)
+{
+}
+
+
+void xbee_test_close(t_xbee_test *x)
+{
+ xbee_t *xbee = x->xbee;
+ xbee_io_context_t *ctx;
+
+
+ if (!xbee)
+ return;
+
+ xbee_kill_io_thread(x->xbee);
+
+ ctx = xbee_user_context(*xbee);
+ if (!ctx)
+ return;
+
+ if (ctx->fd >= 0) {
+ close(ctx->fd);
+ ctx->fd = -1;
+ }
+
+ if (ctx->pipe_fds[0] >= 0) {
+ close(ctx->pipe_fds[0]);
+ ctx->pipe_fds[0] = -1;
+ }
+
+ if (ctx->pipe_fds[1] >= 0) {
+ close(ctx->pipe_fds[1]);
+ ctx->pipe_fds[1] = -1;
+ }
+}
+
+
+void xbee_test_free(t_xbee_test *x)
+{
+ xbee_t *xbee = x->xbee;
+ xbee_io_context_t *ctx;
+
+
+ xbee_test_close(x);
+ if (xbee) {
+ ctx = xbee_user_context(*xbee);
+ if (ctx) {
+ sysmem_freeptr(ctx);
+ }
+
+ sysmem_freeptr(xbee);
+ }
+}
+
+
+void xbee_test_dest64(t_xbee_test *x, t_symbol *s)
+{
+ uint64_t dest;
+ int i;
+
+
+ dest = strtoll(s->s_name, NULL, 16);
+ for (i = 0; i < 8; i++) {
+ x->dest_addr64[7 - i] = dest & 0xff;
+ dest >>= 8;
+ }
+
+ post("xbee_test: set dest64 addr to %02x%02x%02x%02x%02x%02x%02x%02x",
+ x->dest_addr64[0], x->dest_addr64[1], x->dest_addr64[2], x->dest_addr64[3],
+ x->dest_addr64[4], x->dest_addr64[5], x->dest_addr64[6], x->dest_addr64[7]);
+}
+
+
+void xbee_test_dest16(t_xbee_test *x, t_symbol *s)
+{
+ uint16_t dest;
+ int i;
+
+
+ dest = strtol(s->s_name, NULL, 16);
+ for (i = 0; i < 2; i++) {
+ x->dest_addr16[1 - i] = dest & 0xff;
+ dest >>= 8;
+ }
+
+ post("xbee_test: set dest16 addr to %02x%02x", x->dest_addr16[0], x->dest_addr16[1]);
+}
+
+
+int xbee_test_open_device(t_xbee_test *x, t_symbol *s)
+{
+ xbee_io_context_t *xbee_io_context;
+ int fd;
+
+
+ if (s == gensym("")) {
+ return 0;
+ }
+
+ xbee_test_close(x);
+
+ xbee_io_context = (xbee_io_context_t *)sysmem_newptr(sizeof(xbee_io_context_t));
+ if (xbee_io_context == NULL) {
+ error("xbee_test: %s: can't allocate memory", s->s_name);
+ return -1;
+ }
+
+ memset(xbee_io_context, 0, sizeof(xbee_io_context_t));
+
+ // Pipe for nudging io thread when there's more data to write
+ if (pipe(xbee_io_context->pipe_fds) < 0) {
+ error("xbee_test: %s: can't open pipe (%d)", s->s_name, errno);
+ sysmem_freeptr(xbee_io_context);
+ return -1;
+ }
+
+ fd = open(s->s_name, O_RDWR | O_NONBLOCK, 0);
+ if (fd < 0) {
+ error("xbee_test: %s: can't open device file (error %d)", s->s_name, errno);
+ close(xbee_io_context->pipe_fds[0]);
+ close(xbee_io_context->pipe_fds[1]);
+ sysmem_freeptr(xbee_io_context);
+ return -1;
+ }
+
+ post("xbee_test: opened %s", s->s_name);
+
+ if (set_baud(fd, x->baud) < 0) {
+ post("xbee_test: %s: error setting baud to %d", s->s_name, x->baud);
+ } else {
+ post("xbee_test: baud set to %d", x->baud);
+ }
+
+ xbee_io_context->fd = fd;
+
+ xbee_user_context(*(x->xbee)) = xbee_io_context;
+
+ if (xbee_new_io_thread(x->xbee) < 0) {
+ xbee_user_context(*(x->xbee)) = NULL;
+ close(fd);
+ close(xbee_io_context->pipe_fds[0]);
+ close(xbee_io_context->pipe_fds[1]);
+ sysmem_freeptr(xbee_io_context);
+ error("xbee_test: error starting new IO thread");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void *xbee_test_new(t_symbol *s, long argc, t_atom *argv)
+{
+ t_xbee_test *x = NULL;
+ t_symbol *a;
+
+
+ if (argc < 1) {
+ error("xbee_test: No device name specified");
+ return NULL;
+ }
+
+ x = (t_xbee_test *)object_alloc(xbee_test_class);
+
+ x->baud = 9600;
+
+ x->xbee = (xbee_t *)sysmem_newptr(sizeof(*x->xbee));
+ if (x->xbee == NULL) {
+ object_free(x);
+ return NULL;
+ }
+
+ xbee_init(x->xbee);
+
+ // Set 64-bit destination to 0x0000000000ffff (broadcast)
+ memset(x->dest_addr64, 0, sizeof(x->dest_addr64));
+ x->dest_addr64[7] = 0xff;
+ x->dest_addr64[6] = 0xff;
+
+ // Set 16-bit destination to 0xfffe (ZNet broadcast)
+ x->dest_addr16[0] = 0xff;
+ x->dest_addr16[1] = 0xfe;
+
+ if (argc >= 1) {
+ if (argc >= 2) {
+ x->baud = atom_getlong(&argv[1]);
+
+ if (x->baud == 0) {
+ error("xbee_test: second argument should be a valid baud rate.");
+ sysmem_freeptr(x->xbee);
+ object_free(x);
+ return NULL;
+ }
+ }
+
+ a = atom_getsym(&argv[0]);
+ if (a != gensym("")) {
+ if (xbee_test_open_device(x, a) < 0) {
+ sysmem_freeptr(x->xbee);
+ object_free(x);
+ return NULL;
+ }
+ }
+
+ }
+
+ return (x);
+}