From 8238e049724286e6a8af96734c71e826c6826006 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 11 Feb 2009 00:50:16 +0000 Subject: first attempt at a Pd port, it compiles without any real warnings, now we just need an xbee to test on! svn path=/trunk/externals/io/; revision=10754 --- xbee/Makefile | 33 ++++ xbee/max2pd.h | 19 ++ xbee/xbee.c | 340 ++++++++++++++++++++++++++++++++++++ xbee/xbee.h | 261 ++++++++++++++++++++++++++++ xbee/xbee_internal.h | 248 +++++++++++++++++++++++++++ xbee/xbee_io.c | 268 +++++++++++++++++++++++++++++ xbee/xbee_io.h | 34 ++++ xbee/xbee_protocol.h | 292 +++++++++++++++++++++++++++++++ xbee/xbee_test-help.pd | 2 + xbee/xbee_test.c | 457 +++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1954 insertions(+) create mode 100644 xbee/Makefile create mode 100644 xbee/max2pd.h create mode 100644 xbee/xbee.c create mode 100644 xbee/xbee.h create mode 100644 xbee/xbee_internal.h create mode 100644 xbee/xbee_io.c create mode 100644 xbee/xbee_io.h create mode 100644 xbee/xbee_protocol.h create mode 100644 xbee/xbee_test-help.pd create mode 100644 xbee/xbee_test.c 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 + * + */ + +#include +#include /* 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 + * + * + * 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 +#include + +/*---------------------------------------------------------------------------- + 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 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 +#else +# include +#endif + +#include + +#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 +#include +#include +#include +#include + +#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 + +#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 +#else +# include +#endif + +#include + +#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 +#include +#include +#include +#include +#include + +#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); +} -- cgit v1.2.1