1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/xbee: adapted to netdev2

This commit is contained in:
Hauke Petersen 2016-11-23 19:38:41 +01:00
parent 11a0422b83
commit 83d206e2b0
6 changed files with 393 additions and 480 deletions

View File

@ -73,3 +73,6 @@ endif
ifneq (,$(filter w5100,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/w5100/include
endif
ifneq (,$(filter xbee,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/xbee/include
endif

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 INRIA
* Copyright (C) 2015 Freie Universität Berlin
* Copyright (C) 2015-2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -29,8 +29,9 @@
#include "xtimer.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#include "net/gnrc.h"
#include "net/netdev2.h"
#include "net/ieee802154.h"
#include "net/gnrc/nettype.h"
#ifdef __cplusplus
extern "C" {
@ -55,6 +56,11 @@ extern "C" {
*/
#define XBEE_MAX_RESP_LENGTH (16U)
/**
* @brief Maximal possible size of a TX header
*/
#define XBEE_MAX_TXHDR_LENGTH (14U)
/**
* @brief Default protocol for data that is coming in
*/
@ -95,31 +101,43 @@ extern "C" {
* frame specific data as the frame size, frame type, and checksums.
*/
typedef enum {
XBEE_INT_STATE_IDLE, /**< waiting for the beginning of a new frame */
XBEE_INT_STATE_SIZE1, /**< waiting for the first byte (MSB) of the
* frame size field */
XBEE_INT_STATE_SIZE2, /**< waiting for the second byte (LSB) of the
* frame size field */
XBEE_INT_STATE_TYPE, /**< waiting for the frame type field */
XBEE_INT_STATE_RESP, /**< handling incoming data for AT command
* responses */
XBEE_INT_STATE_RX, /**< handling incoming data when receiving radio
* packets */
XBEE_INT_STATE_IDLE, /**< waiting for the beginning of a new frame */
XBEE_INT_STATE_SIZE1, /**< waiting for the first byte (MSB) of the
* frame size field */
XBEE_INT_STATE_SIZE2, /**< waiting for the second byte (LSB) of the
* frame size field */
XBEE_INT_STATE_TYPE, /**< waiting for the frame type field */
XBEE_INT_STATE_RESP, /**< handling incoming data for AT command
* responses */
XBEE_INT_STATE_RX, /**< handling incoming data when receiving radio
* packets */
} xbee_rx_state_t;
/**
* @brief Configuration parameters for XBee devices
*/
typedef struct {
uart_t uart; /**< UART interfaced the device is connected to */
uint32_t br; /**< baudrate to use */
gpio_t pin_sleep; /**< GPIO pin that is connected to the SLEEP pin
set to GPIO_UNDEF if not used */
gpio_t pin_reset; /**< GPIO pin that is connected to the STATUS pin
set to GPIO_UNDEF if not used */
} xbee_params_t;
/**
* @brief XBee device descriptor
*/
typedef struct {
/* netdev fields */
gnrc_netdev_driver_t const *driver; /**< pointer to the devices interface */
gnrc_netdev_event_cb_t event_cb; /**< netdev event callback */
kernel_pid_t mac_pid; /**< the driver's thread's PID */
const struct netdev2_driver *driver; /**< ptr to that driver's interface. */
netdev2_event_cb_t event_callback; /**< callback for device events */
void* context; /**< ptr to network stack context */
#ifdef MODULE_NETSTATS_L2
netstats_t stats; /**< transceiver's statistics */
#endif
/* device driver specific fields */
uart_t uart; /**< UART interfaced used */
gpio_t reset_pin; /**< GPIO pin connected to RESET */
gpio_t sleep_pin; /**< GPIO pin connected to SLEEP */
gnrc_nettype_t proto; /**< protocol the interface speaks */
xbee_params_t p; /**< configuration parameters */
uint8_t options; /**< options field */
uint8_t addr_flags; /**< address flags as defined above */
uint8_t addr_short[2]; /**< onw 802.15.4 short address */
@ -131,7 +149,8 @@ typedef struct {
/* values for the UART TX state machine */
mutex_t tx_lock; /**< mutex to allow only one
* transmission at a time */
uint8_t tx_buf[XBEE_MAX_PKT_LENGTH];/**< transmit data buffer */
uint8_t cmd_buf[XBEE_MAX_RESP_LENGTH];/**< command data buffer */
uint8_t tx_fid; /**< TX frame ID */
/* buffer and synchronization for command responses */
mutex_t resp_lock; /**< mutex for waiting for AT command
* response frames */
@ -145,24 +164,23 @@ typedef struct {
} xbee_t;
/**
* @brief auto_init struct holding Xbee device initalization params
* @brief Data structure for extraction L2 information of received packets
*/
typedef struct xbee_params {
uart_t uart; /**< UART interfaced the device is connected to */
uint32_t baudrate; /**< baudrate to use */
gpio_t sleep_pin; /**< GPIO pin that is connected to the SLEEP pin
set to GPIO_UNDEF if not used */
gpio_t reset_pin; /**< GPIO pin that is connected to the STATUS pin
set to GPIO_UNDEF if not used */
} xbee_params_t;
typedef struct {
uint8_t addr_len; /**< L2 address length (SRC and DST) */
uint8_t bcast; /**< 0 := unicast, 1:=broadcast */
uint8_t rssi; /**< RSSI value */
uint8_t src_addr[8]; /**< L2 source address */
uint8_t dst_addr[8]; /**< L2 dst address */
} xbee_l2hdr_t;
/**
* @brief Reference to the XBee driver interface
*/
extern const gnrc_netdev_driver_t xbee_driver;
extern const netdev2_driver_t xbee_driver;
/**
* @brief Initialize the given Xbee device
* @brief Prepare the given Xbee device
*
* @param[out] dev Xbee device to initialize
* @param[in] params parameters for device initialization
@ -171,7 +189,34 @@ extern const gnrc_netdev_driver_t xbee_driver;
* @return -ENODEV on invalid device descriptor
* @return -ENXIO on invalid UART or GPIO pins
*/
int xbee_init(xbee_t *dev, const xbee_params_t *params);
void xbee_setup(xbee_t *dev, const xbee_params_t *params);
/**
* @brief Put together the internal proprietary XBee header
*
* @param[out] xhdr buffer to write the header into, MUST be at least of
* length XBEE_MAX_TXHDR_LENGTH
* @param[in] payload_len actual payload length (without the XBee header)
* @param[in] dst_addr link layer (L2) destination address
* @param[in] addr_len length of @p dst_addr in byte (MUST be 2 or 8)
*
* @return the length of the created header in byte
* @return -EOVERFLOW if @p payload_len is greater than XBEE_MAX_PAYLOAD_LENGTH
* @return -ENOMSG if the given destination address has an invalid length
*/
int xbee_build_hdr(xbee_t *dev, uint8_t *xhdr, size_t payload_len,
void *dst_addr, size_t addr_len);
/**
* @brief Extract IEEE802.15.4 L2 header information from the XBee header
*
* @param[in] xhdr XBee header, starting with the API identifier
* @param[out] l2hdr the L2 header information is written here
*
* @return the length of the XBee header
* @return -ENOMST if the given XBee header is invalid
*/
int xbee_parse_hdr(xbee_t *dev, const uint8_t *xhdr, xbee_l2hdr_t *l2hdr);
#ifdef __cplusplus
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_xbee
* @{
*
* @file
* @brief Default configuration for XBee devices
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef XBEE_PARAMS_H
#define XBEE_PARAMS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the XBee driver
* @{
*/
#ifndef XBEE_PARAM_UART
#define XBEE_PARAM_UART (UART_DEV(1))
#endif
#ifndef XBEE_PARAM_BR
#define XBEE_PARAM_BR (9600U)
#endif
#ifndef XBEE_PARAM_PIN_SLEEP
#define XBEE_PARAM_PIN_SLEEP (GPIO_UNDEF)
#endif
#ifndef XBEE_PARAM_PIN_RESET
#define XBEE_PARAM_PIN_RESET (GPIO_UNDEF)
#endif
#ifndef XBEE_PARAMS
#define XBEE_PARAMS { .uart = XBEE_PARAM_UART, \
.br = XBEE_PARAM_BR, \
.pin_sleep = XBEE_PARAM_PIN_SLEEP, \
.pin_reset = XBEE_PARAM_PIN_RESET }
#endif
/**@}*/
/**
* @brief XBee configuration
*/
static const xbee_params_t xbee_params[] =
{
XBEE_PARAMS
};
#ifdef __cplusplus
}
#endif
#endif /* XBEE_PARAMS_H */
/** @} */

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 INRIA
* Copyright (C) 2015 Freie Universität Berlin
* Copyright (C) 2015-2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -21,13 +21,14 @@
*/
#include <string.h>
#include <errno.h>
#include "xbee.h"
#include "assert.h"
#include "xtimer.h"
#include "msg.h"
#include "net/eui64.h"
#include "net/netdev2.h"
#include "net/ieee802154.h"
#include "periph/cpuid.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
@ -76,6 +77,8 @@
* @{
*/
#define OPT_DIS_AUTO_ACK (0x01) /**< disable sending of auto ACKs */
#define OPT_BCAST_ADDR (0x02) /**< address broadcast */
#define OPT_BCAST_PAN (0x04) /**< PAN broadcast */
/** @} */
/**
@ -91,10 +94,10 @@ typedef struct {
/*
* Driver's internal utility functions
*/
static uint8_t _cksum(uint8_t *buf, size_t size)
static uint8_t _cksum(size_t offset, uint8_t *buf, size_t size)
{
uint8_t res = 0xff;
for (size_t i = 3; i < size; i++) {
for (size_t i = offset; i < size; i++) {
res -= buf[i];
}
return res;
@ -102,9 +105,9 @@ static uint8_t _cksum(uint8_t *buf, size_t size)
static void _at_cmd(xbee_t *dev, const char *cmd)
{
DEBUG("xbee: AT_CMD: %s\n", cmd);
DEBUG("[xbee] AT_CMD: %s\n", cmd);
uart_write(dev->uart, (uint8_t *)cmd, strlen(cmd));
uart_write(dev->p.uart, (uint8_t *)cmd, strlen(cmd));
}
static void isr_resp_timeout(void *arg)
@ -120,23 +123,23 @@ static void isr_resp_timeout(void *arg)
static void _api_at_cmd(xbee_t *dev, uint8_t *cmd, uint8_t size, resp_t *resp)
{
DEBUG("xbee: AT_CMD: %s\n", cmd);
DEBUG("[xbee] AT_CMD: %s\n", cmd);
/* acquire TX lock */
mutex_lock(&(dev->tx_lock));
/* construct API frame */
dev->tx_buf[0] = API_START_DELIMITER;
dev->tx_buf[1] = (size + 2) >> 8;
dev->tx_buf[2] = (size + 2) & 0xff;
dev->tx_buf[3] = API_ID_AT;
dev->tx_buf[4] = 1; /* use fixed frame id */
memcpy(dev->tx_buf + 5, cmd, size);
dev->tx_buf[size + 5] = _cksum(dev->tx_buf, size + 5);
dev->cmd_buf[0] = API_START_DELIMITER;
dev->cmd_buf[1] = (size + 2) >> 8;
dev->cmd_buf[2] = (size + 2) & 0xff;
dev->cmd_buf[3] = API_ID_AT;
dev->cmd_buf[4] = 1; /* use fixed frame id */
memcpy(dev->cmd_buf + 5, cmd, size);
dev->cmd_buf[size + 5] = _cksum(3, dev->cmd_buf, size + 5);
/* reset the response data counter */
dev->resp_count = 0;
/* start send data */
uart_write(dev->uart, dev->tx_buf, size + 6);
uart_write(dev->p.uart, dev->cmd_buf, size + 6);
xtimer_ticks64_t sent_time = xtimer_now64();
@ -158,7 +161,7 @@ static void _api_at_cmd(xbee_t *dev, uint8_t *cmd, uint8_t size, resp_t *resp)
xtimer_remove(&resp_timer);
if (dev->resp_limit != dev->resp_count) {
DEBUG("xbee: response timeout\n");
DEBUG("[xbee] api_at_cmd: response timeout\n");
resp->status = 255;
mutex_unlock(&(dev->tx_lock));
@ -180,7 +183,6 @@ static void _api_at_cmd(xbee_t *dev, uint8_t *cmd, uint8_t size, resp_t *resp)
static void _rx_cb(void *arg, uint8_t c)
{
xbee_t *dev = (xbee_t *)arg;
msg_t msg;
switch (dev->int_state) {
case XBEE_INT_STATE_IDLE:
@ -228,9 +230,9 @@ static void _rx_cb(void *arg, uint8_t c)
dev->rx_buf[dev->rx_count++] = c;
if (dev->rx_count == dev->rx_limit) {
/* packet is complete */
msg.type = GNRC_NETDEV_MSG_TYPE_EVENT;
msg.content.value = ISR_EVENT_RX_DONE;
msg_send_int(&msg, dev->mac_pid);
if (dev->event_callback) {
dev->event_callback((netdev2_t *)dev, NETDEV2_EVENT_ISR);
}
dev->int_state = XBEE_INT_STATE_IDLE;
}
break;
@ -243,26 +245,6 @@ static void _rx_cb(void *arg, uint8_t c)
/*
* Getter and setter functions
*/
static int _get_addr_short(xbee_t *dev, uint8_t *val, size_t len)
{
uint8_t cmd[2];
resp_t resp;
if (len < 2) {
return -EOVERFLOW;
}
cmd[0] = 'M';
cmd[1] = 'Y';
_api_at_cmd(dev, cmd, 2, &resp);
if (resp.status == 0) {
memcpy(val, resp.data, IEEE802154_SHORT_ADDRESS_LEN);
return IEEE802154_SHORT_ADDRESS_LEN;
}
return -ECANCELED;
}
static int _get_addr_long(xbee_t *dev, uint8_t *val, size_t len)
{
uint8_t cmd[2];
@ -325,7 +307,7 @@ static int _set_addr(xbee_t *dev, uint8_t *val, size_t len)
#endif
if (dev->addr_flags & XBEE_ADDR_FLAGS_LONG ||
_set_short_addr(dev, addr) == 0) {
_set_short_addr(dev, addr) == 0) {
memcpy(dev->addr_short, addr, 2);
@ -440,24 +422,6 @@ static int _set_panid(xbee_t *dev, uint8_t *val, size_t len)
return -EINVAL;
}
static int _get_proto(xbee_t *dev, uint8_t *val, size_t max)
{
if (max < sizeof(gnrc_nettype_t)) {
return -EOVERFLOW;
}
memcpy(val, &(dev->proto), sizeof(gnrc_nettype_t));
return sizeof(gnrc_nettype_t);
}
static int _set_proto(xbee_t *dev, uint8_t *val, size_t len)
{
if (len != sizeof(gnrc_nettype_t)) {
return -EINVAL;
}
memcpy(&(dev->proto), val, sizeof(gnrc_nettype_t));
return sizeof(gnrc_nettype_t);
}
#ifdef MODULE_XBEE_ENCRYPTION
static int _set_encryption(xbee_t *dev, uint8_t *val)
{
@ -505,245 +469,271 @@ static int _set_encryption_key(xbee_t *dev, uint8_t *val, size_t len)
/*
* Driver's "public" functions
*/
int xbee_init(xbee_t *dev, const xbee_params_t *params)
{
uint8_t tmp[2];
/* check device and bus parameters */
if (dev == NULL) {
return -ENODEV;
}
if (params->uart >= UART_NUMOF) {
return -ENXIO;
}
void xbee_setup(xbee_t *dev, const xbee_params_t *params)
{
assert(dev && (params->uart < UART_NUMOF));
/* set device driver */
dev->driver = &xbee_driver;
dev->event_callback = NULL;
dev->context = dev;
/* set peripherals to use */
dev->uart = params->uart;
dev->reset_pin = params->reset_pin;
dev->sleep_pin = params->sleep_pin;
memcpy(&dev->p, params, sizeof(xbee_params_t));
/* initialize pins */
if (dev->p.pin_reset != GPIO_UNDEF) {
gpio_init(dev->p.pin_reset, GPIO_OUT);
gpio_set(dev->p.pin_reset);
}
if (dev->p.pin_sleep != GPIO_UNDEF) {
gpio_init(dev->p.pin_sleep, GPIO_OUT);
gpio_clear(dev->p.pin_sleep);
}
/* we initialize the UART later, since we can not handle interrupts, yet */
}
int xbee_build_hdr(xbee_t *dev, uint8_t *xhdr, size_t payload_len,
void *dst_addr, size_t addr_len)
{
/* make sure payload fits into a packet */
if (payload_len > XBEE_MAX_PAYLOAD_LENGTH) {
return -EOVERFLOW;
}
/* set start delimiter, configure address and set options. Also make sure,
* that the link layer address is of known length */
xhdr[0] = API_START_DELIMITER;
xhdr[4] = dev->tx_fid++;
if (addr_len == IEEE802154_SHORT_ADDRESS_LEN) {
xhdr[3] = API_ID_TX_SHORT_ADDR;
xhdr[7] = dev->options;
}
else if (addr_len == IEEE802154_LONG_ADDRESS_LEN) {
xhdr[3] = API_ID_TX_LONG_ADDR;
xhdr[13] = dev->options;
}
else {
return -ENOMSG;
}
/* finally configure the packet size and copy the actual dst address */
uint16_t size = (uint16_t)(payload_len + addr_len + 3);
xhdr[1] = (uint8_t)(size >> 8);
xhdr[2] = (uint8_t)(size & 0xff);
memcpy(&xhdr[5], dst_addr, addr_len);
return (int)(addr_len + 6);
}
int xbee_parse_hdr(xbee_t *dev, const uint8_t *xhdr, xbee_l2hdr_t *l2hdr)
{
uint8_t alen;
assert(xhdr && l2hdr);
/* get the address length */
if (xhdr[0] == API_ID_RX_SHORT_ADDR) {
alen = IEEE802154_SHORT_ADDRESS_LEN;
}
else if (xhdr[0] == API_ID_RX_LONG_ADDR) {
alen = IEEE802154_LONG_ADDRESS_LEN;
}
else {
return -ENOMSG;
}
/* copy the actual SRC address and the RSSI value */
memcpy(l2hdr->src_addr, &xhdr[1], alen);
l2hdr->rssi = xhdr[1 + alen];
/* copy the destination address */
l2hdr->bcast = (xhdr[2 + alen] & OPT_BCAST_ADDR) ? 1 : 0;
if (l2hdr->bcast) {
memset(l2hdr->dst_addr, 0xff, alen);
}
else {
if (alen == IEEE802154_SHORT_ADDRESS_LEN) {
memcpy(l2hdr->dst_addr, dev->addr_short, alen);
}
else {
memcpy(l2hdr->dst_addr, dev->addr_long.uint8, alen);
}
}
l2hdr->addr_len = alen;
return (int)(alen + 3);
}
int xbee_init(netdev2_t *dev)
{
uint8_t tmp[2];
xbee_t *xbee = (xbee_t *)dev;
/* set default options */
dev->addr_flags = 0;
dev->proto = XBEE_DEFAULT_PROTOCOL;
dev->options = 0;
xbee->addr_flags = XBEE_ADDR_FLAGS_LONG;
xbee->options = 0;
/* initialize buffers and locks*/
mutex_init(&(dev->tx_lock));
mutex_init(&(dev->resp_lock));
dev->resp_limit = 1; /* needs to be greater then 0 initially */
dev->rx_count = 0;
mutex_init(&(xbee->tx_lock));
mutex_init(&(xbee->resp_lock));
xbee->resp_limit = 1; /* needs to be greater then 0 initially */
xbee->rx_count = 0;
/* initialize UART and GPIO pins */
if (uart_init(params->uart, params->baudrate, _rx_cb, dev) != UART_OK) {
DEBUG("xbee: Error initializing UART\n");
if (uart_init(xbee->p.uart, xbee->p.br, _rx_cb, xbee) != UART_OK) {
DEBUG("[xbee] init: error initializing UART\n");
return -ENXIO;
}
if (params->reset_pin != GPIO_UNDEF) {
if (gpio_init(params->reset_pin, GPIO_OUT) < 0) {
DEBUG("xbee: Error initializing RESET pin\n");
return -ENXIO;
}
gpio_set(params->reset_pin);
}
if (params->sleep_pin != GPIO_UNDEF) {
if (gpio_init(params->sleep_pin, GPIO_OUT) < 0) {
DEBUG("xbee: Error initializing SLEEP pin\n");
return -ENXIO;
}
gpio_clear(params->sleep_pin);
}
/* if reset pin is connected, do a hardware reset */
if (params->reset_pin != GPIO_UNDEF) {
gpio_clear(params->reset_pin);
if (xbee->p.pin_reset != GPIO_UNDEF) {
gpio_clear(xbee->p.pin_reset);
xtimer_usleep(RESET_DELAY);
gpio_set(params->reset_pin);
gpio_set(xbee->p.pin_reset);
}
/* put the XBee device into command mode */
xtimer_usleep(ENTER_CMD_MODE_DELAY);
_at_cmd(dev, "+++");
_at_cmd(xbee, "+++");
xtimer_usleep(ENTER_CMD_MODE_DELAY);
/* disable non IEEE802.15.4 extensions */
_at_cmd(dev, "ATMM2\r");
_at_cmd(xbee, "ATMM2\r");
/* put XBee module in "API mode without escaped characters" */
_at_cmd(dev, "ATAP1\r");
_at_cmd(xbee, "ATAP1\r");
/* apply AT commands */
_at_cmd(dev, "ATAC\r");
_at_cmd(xbee, "ATAC\r");
/* exit command mode */
_at_cmd(dev, "ATCN\r");
_at_cmd(xbee, "ATCN\r");
/* load long address (we can not set it, its read only for Xbee devices) */
if (_get_addr_long(dev, dev->addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN) < 0) {
DEBUG("xbee: Error getting address\n");
if (_get_addr_long(xbee, xbee->addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN) < 0) {
DEBUG("[xbee] init: error getting address\n");
return -EIO;
}
if (_set_addr(dev, &((dev->addr_long).uint8[6]), IEEE802154_SHORT_ADDRESS_LEN) < 0) {
DEBUG("xbee: Error setting short address\n");
if (_set_addr(xbee, &((xbee->addr_long).uint8[6]), IEEE802154_SHORT_ADDRESS_LEN) < 0) {
DEBUG("[xbee] init: error setting short address\n");
return -EIO;
}
/* set default channel */
tmp[1] = 0;
tmp[0] = XBEE_DEFAULT_CHANNEL;
if (_set_channel(dev, tmp, 2) < 0) {
DEBUG("xbee: Error setting channel\n");
if (_set_channel(xbee, tmp, 2) < 0) {
DEBUG("[xbee] init: error setting channel\n");
return -EIO;
}
/* set default PAN ID */
tmp[1] = (uint8_t)(XBEE_DEFAULT_PANID >> 8);
tmp[0] = (uint8_t)(XBEE_DEFAULT_PANID & 0xff);
if (_set_panid(dev, tmp, 2) < 0) {
DEBUG("xbee: Error setting PAN ID\n");
if (_set_panid(xbee, tmp, 2) < 0) {
DEBUG("[xbee] init: error setting PAN ID\n");
return -EIO;
}
DEBUG("xbee: Initialization successful\n");
DEBUG("[xbee] init: Initialization successful\n");
return 0;
}
static inline bool _is_broadcast(gnrc_netif_hdr_t *hdr)
static int xbee_send(netdev2_t *dev, const struct iovec *vector, unsigned count)
{
/* IEEE 802.15.4 does not support multicast so we need to check both flags */
return (bool)(hdr->flags & (GNRC_NETIF_HDR_FLAGS_BROADCAST |
GNRC_NETIF_HDR_FLAGS_MULTICAST));
}
static int _send(gnrc_netdev_t *netdev, gnrc_pktsnip_t *pkt)
{
xbee_t *dev = (xbee_t *)netdev;
xbee_t *xbee = (xbee_t *)dev;
size_t size;
size_t pos;
gnrc_netif_hdr_t *hdr;
gnrc_pktsnip_t *payload;
uint8_t csum;
/* check device descriptor and packet */
if (pkt == NULL) {
return -ENOMSG;
}
if (dev == NULL) {
gnrc_pktbuf_release(pkt);
return -ENODEV;
}
assert(xbee && vector && (count > 0));
/* figure out the size of the payload to send */
size = gnrc_pkt_len(pkt->next);
if (size > XBEE_MAX_PAYLOAD_LENGTH) {
DEBUG("xbee: Error sending data, payload length exceeds limit\n");
gnrc_pktbuf_release(pkt);
return -EOVERFLOW;
}
/* get netif header check address length and flags */
hdr = (gnrc_netif_hdr_t *)pkt->data;
if (!((hdr->dst_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) ||
(hdr->dst_l2addr_len == IEEE802154_LONG_ADDRESS_LEN) ||
_is_broadcast(hdr))) {
gnrc_pktbuf_release(pkt);
return -ENOMSG;
}
/* acquire TX lock */
mutex_lock(&(dev->tx_lock));
/* put together the API frame */
dev->tx_buf[0] = API_START_DELIMITER;
dev->tx_buf[4] = 0; /* set to zero to disable response frame */
/* set size, API id and address field depending on dst address length */
if (_is_broadcast(hdr)) {
DEBUG("xbee: sending broadcast");
dev->tx_buf[1] = (uint8_t)((size + 5) >> 8);
dev->tx_buf[2] = (uint8_t)(size + 5);
dev->tx_buf[3] = API_ID_TX_SHORT_ADDR;
dev->tx_buf[5] = 0xff;
dev->tx_buf[6] = 0xff;
pos = 7;
}
else if (hdr->dst_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) {
uint8_t *destination = gnrc_netif_hdr_get_dst_addr(hdr);
DEBUG("xbee: sending unicast to %02x:%02x",
(uint8_t) destination[0], (uint8_t) destination[1]);
dev->tx_buf[1] = (uint8_t)((size + 5) >> 8);
dev->tx_buf[2] = (uint8_t)(size + 5);
dev->tx_buf[3] = API_ID_TX_SHORT_ADDR;
memcpy(dev->tx_buf + 5, destination, IEEE802154_SHORT_ADDRESS_LEN);
pos = 7;
}
else {
uint8_t *destination = gnrc_netif_hdr_get_dst_addr(hdr);
DEBUG("xbee: sending unicast to %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
(uint8_t) destination[0], (uint8_t) destination[1],
(uint8_t) destination[2], (uint8_t) destination[3],
(uint8_t) destination[4], (uint8_t) destination[5],
(uint8_t) destination[6], (uint8_t) destination[7]);
dev->tx_buf[1] = (uint8_t)((size + 11) >> 8);
dev->tx_buf[2] = (uint8_t)(size + 11);
dev->tx_buf[3] = API_ID_TX_LONG_ADDR;
memcpy(dev->tx_buf + 5, destination, IEEE802154_LONG_ADDRESS_LEN);
pos = 13;
}
/* set options */
DEBUG(", option: %02x", dev->options);
dev->tx_buf[pos++] = dev->options;
/* copy payload */
DEBUG(", payload:");
payload = pkt->next;
while (payload) {
#if ENABLE_DEBUG
for (size_t i = 0; i < payload->size; i++) {
DEBUG(" %02x", ((uint8_t *) payload->data)[i]);
/* calculate the checksum and the packet size */
size = vector[0].iov_len;
csum = _cksum(3, (uint8_t *)vector[0].iov_base, size);
for (unsigned i = 1; i < count; i++) {
size += vector[i].iov_len;
for (size_t p = 0; p < vector[i].iov_len; p++) {
csum -= ((uint8_t *)vector[i].iov_base)[p];
}
#endif
memcpy(&(dev->tx_buf[pos]), payload->data, payload->size);
pos += payload->size;
payload = payload->next;
}
/* set checksum */
dev->tx_buf[pos] = _cksum(dev->tx_buf, pos);
/* start transmission */
uart_write(dev->uart, dev->tx_buf, pos + 1);
/* release data */
gnrc_pktbuf_release(pkt);
/* release TX lock */
mutex_unlock(&(dev->tx_lock));
/* make sure the data fits into a packet */
if (size >= XBEE_MAX_PKT_LENGTH) {
DEBUG("[xbee] send: data to send is too large for TX buffer\n");
return -1;
}
/* send the actual data packet */
DEBUG("[xbee] send: now sending out %i byte\n", (int)size);
mutex_lock(&(xbee->tx_lock));
for (unsigned i = 0; i < count; i++) {
uart_write(xbee->p.uart, vector[i].iov_base, vector[i].iov_len);
}
uart_write(xbee->p.uart, &csum, 1);
mutex_unlock(&(xbee->tx_lock));
/* return number of payload byte */
DEBUG("\n");
return (int)size;
}
static int _add_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
static int xbee_recv(netdev2_t *dev, void *buf, size_t len, void *info)
{
if (dev == NULL) {
return -ENODEV;
(void)info;
size_t size;
xbee_t *xbee = (xbee_t *)dev;
assert(xbee);
/* make sure we have new data waiting */
if (xbee->rx_count != xbee->rx_limit) {
DEBUG("[xbee] recv: no data available for reading\n");
return 0;
}
if (dev->event_cb != NULL) {
return -ENOBUFS;
/* data available, so we read it (or it's size) */
size = (size_t)(xbee->rx_limit - 1);
if (buf == NULL) {
if (len > 0) {
DEBUG("[xbee] recv: reading size and dropping: %i\n", size);
xbee->rx_count = 0;
}
else {
DEBUG("[xbee] recv: reading size without dropping: %i\n", size);
}
}
dev->event_cb = cb;
return 0;
else {
size = (size > len) ? len : size;
DEBUG("[xbee] recv: consuming packet: reading %i byte\n", size);
memcpy(buf, xbee->rx_buf, size);
xbee->rx_count = 0;
}
return (int)size;
}
static int _rem_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
{
if (dev == NULL) {
return -ENODEV;
}
if (dev->event_cb != cb) {
return -ENOENT;
}
dev->event_cb = NULL;
return 0;
}
static int _get(gnrc_netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
static void xbee_isr(netdev2_t *netdev)
{
xbee_t *dev = (xbee_t *)netdev;
if (dev == NULL) {
return -ENODEV;
if (dev->rx_count == dev->rx_limit) {
/* make sure the checksum checks out */
if (_cksum(0, dev->rx_buf, dev->rx_limit) != 0) {
DEBUG("[xbee] isr: invalid RX checksum\n");
dev->rx_count = 0;
}
else {
DEBUG("[xbee] isr: data available, waiting for read\n");
dev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE);
}
}
}
static int xbee_get(netdev2_t *ndev, netopt_t opt, void *value, size_t max_len)
{
xbee_t *dev = (xbee_t *)ndev;
assert(dev);
switch (opt) {
case NETOPT_ADDRESS:
return _get_addr_short(dev, (uint8_t *)value, max_len);
assert(max_len >= IEEE802154_SHORT_ADDRESS_LEN);
memcpy(value, dev->addr_short, IEEE802154_SHORT_ADDRESS_LEN);
return IEEE802154_SHORT_ADDRESS_LEN;
case NETOPT_ADDRESS_LONG:
return _get_addr_long(dev, (uint8_t *)value, max_len);
assert(max_len >= IEEE802154_LONG_ADDRESS_LEN);
memcpy(value, dev->addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN);
return IEEE802154_LONG_ADDRESS_LEN;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
if (max_len < sizeof(uint16_t)) {
@ -761,12 +751,13 @@ static int _get(gnrc_netdev_t *netdev, netopt_t opt, void *value, size_t max_len
return -EOVERFLOW;
}
if (dev->addr_flags & XBEE_ADDR_FLAGS_LONG) {
ieee802154_get_iid(value, (uint8_t *)&dev->addr_long, IEEE802154_LONG_ADDRESS_LEN);
ieee802154_get_iid(value, dev->addr_long.uint8,
IEEE802154_LONG_ADDRESS_LEN);
}
else {
ieee802154_get_iid(value, (uint8_t *)&dev->addr_short, IEEE802154_SHORT_ADDRESS_LEN);
ieee802154_get_iid(value, dev->addr_short,
IEEE802154_SHORT_ADDRESS_LEN);
}
return sizeof(eui64_t);
case NETOPT_CHANNEL:
return _get_channel(dev, (uint8_t *)value, max_len);
@ -778,161 +769,45 @@ static int _get(gnrc_netdev_t *netdev, netopt_t opt, void *value, size_t max_len
return sizeof(uint16_t);
case NETOPT_NID:
return _get_panid(dev, (uint8_t *)value, max_len);
case NETOPT_PROTO:
return _get_proto(dev, (uint8_t *)value, max_len);
default:
return -ENOTSUP;
}
}
static int _set(gnrc_netdev_t *netdev, netopt_t opt, void *value, size_t value_len)
static int xbee_set(netdev2_t *ndev, netopt_t opt, void *value, size_t len)
{
xbee_t *dev = (xbee_t *)netdev;
if (dev == NULL) {
return -ENODEV;
}
xbee_t *dev = (xbee_t *)ndev;
assert(dev);
switch (opt) {
case NETOPT_ADDRESS:
return _set_addr(dev, (uint8_t *)value, value_len);
return _set_addr(dev, (uint8_t *)value, len);
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
return _set_addr_len(dev, value, value_len);
return _set_addr_len(dev, value, len);
case NETOPT_CHANNEL:
return _set_channel(dev, (uint8_t *)value, value_len);
return _set_channel(dev, (uint8_t *)value, len);
case NETOPT_NID:
return _set_panid(dev, (uint8_t *)value, value_len);
case NETOPT_PROTO:
return _set_proto(dev, (uint8_t *)value, value_len);
return _set_panid(dev, (uint8_t *)value, len);
#ifdef MODULE_XBEE_ENCRYPTION
case NETOPT_ENCRYPTION:
return _set_encryption(dev, (uint8_t *)value);
case NETOPT_ENCRYPTION_KEY:
return _set_encryption_key(dev, (uint8_t *)value, value_len);
return _set_encryption_key(dev, (uint8_t *)value, len);
#endif
default:
return -ENOTSUP;
}
}
static void _isr_event(gnrc_netdev_t *netdev, uint32_t event_type)
{
xbee_t *dev = (xbee_t *)netdev;
gnrc_pktsnip_t *pkt_head;
gnrc_pktsnip_t *pkt;
gnrc_netif_hdr_t *hdr;
size_t pos;
size_t addr_len;
uint8_t cksum = 0;
/* check device */
if (dev == NULL) {
return;
}
/* check rx callback and event type */
if (event_type != ISR_EVENT_RX_DONE || dev->event_cb == NULL) {
dev->rx_count = 0;
return;
}
/* read address length */
if (dev->rx_buf[0] == API_ID_RX_SHORT_ADDR) {
addr_len = IEEE802154_SHORT_ADDRESS_LEN;
}
else {
addr_len = IEEE802154_LONG_ADDRESS_LEN;
}
#ifdef XBEE_DENIED_ADDRESSES
if (addr_len == 8) {
uint8_t denied_addresses[] = XBEE_DENIED_ADDRESSES;
for (size_t i = 0; i < sizeof(denied_addresses) / 8; i++) {
if (memcmp(&(dev->rx_buf[1]),
&denied_addresses[i * 8],
addr_len) == 0) {
dev->rx_count = 0;
DEBUG("xbee: dropping denied packet\n");
return;
}
}
}
#endif
/* check checksum for correctness */
for (int i = 0; i < dev->rx_limit; i++) {
cksum += dev->rx_buf[i];
}
if (cksum != 0xff) {
DEBUG("xbee: Received packet with incorrect checksum, dropping it\n");
dev->rx_count = 0;
return;
}
/* allocate and fill interface header */
pkt_head = gnrc_pktbuf_add(NULL, NULL,
sizeof(gnrc_netif_hdr_t) + (2 * addr_len),
GNRC_NETTYPE_NETIF);
if (pkt_head == NULL) {
DEBUG("xbee: Error allocating netif header in packet buffer on RX\n");
dev->rx_count = 0;
return;
}
hdr = (gnrc_netif_hdr_t *)pkt_head->data;
hdr->src_l2addr_len = (uint8_t)addr_len;
hdr->dst_l2addr_len = (uint8_t)addr_len;
hdr->if_pid = dev->mac_pid;
hdr->rssi = dev->rx_buf[1 + addr_len]; /* API ID + source address */
hdr->lqi = 0;
gnrc_netif_hdr_set_src_addr(hdr, &(dev->rx_buf[1]), addr_len);
if (addr_len == 2) {
gnrc_netif_hdr_set_dst_addr(hdr, dev->addr_short, IEEE802154_SHORT_ADDRESS_LEN);
}
else {
gnrc_netif_hdr_set_dst_addr(hdr, dev->addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN);
}
pos = 3 + addr_len;
/* allocate and copy payload */
pkt = gnrc_pktbuf_add(pkt_head, &(dev->rx_buf[pos]), dev->rx_limit - pos - 1,
dev->proto);
if (pkt == NULL) {
DEBUG("xbee: Error allocating payload in packet buffer on RX\n");
gnrc_pktbuf_release(pkt_head);
dev->rx_count = 0;
return;
}
#if ENABLE_DEBUG
DEBUG("xbee: received packet from");
for (size_t i = 0; i < addr_len; i++) {
DEBUG(" %02x", (uint8_t) gnrc_netif_hdr_get_src_addr(hdr)[i]);
}
DEBUG(", RSSI: -%d dBm", hdr->rssi);
DEBUG(", options: %02x", (uint8_t) dev->rx_buf[1 + addr_len + 1]); /* API ID + source address + RSSI */
DEBUG(", payload:");
for (size_t i = 0; i < pkt->size; i++) {
DEBUG(" %02x", ((uint8_t *) pkt->data)[i]);
}
DEBUG("\n");
#endif
/* pass on the received packet */
dev->event_cb(NETDEV_EVENT_RX_COMPLETE, pkt);
/* reset RX byte counter to enable receiving of the next packet */
dev->rx_count = 0;
}
/*
* The drivers netdev interface
*/
const gnrc_netdev_driver_t xbee_driver = {
.send_data = _send,
.add_event_callback = _add_cb,
.rem_event_callback = _rem_cb,
.get = _get,
.set = _set,
.isr_event = _isr_event,
const netdev2_driver_t xbee_driver = {
.send = xbee_send,
.recv = xbee_recv,
.init = xbee_init,
.isr = xbee_isr,
.get = xbee_get,
.set = xbee_set,
};

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief xbee driver parameters example, used by auto_init_gnrc_netif
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef XBEE_PARAMS_H
#define XBEE_PARAMS_H
#ifdef __cplusplus
extern "C" {
#endif
static xbee_params_t xbee_params[] = {
{ .uart = XBEE_UART,
.baudrate = 9600U,
.sleep_pin = GPIO_UNDEF,
.reset_pin = GPIO_UNDEF
},
};
#ifdef __cplusplus
}
#endif
#endif /* XBEE_PARAMS_H */
/** @} */

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief xbee driver parameters example, used by auto_init_gnrc_netif
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef XBEE_PARAMS_H
#define XBEE_PARAMS_H
#ifdef __cplusplus
extern "C" {
#endif
static xbee_params_t xbee_params[] = {
{ .uart = XBEE_UART,
.baudrate = 9600U,
.sleep_pin = GPIO_UNDEF,
.reset_pin = GPIO_UNDEF
},
};
#ifdef __cplusplus
}
#endif
#endif /* XBEE_PARAMS_H */
/** @} */