diff --git a/drivers/cc1xxx_common/Makefile b/drivers/cc1xxx_common/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/cc1xxx_common/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c b/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c new file mode 100644 index 0000000000..c25e4aadc6 --- /dev/null +++ b/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2016-17 Freie Universität Berlin + * 2018 Otto-von-Guericke-Universität Magdeburg + * + * 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_netif + * @{ + * + * @file + * + * @author Martine Lenders + * @author Hauke Petersen + * @author Marian Buschsieweke + * + * Adapted from @ref gnrc_xbee.c with only minor modifications. So all credit + * goes to Martine Lenders and to + * Hauke Petersen . + * + * @} + */ + +#include "assert.h" +#include "net/gnrc.h" +#include "cc1xxx_common.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define BCAST (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST) + +static gnrc_pktsnip_t *cc1xxx_adpt_recv(gnrc_netif_t *netif) +{ + netdev_t *dev = netif->dev; + cc1xxx_rx_info_t rx_info; + int pktlen; + gnrc_pktsnip_t *payload; + gnrc_pktsnip_t *hdr; + gnrc_netif_hdr_t *netif_hdr; + cc1xxx_l2hdr_t l2hdr; + + assert(dev); + + /* see how much data there is to process */ + pktlen = dev->driver->recv(dev, NULL, 0, &rx_info); + if (pktlen <= 0) { + DEBUG("[cc1xxx-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, CC1XXX_DEFAULT_PROTOCOL); + if (payload == NULL) { + DEBUG("[cc1xxx-gnrc] recv: unable to allocate space in the pktbuf\n"); + /* tell the driver to drop the packet */ + dev->driver->recv(dev, NULL, pktlen, NULL); + return NULL; + } + + /* copy the complete including the CC1XXX header into the packet buffer */ + dev->driver->recv(dev, payload->data, pktlen, NULL); + + /* The first two bytes are the layer 2 header */ + l2hdr.dest_addr = ((uint8_t *)payload->data)[0]; + l2hdr.src_addr = ((uint8_t *)payload->data)[1]; + + /* crop the layer 2 header from the payload */ + hdr = gnrc_pktbuf_mark(payload, sizeof(cc1xxx_l2hdr_t), GNRC_NETTYPE_UNDEF); + if (hdr == NULL) { + DEBUG("[cc1xxx-gnrc] recv: unable to mark cc1xxx header snip\n"); + gnrc_pktbuf_release(payload); + return NULL; + } + gnrc_pktbuf_remove_snip(payload, hdr); + + /* create a netif hdr from the obtained data */ + hdr = gnrc_netif_hdr_build(&l2hdr.src_addr, CC1XXX_ADDR_SIZE, + &l2hdr.dest_addr, CC1XXX_ADDR_SIZE); + if (hdr == NULL) { + DEBUG("[cc1xxx-gnrc] recv: unable to allocate netif header\n"); + gnrc_pktbuf_release(payload); + return NULL; + } + netif_hdr = (gnrc_netif_hdr_t *)hdr->data; + netif_hdr->if_pid = netif->pid; + netif_hdr->rssi = rx_info.rssi; + netif_hdr->lqi = rx_info.lqi; + if (l2hdr.dest_addr == CC1XXX_BCAST_ADDR) { + netif_hdr->flags = GNRC_NETIF_HDR_FLAGS_BROADCAST; + } + + DEBUG("[cc1xxx-gnrc] recv: successfully parsed packet\n"); + + /* and append the netif header */ + LL_APPEND(payload, hdr); + + return payload; +} + +static int cc1xxx_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) +{ + int res; + size_t size; + cc1xxx_t *cc1xxx_dev = (cc1xxx_t *)netif->dev; + gnrc_netif_hdr_t *netif_hdr; + cc1xxx_l2hdr_t l2hdr; + + /* check device descriptor and packet */ + assert(netif && pkt); + + /* get the payload size and the dst address details */ + size = gnrc_pkt_len(pkt->next); + DEBUG("[cc1xxx-gnrc] send: payload of packet is %i\n", (int)size); + netif_hdr = (gnrc_netif_hdr_t *)pkt->data; + + + l2hdr.src_addr = cc1xxx_dev->addr; + if (netif_hdr->flags & BCAST) { + l2hdr.dest_addr = CC1XXX_BCAST_ADDR; + DEBUG("[cc1xxx-gnrc] send: preparing to send broadcast\n"); + } + else { + /* check that destination address is valid */ + assert(netif_hdr->dst_l2addr_len > 0); + uint8_t *addr = gnrc_netif_hdr_get_dst_addr(netif_hdr); + l2hdr.dest_addr = addr[0]; + DEBUG("[cc1xxx-gnrc] send: preparing to send unicast %02x --> %02x\n", + (int)l2hdr.src_addr, (int)l2hdr.dest_addr); + } + + /* now let's send out the stuff */ + iolist_t iolist = { + .iol_next = (iolist_t *)pkt->next, + .iol_base = &l2hdr, + .iol_len = sizeof(l2hdr), + }; + +#ifdef MODULE_NETSTATS_L2 + if (netif_hdr->flags & BCAST) { + netif->dev->stats.tx_mcast_count++; + } + else { + netif->dev->stats.tx_unicast_count++; + } +#endif + DEBUG("[cc1xxx-gnrc] send: triggering the drivers send function\n"); + res = netif->dev->driver->send(netif->dev, &iolist); + + gnrc_pktbuf_release(pkt); + + return res; +} + +static const gnrc_netif_ops_t cc1xxx_netif_ops = { + .send = cc1xxx_adpt_send, + .recv = cc1xxx_adpt_recv, + .get = gnrc_netif_get_from_netdev, + .set = gnrc_netif_set_from_netdev, +}; + +gnrc_netif_t *gnrc_netif_cc1xxx_create(char *stack, int stacksize, + char priority, char *name, + netdev_t *dev) +{ + return gnrc_netif_create(stack, stacksize, priority, name, + dev, &cc1xxx_netif_ops); +} diff --git a/drivers/include/cc1xxx_common.h b/drivers/include/cc1xxx_common.h new file mode 100644 index 0000000000..f93bee855d --- /dev/null +++ b/drivers/include/cc1xxx_common.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * 2018 Otto-von-Guericke-Universität Magdeburg + * + * 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. + */ + +/** + * @defgroup drivers_cc1xxx CC1100/CC1100e/CC1101/CC1200 common code + * @ingroup drivers_netdev + * @ingroup net_gnrc_netif + * @{ + * + * @file + * @brief CC110x/CC1200 adaption for @ref net_gnrc_netif + * + * @author Martine Lenders + * @author Hauke Petersen + * @author Marian Buschsieweke + * + * Supported Transceivers + * ====================== + * + * This adaption layer is written to be used by CC110x and CC1200 transceivers, + * but any transceiver using layer 2 addresses which are 1 byte in size would + * likely be able to use it. Keep in mind that both CC110x and CC1200 are able + * to transmit frames of up to 255 bytes (thus 253 bytes of payload, as the + * layer 2 header is 2 bytes in size). Other transceivers only supporting + * smaller frames may not be able to use all the upper layer protocols supported + * by the CC110x and CC1200 transceivers. + * + * Frame Format + * ============ + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination | Source | Payload... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * | Field | Description | + * |-------------|---------------------------------| + * | Destination | The layer 2 destination address | + * | Source | The layer 2 source address | + * | Payload | The payload (variable size) | + * + * Layer 2 Broadcast + * ================= + * + * This adaption layer assumes that the layer 2 address `0x00` (see + * @ref CC1XXX_BCAST_ADDR) is reserved for layer 2 broadcast, which is true for + * CC110x and CC1200 transceivers (provided they are configured accordingly). If + * more users of this adaption layer are added, this behaviour might needs to be + * more generalized. + */ +#ifndef CC1XXX_COMMON_H +#define CC1XXX_COMMON_H + +#include "net/gnrc/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Default protocol for data that is coming in + */ +#ifdef MODULE_GNRC_SIXLOWPAN +#define CC1XXX_DEFAULT_PROTOCOL (GNRC_NETTYPE_SIXLOWPAN) +#else +#define CC1XXX_DEFAULT_PROTOCOL (GNRC_NETTYPE_UNDEF) +#endif + +/** + * @brief Size of a layer 2 address on CC110x/CC1200 transceivers + */ +#define CC1XXX_ADDR_SIZE (1) + +/** + * @brief Special layer 2 address reserved for broadcast frames + */ +#define CC1XXX_BCAST_ADDR (0x00) + +/** + * @brief Layer 2 header used in CC1xxx frames + * + * This structure has the same memory layout as the data send in the frames. + */ +typedef struct __attribute__((packed)) { + uint8_t dest_addr; /**< Destination layer 2 address */ + uint8_t src_addr; /**< Source layer 2 address */ +} cc1xxx_l2hdr_t; + +/** + * @brief Users of the CC110x/CC1200 adaption layer have to overlap their + * device handle with this structure. + * + * The first two fields of the device structure of any transceiver driver using + * this adaption layer have to be equal to the `cc1xxx_t` structure. This allows + * efficient access to the current layer 2 address of the device from the + * adaption layer. + */ +typedef struct { + netdev_t netdev; /**< RIOT's interface to this driver */ + uint8_t addr; /**< Layer 2 address of this device */ +} cc1xxx_t; + +/** + * @brief Statistics for one received frame + */ +typedef struct netdev_radio_rx_info cc1xxx_rx_info_t; + +/** + * @brief Creates a CC110x/CC1200 network interface + * + * @param[in] stack The stack for the network interface's thread. + * @param[in] stacksize Size of @p stack. + * @param[in] priority Priority for the network interface's thread. + * @param[in] name Name for the network interface. May be NULL. + * @param[in] dev Device for the interface. + * + * @see @ref gnrc_netif_create() + * + * @return The network interface on success. + */ +gnrc_netif_t *gnrc_netif_cc1xxx_create(char *stack, int stacksize, + char priority, char *name, + netdev_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* CC1XXX_COMMON_H */ +/** @} */