mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
201 lines
6.9 KiB
C
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 */
|
|
/** @} */
|