From 4e715e8221e500f578e12d25f36f183dd6c79813 Mon Sep 17 00:00:00 2001 From: Hauke Petersen <hauke.petersen@fu-berlin.de> Date: Thu, 5 Apr 2018 10:55:39 +0200 Subject: [PATCH] drivers/netdev: added BLE adaption for netdev --- drivers/include/net/netdev/ble.h | 200 +++++++++++++++++++++++++++++ sys/include/net/netopt.h | 2 + sys/net/crosslayer/netopt/netopt.c | 1 + 3 files changed, 203 insertions(+) create mode 100644 drivers/include/net/netdev/ble.h diff --git a/drivers/include/net/netdev/ble.h b/drivers/include/net/netdev/ble.h new file mode 100644 index 0000000000..e70a4d0442 --- /dev/null +++ b/drivers/include/net/netdev/ble.h @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2017-2018 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. + */ + +/** + * @defgroup drivers_netdev_ble Netdev BLE mode + * @ingroup drivers_netdev_api + * @brief BLE adaption of netdev + * @{ + * + * @warning This API is experimental and in an early state - expect + * significant changes! + * + * # About + * + * BLE defines a very specific environment for the used radio, both in terms of + * communication sequences and in terms of timings. BLE communication is + * structured in so called events, where each event is a sequence of request and + * reply packets send between two peers. A radio context (frequency, CRC + * initializer, and access address) is used throughout such an event and + * typically changed for the next one. In addition, the timing of the packets + * sent in a sequence is fixed to an inter-frame-spacing of exactly 150us. + * + * To cater with these specific attributes of BLE, this interface tailors the + * generic netdev interface to be used for BLE radios. + * + * + * # Interface Adaption / Netdev Interpretation + * + * ## Transmission Sequence Based Approach + * + * To be able to handle the exact inter-packet-spacing if 150us seconds, this + * interface expects the device driver to stay in a continuous alternating + * RX-TX sequence, until it is manually aborted. While in this sequence, the + * radio driver needs to take care of switching to RX mode 150us after sending + * the last packet, and to send the next packet 150us after the last packet was + * received. + * + * Such a transmission sequence is started by calling either the radio's send + * or receive function while the radio is in idle/standby mode. + * + * Once a transmission sequence is in progress, the next packet to be send, or + * the next reception buffer to be used is specified also using the send/recv + * functions. They should be called in the `event_callback` right after the + * last transmission (RX or TX) was finished. + * + * The transmission sequence is aborted by calling `netdev_ble_stop(dev)` + * (`netdev->set(dev, NETOPT_BLE_CTX, NULL, 0)`). This will put the radio back + * into idle/standby mode. + * + * ## Radio Context + * + * As BLE uses time sliced channel hopping, the used channel needs to be set + * regularly. Additionally, also the used access address and the CRC initializer + * need to be set regularly, as they differ for different BLE connections. To + * make setting these values more efficient, this interface combines these three + * values in to a so called `radio context` and adds a `netopt` option to set + * all three values at once using `netdev_ble_set_ctx(dev, ctx)` + * (`netdev->set(dev, NETOPT_BLE_CTX, ctx, sizeof(netdev_ble_ctx_t))`). + * + * + * # Implementation Status and Limitations + * - This interface works for memory mapped radios only (no support for + * bus-connected devices). This is mainly for timing reasons. + * - No support for LE Data Length Extension (bigger packet size), yet + * + * @file + * @brief BLE specific adaption for the Netdev API + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + */ + +#ifndef NET_NETDEV_BLE_H +#define NET_NETDEV_BLE_H + +#include "net/netdev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum payload length of a standard BLE packet + */ +#define NETDEV_BLE_PDU_MAXLEN (37U) + +/** + * @brief Mask for the actual (3 byte) CRC data in the context's CRC field + */ +#define NETDEV_BLE_CRC_MASK (0x00ffffff) + +/** + * @brief Flag for marking a correct CRC on packet reception + */ +#define NETDEV_BLE_CRC_OK (0x80000000) + +/** + * @brief BLE packet structure (as defined by the BLE standard) + */ +typedef struct __attribute__((packed)) { + uint8_t flags; /**< header flags */ + uint8_t len; /**< actual length of PDU */ + uint8_t pdu[NETDEV_BLE_PDU_MAXLEN]; /**< protocol data unit (PDU) */ +} netdev_ble_pkt_t; + +/** + * @brief Radio context + */ +typedef struct { + union { + uint8_t raw[4]; /**< byte-wise access */ + uint32_t u32; /**< compact access */ + } aa; /**< access address */ + uint32_t crc; /**< CRC: 3 LSB for CRC, most + * significant bit for RX state*/ + uint8_t chan; /**< channel to use/used */ +} netdev_ble_ctx_t; + +/** + * @brief Send the given packet on the next occasion + * + * If a transmission sequence is in progress, the given packet will be send + * after 150us after receptions of the last packet. If no sequence is currently + * active, the packet will be send immediately and a new transmission sequence + * is started. + * + * @note Call this function only to start a new transmission sequence (radio + * is currently idle), or right after a packet was received. If called + * at any other point in time, the behavior is undefined. + * + * @param[in] dev radio to use for sending + * @param[in] pkt data to send + * + * @return 0 on success + * @return `< 0` on error + */ +static inline int netdev_ble_send(netdev_t *dev, netdev_ble_pkt_t *pkt) +{ + struct iolist data = { NULL, pkt, sizeof(netdev_ble_pkt_t) }; + return dev->driver->send(dev, &data); +} + +/** + * @brief Start listening for an incoming packet and write it into @p pkt + * + * If a transmission sequence is in progress, the radio will use the given + * buffer for reception when it goes in to RX mode 150us after sending the last + * packet. If no sequence is in progress, the radio will go into RX mode + * immediately (using the given RX buffer), and a new transmission sequence is + * started. + * + * @note Call this function only to start a new transmission sequence (radio + * is currently idle), or right after a packet was sent. If called + * at any other point in time, the behavior is undefined. + * + * @param[in] dev radio to use for receiving + * @param[out] pkt buffer to write new packet to + * + * @return 0 on success + * @return `< 0` on error + */ +static inline int netdev_ble_recv(netdev_t *dev, netdev_ble_pkt_t *pkt) +{ + return dev->driver->recv(dev, pkt, sizeof(netdev_ble_pkt_t), NULL); +} + +/** + * @brief Set the radio context for the given radio device + * + * @param[in] dev target radio device + * @param[in] ctx new radio context (CRC, channel, access address) + */ +static inline void netdev_ble_set_ctx(netdev_t *dev, netdev_ble_ctx_t *ctx) +{ + dev->driver->set(dev, NETOPT_BLE_CTX, ctx, sizeof(netdev_ble_ctx_t)); +} + +/** + * @brief Stop the ongoing RX/TX sequence + * + * @note This function has not effect if the radio is in the middle of a + * data transfer + * + * @param[in] dev target radio device + */ +static inline void netdev_ble_stop(netdev_t *dev) +{ + dev->driver->set(dev, NETOPT_BLE_CTX, NULL, 0); +} + +#ifdef __cplusplus +} +#endif + +#endif /* NET_NETDEV_BLE_H */ +/** @} */ diff --git a/sys/include/net/netopt.h b/sys/include/net/netopt.h index d921aa72ed..61e1965e2a 100644 --- a/sys/include/net/netopt.h +++ b/sys/include/net/netopt.h @@ -532,6 +532,8 @@ typedef enum { */ NETOPT_TX_RETRIES_NEEDED, + NETOPT_BLE_CTX, /**< set radio context (channel, CRC, AA) */ + /* add more options if needed */ /** diff --git a/sys/net/crosslayer/netopt/netopt.c b/sys/net/crosslayer/netopt/netopt.c index 951d2f0a90..e9ba46d5a4 100644 --- a/sys/net/crosslayer/netopt/netopt.c +++ b/sys/net/crosslayer/netopt/netopt.c @@ -89,6 +89,7 @@ static const char *_netopt_strmap[] = { [NETOPT_IQ_INVERT] = "NETOPT_IQ_INVERT", [NETOPT_TX_RETRIES_NEEDED] = "NETOPT_TX_RETRIES_NEEDED", [NETOPT_6LO_IPHC] = "NETOPT_6LO_IPHC", + [NETOPT_BLE_CTX] = "NETOPT_BLE_CTX", [NETOPT_NUMOF] = "NETOPT_NUMOF", }; -- GitLab