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