diff --git a/sys/include/net/gnrc/netdev2/xbee_adpt.h b/sys/include/net/gnrc/netdev2/xbee_adpt.h new file mode 100644 index 0000000000..68106c4e97 --- /dev/null +++ b/sys/include/net/gnrc/netdev2/xbee_adpt.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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. + */ + +/** + * @addtogroup net_gnrc + * @{ + * + * @file + * @brief GNRC to XBee netdev2 glue code interface + * + * Although the XBee devices are IEEE802.15.4 transceivers, use their own + * proprietary format for communicating between the host CPU and the device over + * UART. The XBee device driver expects the data to send to be given in this + * format, hence we need to introduce an XBee specific adaption layer that + * translates between GNRC and the XBee proprietary header format. + * + * For this custom header format, we can not make use of the existing adaption + * layers for other IEEE802.15.4 devices. + * + * @author Hauke Petersen + */ + +#ifndef GNRC_NETDEV2_XBEE_ADPT_H_ +#define GNRC_NETDEV2_XBEE_ADPT_H_ + +#include "xbee.h" +#include "net/gnrc/netdev2.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize GNRC handler for netdev2 XBee devices + * + * @param[out] gnrc_netdev2 gnrc_netdev2 struct to initialize + * @param[in] dev XBee device to handle + */ +void gnrc_netdev2_xbee_init(gnrc_netdev2_t *gnrc_netdev2, xbee_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_NETDEV2_XBEE_ADPT_H_ */ +/** @} */ diff --git a/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_xbee.c b/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_xbee.c new file mode 100644 index 0000000000..84a5e14abb --- /dev/null +++ b/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_xbee.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 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 net_gnrc + * @{ + * + * @file + * @brief GNRC to netdev adapter for XBee devices + * + * @author Hauke Petersen + * + * @} + */ + +#include "assert.h" +#include "xbee.h" +#include "net/gnrc.h" +#include "net/gnrc/netdev2/xbee_adpt.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define BCAST (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST) + +static gnrc_pktsnip_t *xbee_adpt_recv(gnrc_netdev2_t *gnrc_netdev2) +{ + netdev2_t *dev = gnrc_netdev2->dev; + int pktlen; + int xhdr_len; + gnrc_pktsnip_t *payload; + gnrc_pktsnip_t *netif_snip; + gnrc_pktsnip_t *xhdr_snip; + gnrc_netif_hdr_t *netif; + xbee_l2hdr_t l2hdr; + + assert(dev); + + /* see how much data there is to process */ + pktlen = dev->driver->recv(dev, NULL, 0, NULL); + if (pktlen <= 0) { + DEBUG("[xbee-gnrc] recv: no data available to process\n"); + return NULL; + } + + /* allocate space for the packet in the pktbuf */ + payload = gnrc_pktbuf_add(NULL, NULL, pktlen, XBEE_DEFAULT_PROTOCOL); + if (payload == NULL) { + DEBUG("[xbee-gnrc] recv: unable to allocate space in the pktbuf\n"); + /* tell the driver to drop the packet */ + dev->driver->recv(dev, NULL, 1, NULL); + return NULL; + } + + /* copy the complete including the XBee header into the packet buffer */ + dev->driver->recv(dev, payload->data, pktlen, NULL); + + /* try to parse the L2 header data from the XBee header */ + xhdr_len = xbee_parse_hdr((xbee_t *)dev, (uint8_t *)payload->data, &l2hdr); + if (xhdr_len < 0) { + DEBUG("[xbee-gnrc] recv: unable to parse XBee header\n"); + gnrc_pktbuf_release(payload); + return NULL; + } + + /* crop the XBee header from the payload */ + xhdr_snip = gnrc_pktbuf_mark(payload, xhdr_len, GNRC_NETTYPE_UNDEF); + if (xhdr_snip == NULL) { + DEBUG("[xbee-gnrc] recv: unable to mark XBee header snip\n"); + gnrc_pktbuf_release(payload); + return NULL; + } + gnrc_pktbuf_remove_snip(payload, xhdr_snip); + + /* create a netif hdr from the obtained data */ + netif_snip = gnrc_netif_hdr_build(l2hdr.src_addr, l2hdr.addr_len, + l2hdr.dst_addr, l2hdr.addr_len); + if (netif_snip == NULL) { + DEBUG("[xbee-gnrc] recv: unable to allocate netif header\n"); + gnrc_pktbuf_release(payload); + return NULL; + } + netif = (gnrc_netif_hdr_t *)netif_snip->data; + netif->if_pid = gnrc_netdev2->pid; + netif->rssi = l2hdr.rssi; + if (l2hdr.bcast) { + netif->flags = GNRC_NETIF_HDR_FLAGS_BROADCAST; + } + + DEBUG("[xbee-gnrc] recv: successfully parsed packet\n"); + + /* and append the netif header */ + LL_APPEND(payload, netif_snip); + + return payload; +} + +static int xbee_adpt_send(gnrc_netdev2_t *dev, gnrc_pktsnip_t *pkt) +{ + int res; + size_t size; + size_t count; + gnrc_pktsnip_t *vec; + gnrc_netif_hdr_t *hdr; + uint8_t xhdr[XBEE_MAX_TXHDR_LENGTH]; + + /* check device descriptor and packet */ + assert(dev && pkt); + + /* get the payload size and the dst address details */ + size = gnrc_pkt_len(pkt->next); + DEBUG("[xbee-gnrc] send: payload of packet is %i\n", (int)size); + hdr = (gnrc_netif_hdr_t *)pkt->data; + if (hdr->flags & BCAST) { + uint16_t addr = 0xffff; + res = xbee_build_hdr((xbee_t *)dev, xhdr, size, &addr, 2); + DEBUG("[xbee-gnrc] send: preparing to send broadcast\n"); + } + else { + uint8_t *addr = gnrc_netif_hdr_get_dst_addr(hdr); + res = xbee_build_hdr((xbee_t *)dev, xhdr, size, addr, hdr->dst_l2addr_len); + if (res < 0) { + if (res == -EOVERFLOW) { + DEBUG("[xbee-gnrc] send: payload length exceeds max limit\n"); + } + else if (res == -ENOMSG) { + DEBUG("[xbee-gnrc] send: invalid destination l2 address\n"); + } + return res; + } + if (hdr->dst_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) { + DEBUG("[xbee-gnrc] send: preparing to send unicast to %02x:%02x\n", + (int)addr[0], (int)addr[1]); + } + else { + DEBUG("[xbee-gnrc] send: preparing to send unicast to " + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + (int)addr[0], (int)addr[1], (int)addr[2], (int)addr[3], + (int)addr[4], (int)addr[5], (int)addr[6], (int)addr[7]); + } + } + + /* now let's extract the iovector and send out the stuff */ + vec = gnrc_pktbuf_get_iovec(pkt, &count); + if (vec != NULL) { + pkt = vec; + struct iovec *vector = (struct iovec *)pkt->data; + vector[0].iov_base = xhdr; + vector[0].iov_len = res; +#ifdef MODULE_NETSTATS_L2 + if (hdr->flags & BCAST) { + dev->dev->stats.tx_mcast_count++; + } + else { + dev->dev->stats.tx_unicast_count++; + } +#endif + DEBUG("[xbee-gnrc] send: triggering the drivers send function\n"); + res = dev->dev->driver->send(dev->dev, vector, count); + } + else { + DEBUG("[xbee-gnrc] send: unable to create iovec\n"); + } + + gnrc_pktbuf_release(pkt); + + return res; +} + +void gnrc_netdev2_xbee_init(gnrc_netdev2_t *gnrc_netdev2, xbee_t *dev) +{ + assert(gnrc_netdev2 && dev); + + gnrc_netdev2->send = xbee_adpt_send; + gnrc_netdev2->recv = xbee_adpt_recv; + gnrc_netdev2->dev = (netdev2_t *)dev; +}