1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/include/net/netdev/ble.h
2018-04-06 11:18:53 +02:00

201 lines
6.9 KiB
C

/*
* 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 */
/** @} */