78 KiB
- RDM: 2
- Title: The IEEE802.15.4 radio HAL
- Authors: José Álamos
- Status: Deprecated by RDM 0004
- Type: Design
- Created: March 2020
1. Abstract
This memo describes a Hardware Abstraction Layer (HAL) for radios compliant with the IEEE802.15.4 standard. The work follows a technology-specific approach to provide well defined hardware access that allows to implement agnostic IEEE802.15.4 PHY and MAC layers on top. Additionally, the new HAL enables integration of network stacks that require direct access to the radio.
2. Status
This document is currently under open discussions. The content of this document is licensed with a Creative Commons CC-BY-SA license.
2.1 Terminology
This memo uses the RFC2119 terminology and the following acronyms and definitions:
2.2 Acronyms
- RDM: RIOT Developer Memo
- PIB: Physical Information Base.
- MIB: MAC Information Base.
2.3 Definitions
- SubMAC: Lower layer of the IEEE802.15.4 MAC that provides the retransmissions with CSMA-CA logic, address filtering and CRC validation.
- Standalone CCA: Single run of the Clear Channel Assessment procedure.
- Continuous CCA: Clear Channel Assessment procedure followed by transmission (required by the CSMA-CA algorithm)
- Caps: Short word for capabilities. In this context, capabilities are the the features (hardware acceleration) present in a radio device.
- Ops: Short word for operations. In this context, operations are a set of instructions to control the radio device.
3. Introduction
This document is a product of the Uniform Network Stack Integration and aims to describe the architecture of a Hardware Abstraction Layer for IEEE802.15.4 compliant radios.
The IEEE802.15.4 Radio HAL abstracts common functionalities of IEEE802.15.4 compliant radios such as loading packets, transmitting, configuring PHY parameters, etc. This abstraction is required for upper layers that require hardware-independent access to drive IEEE802.15.4 radio devices (802.15.4 MAC, network stacks, test applications, etc).
In the current RIOT lower network stack architecture, all network interfaces
are driven by the netdev
interface. The work presented in this document
addresses deficits of using netdev
as a Hardware Abstraction Layer:
netdev
is too generic to be used as a HAL to cover the wide range of different technologies in RIOT (IEEE802.15.4, BLE, Ethernet, WiFi, Proprietary devices, ...). The semantics of a standardized radio are technology specific and in most cases well defined. In the case of IEEE802.15.4 devices, they are defined by the IEEE.netdev
includes PHY and MAC components that are not in the scope of a hardware abstraction layer. Thenetdev
interface is implemented as a device driver but it additionally includes technology-dependent components for every single device. For the case of IEEE802.15.4, this includes components of the 802.15.4 MAC/PHY such as transmission of Physical Service Data Units (PSDU), or retransmissions with CSMA-CA and ACK handling. As a consequence, code is duplicated, feature sets of similar devices heavily depend on the specific implementation, and integration of new devices is more complex than need be. Furthermore, duplication and unspecified device access complicate code maintenance.netdev
hardcodes MAC layer functionalities, which is likely the consequence of hardware MAC acceleration on certain devices. These capabilities are currently only available if the hardware provides integrated support. An indication mechanism which MAC features are provided within anetdev
implementation is missing. A full MAC layer that is situated on top of the HAL requires a defined access to specific radio functionalities in order to meet timing constraints or energy requirements. That means, varying properties between implementations and partly implemented MAC features within the device driver interfere with the concept of transparent hardware access by one MAC layer implementation.
Other components of the 802.15.4 MAC are present in the GNRC Netif
implementation for the 802.15.4 Link Layer (gnrc_netif_ieee802154
). These
components prepare and parse 802.15.4 frames in order to send and receive data.
However, mandatory 802.15.4 MAC features are missing (commissioning, security,
channel scanning, etc). One major drawback of this approach is the fact that
802.15.4 MAC components of gnrc_netif_ieee802154
are GNRC specific and
cannot be reused in other network stacks that require a 802.15.4 MAC.
As a solution, the lower layer should be separated into three main components:
- 802.15.4 Radio HAL: hardware-agnostic interface to drive radio devices (proposed in this RDM).
- 802.15.4 MAC: full link layer including PHY definition.
- Network Stack interface (netif): controls the 802.15.4 MAC layer to send and receive packets. It provides transparent and technology-independent access to the medium.
The 802.15.4 MAC and netif are not part of this document, but they are affected by this work, thus, they are mentioned to give an outlook for upcoming efforts on the lower network stack.
The following picture compares the current RIOT lower network stack
architecture (left) with the approach described in this document (right). As
can be seen, the new approach adds IEEE802.15.4 specific APIs and layers
between the lower layer network stack interface (GNRC Netif) and the hardware
dependent device driver. In contrast, the netdev
based solution misses a
specific Radio HAL which prevents to run a hardware-agnostic MAC on top.
OLD | NEW
=== | ===
|
+---------------------+ | +---------------------+ +---------------------+
| | | | | | |
| GNRC Network Stack | | | GNRC Network Stack | | |
| | | | | | |
+---------------------+ | +---------------------+ | |
^ | ^ | |
| | | | |
gnrc_netapi | gnrc_netapi | OpenThread, OpenWSN |
| | | | |
v | v | |
+---------------------+ | +---------------------+ | |
| | | | | | |
| GNRC Netif | | | GNRC Netif | | |
| | | | | | |
+---------------------+ | +---------------------+ +---------------------+
^ | ^ ^
| | | |
gnrc_netif_ops_t | gnrc_netif_ops_t |
| | | |
v | v |
+---------------------+ | +---------------------+ |
| | | | | |
|gnrc_netif_ieee802154| | |gnrc_netif_ieee802154| |
| | | | | |
+---------------------+ | +---------------------+ |
^ | ^ |
| | | |
| | 802.15.4 MAC API Radio HAL API
| | | |
| | v |
| | +---------------------+ |
| | | | |
netdev_driver_t | | 802.15.4 MAC | |
| | | | |
| | +---------------------+ |
| | ^ |
| | | |
| | Radio HAL API ----------------+
| | | |
v | v v
+---------------------+ | +---------------------+-------------------------+
| | | | | | |
| netdev | Device | | | 802.15.4 Radio HAL | |
| | Driver | | | | Device Driver |
|----------+ | | +---------------------+ |
| | | | |
+---------------------+ | +-----------------------------------------------+
4. Architecture
+-----------------------------------------------------------------------------+
| |
| Upper layer |
| |
+-----------------------------------------------------------------------------+
| ^
| |
| |
| |
Radio Ops Event Notification +----------------------------+
| | IRQ Handler | |
| | +----------------------| Bottom-Half processor |
| | | | |
| | | +----------------------------+
| | | ^
| | | |
v | v IRQ
+-----------------------------+ |
| 802.15.4 Radio HAL | HW independent |
|-----------------------------|-------------------------------|----------------
| | HW dependent |
| | |
| Device Driver | |
| |-------------------------------+
| |
+-----------------------------+
As shown in the above figure, the IEEE802.15.4 Radio HAL is a central component that provides any upper layer a technology-dependent and unified access to the device driver, by implementing the Radio HAL API.
The HAL uses an Event Notification mechanism to inform the upper layer about
radio events (IEEE802154_RADIO_CONFIRM_TX_DONE
,
IEEE802154_RADIO_INDICATION_RX_DONE
, IEEE802154_RADIO_CONFIRM_CCA
, etc).
This mechanism can either run in interrupt context or thread context, if the
device is not able to resolve events during ISR (e.g SPI devices). For the
latter, the radio HAL requires an upper layer to take over the Bottom-Half
processing which means, offloading the ISR to thread context.
4.1 Upper Layer
Upper layers are users that requires direct access to the primitive operations of a radio and its hardware acceleration features, if available.
Examples for Upper Layers:
- A MAC layer can use the Radio HAL to implement parts of a PHY layer (data communication, set/get parameters, perform CCA, etc.) .
- A network stack that requires low level access to the radio (OpenWSN, OpenThread) can use the Radio HAL to implement the integration code.
- A developer who implements a simple application to send and receive data between 802.15.4 radios (relying on hardware accelerated MAC features, if available).
The upper layer accesses the radio using the Radio HAL API. Events that are triggered by the device (packet received, transmission finished) are indicated by the event notification mechanism, described below.
4.2 Bottom-Half Processor
The Bottom-Half (BH) processor is a component to offload the IRQ processing to thread context. The component is required for radios that cannot resolve radio events during ISR (SPI devices).
The component registers an IRQ handler during initialization which is executed when the device triggers and interrupt. This handler uses internal mechanisms to call the Radio API IRQ handler from a safe context. The IRQ handler may run on a higher priority context. Although the API implementation SHOULD NOT implement reentrancy, it MUST handle concurrent calls between the IRQ handler and API functions.
The BH processor can be implemented dependent or independent of the network stack. A network stack independent solution is preferred in order to reuse functionality between different network stacks.
The term "Bottom Half" was originally introduced by the Linux kernel. See Top and Bottom Halves
4.3 Radio HAL
The Radio HAL is defined by the Radio HAL API which consists of three main components: Radio Operations, Event Notification, and the Device Specific IEEE802.15.4 HAL implementation.
The Radio HAL Implementation provides a set of functionalities to control the operation of the device, to process the IRQ handler and to receive event notifications from the device.
4.3.1 Radio Operations
The Radio Operations (radio_ops
) interface exposes operations that are common
to control 802.15.4 devices and to request their hardware capabilities
information (i.e., MAC acceleration hardware)
The interface defines a collection of mandatory functions:
- Set the transceiver state
- Set the PHY configuration (channel, tx power, etc)
- Load and transmit a frame
- Get device capabilities
The interface provides a collection of optional functions that may or may not be implemented, dependent on the hardware acceleration features of a device. These functions include:
- Read the number of retransmission attempts.
- Set address filter addresses (extended, short, PAN ID).
- Set CSMA-CA backoff parameters.
All radio_ops
functions are non-blocking and some of them follow a
Request/Confirm scheme which means, the end of a request is indicated by a
confirmation function. The confirmation function may be polled. In such case,
the function uses standard error codes to indicate the status (success, error
or request has not finished).
The full list of functions can be found in the Interface Definition section.
4.3.2 Event Notification
The Radio HAL provides an Event Notification mechanism to inform the upper layer about an event (a packet was received, a transmission finished, etc).
The upper layer can subscribe to these events to perform different actions. As an example, a MAC layer would subscribe to the RX done event to allocate the received packet. The TX done event is commonly used to release resources or update statistics.
As described before, the Event Notification mechanism can be called during ISR
or thread context (BH processor). Thus, this must be taken into consideration
for the implementation of the Event Notification callback (e.g the
IEEE802154_RADIO_INDICATION_RX_DONE
event might post an event to an event
queue in order to fetch the packet).
The full list of events and implications are defined in the Interface Definition section.
4.3.3 Device Driver
The Device Driver implements the hardware-dependent part of the IEEE802.15.4
Radio HAL by wrapping the radio_ops
interface around the device specific
code, which grants access to all device operations.
The Device Driver additionally provides a mechanism to expose the ISR of radios that require the Bottom-Half processor.
The function set of the Device Driver can include device specific features that are not exposed by the Radio HAL API (e.g., Smart Listening with AT86RF2xx radios).
5 Implementation Details
5.1 Initialization of device drivers
In order to implement the 802.15.4 abstraction on top of a device driver, it is required an initialization procedure that performs the following tasks:
- Set up IRQ callback
- Reset the device
- Confirm connectivity and perform self tests
- Bring device into a low power state
- Set up IRQs and disable them to use less power.
The radio_ops
interface provides an "on" function that turns on the device
and enables interrupts. It is expected that the upper layer will call this
function to enable the radio device, if the initialization procedure succeeded.
5.2 Abstract State Machine
The Radio HAL defines an Abstract State Machine. In order to ensure a uniform behavior in all devices, all Radio HAL device drivers should be implemented against this. Transient states (e.g pending requests) are not included in this diagram. However, the upper layer MUST NOT trigger another request if there is already a pending one.
+---------+
| |
| OFF |<------ Any state
| | OFF
+---------+
|
ON |
|
v
+---------+
+--------| |--------+
| | TRX_OFF |<----+ |
| +----->| | | |
| | +---------+ | |
SET_TRX_STATE | | | | SET_TRX_STATE
| | | |
v | | v
+---------+ +---------+
| |------------->| |
| IDLE | | RX |
| |<-------------| |
+---------+ +---------+
SET_TRX_STATE
5.2.1 State specification
A specification for each state is described in the following items.
-
OFF: If radio initialization succeeds, the Abstract State Machine begins in
OFF
state. During this state the device consumes the least power and all hardware components (transceiver, crypto acceleration) are disabled. -
TRX OFF: During this state the device is on but the transceiver is off (PLL not locked). The power consumption is higher than the
OFF
state but the device is able to operate the transceiver and other hardware components (e.g crypto accelerator). -
IDLE: This state is device specific and represents a state where the device is ready to transmit, fetch a received frame, change the Physical Information Base or perform Stand-Alone CCA.
-
RX ON: During RX ON state the radio is able to detect Start Frame Delimiter (SFD) and thus, receive frames.
5.3 Prepare and Transmit
The Radio HAL doesn't define an explicit send function. Unlike the netdev
approach, it bases on separation of the send procedure into frame loading
and triggering the transmissions start.
Although it is possible to load and start using the netdev
interface with the
NETOPT_PRELOADING
option, the Radio HAL approach is easier and more
lightweight to implement since it doesn't require internal state variables.
Separated load and start is required for MAC layers with timing constraints (E.g. TSCH mode of 802.15.4 MAC).
In the rare case a radio device doesn't support loading the frame buffer without triggering a transmission, it is still possible to implement the load and transmit pattern using an internal buffer. However, this case is very unlikely because such a device could not meet 802.15.4 timing requirements.
It is expected that a higher layer "send" function is defined for convenience which handles both loading and frame sending. Typically, this would be a 802.15.4 MAC implementation which preloads the devices buffer once accessible, and triggers a send operation at a scheduled time slot. Alternatively, this could be a helper function for non MAC users.
5.4 TX and RX Information
Sometimes upper layers require information associated to the transmission or reception of a packet. The TSCH mode of the 802.15.4 MAC may require LQI and RSSI data from a received packet to schedule new cells. The 802.15.4 MAC may also require the information associated to the frame retransmission component (frame pending bit, number of retransmission, status) if the hardware provides support for hardware retransmissions.
The 802.15.4 Radio HAL API provides functions to retrieve this data. Note that retrieving this information is optional in cases where the RX information is not needed or when the device doesn't support frame retransmissions.
6 802.15.4 Radio HAL Interface definition
6.1 Radio Operations
The Radio Ops interface is implemented using function pointers.
These functions should be implemented with device specific validations only. Parameters that are not device specific (valid channel settings, address lengths, etc) should be checked by higher layers in order to avoids redundancy.
Note that the Radio Ops interface only implements a few get functions. The reason behind this is the fact most members of the PHY and MAC Information Base (such as address, TX power, channel number) are already stored in RAM.
The full documentation of Radio Ops functions is available in the Appendix A.
6.1.1 Summary of Radio Ops
The following table summarizes the Radio Ops and the state in which the Ops can
be invoked (marked with X
).
- Send/Receive
+---------------------------------+
|`OFF` | `TRX_OFF` | `IDLE` | `RX`|
+------------------------------------------------------------+
| `write` | _ | X | X | _ |
| `len` | _ | X | X | _ |
| `read` | _ | X | X | _ |
| `*_op(*_TRANSMIT)` | _ | _ | X | _ |
+------------------------------------------------------------+
- CCA related
+---------------------------------+
|`OFF` | `TRX_OFF` | `IDLE` | `RX`|
+------------------------------------------------------------+
| `set_cca_threshold` | [ ] | [X] | [X] | [X]|
| `set_cca_mode` | [ ] | [X] | [X] | [X]|
| `*_op(*_CCA)` | [ ] | [ ] | [X] | [ ]|
+------------------------------------------------------------+
- PIB/MIB related
+---------------------------------+
|`OFF` | `TRX_OFF` | `IDLE` | `RX`|
+------------------------------------------------------------+
| `config_phy` | [ ] | [X] | [X] | [ ]|
| `set_frame_retrans` | [ ] | [X] | [X] | [X]|
| `set_csma_params` | [ ] | [X] | [X] | [X]|
| `set_frame_filter_mode` | [ ] | [X] | [X] | [X]|
| `config_addr_filter` | [ ] | [X] | [X] | [X]|
| `config_src_addr_match` | [ ] | [X] | [X] | [X]|
+------------------------------------------------------------+
- Device State Management
+---------------------------------+
|`OFF` | `TRX_OFF` | `IDLE` | `RX`|
+------------------------------------------------------------+
| `*_op(*_SET_{IDLE,RX})` | [ ] | [X] | [X] | [X]|
| `*_on` | [X] | [ ] | [ ] | [ ]|
| `off` | [X] | [X] | [X] | [X]|
+------------------------------------------------------------+
6.2 Event Notification
The Event Notification mechanism is implemented with a function callback. The callback function is supposed to be implemented by the upper layer.
The events follow the naming convention of the IEEE Services Access Points (SAP). This means, events that are a triggered as a result of a Request are prefixed with "CONFIRM". All the other events are prefixed with "INDICATION".
The callback signature, the events and their expected behavior are documented in the Appendix A.
MAC specific events such as TX done with frame pending, CSMA-CA medium busy or exceeded number of retransmissions are not explicitly reported because they can be extracted after the TX done event using the Radio HAL API.
Some radio devices support events such as ACK Timeout, CSMA Backoff timeout or PLL lock. Such events are out of the scope of this document. However, these may be added and implemented at any time if required by upper layers.
The following table summarizes the events, whether an event is mandatory, the states which may generate the event notification and special handling. Although mandatory events may be ignored or disabled by the upper layer, all Radio HAL implementations must generate at least the mandatory events. The presence of optional events MUST be indicated using Radio Caps (see Section 6.3).
Event | Mandatory | Trig. state |
+-------------------------------------------+-----------+-------------+
| IEEE802154_RADIO_INDICATION_RX_START | [ ] | RX |
| IEEE802154_RADIO_INDICATION_RX_DONE [1] | [X] | RX |
| IEEE802154_RADIO_INDICATION_CRC_ERROR [2] | [ ] | RX |
| IEEE802154_RADIO_INDICATION_TX_START | [ ] | IDLE |
| IEEE802154_RADIO_CONFIRM_TX_DONE [3] | [X] | IDLE |
| IEEE802154_RADIO_CONFIRM_CCA [4] | [ ] | IDLE |
+-------------------------------------------+-----------+-------------+
[1]: The upper layer MUST set the Abstract State Machine state to `IDLE` or
`TRX_OFF` before calling `read` or `len`.
[2]: Should be treated as the `IEEE802154_RADIO_INDICATION_RX_DONE` event. Use
the `read` function to drop the frame.
[3]: On occurrence, the upper layer MUST call
`confirm_op(IEEE802154_RADIO_CONFIRM_TX_DONE)` to finish the transmission. The
Abstract State Machine stays in IDLE.
[4]: On occurrence, the upper layer MUST call
`confirm_op(IEEE802154_RADIO_CONFIRM_CCA` to finish the CCA procedure and fetch
the channel state. The Abstract State Machine stays in IDLE, ready to transmit
the next frame.
6.3 Radio Caps
The Radio HAL implementation exposes a set of capabilities (Caps) in order to
indicate the presence of a specific hardware feature. The Caps are encoded
using bit flags. The Radio HAL header defines a set of ieee802154_radio_has_*
functions that check whether the radio supports a capability.
See Appendix A for a full list of capabilities.
A Radio HAL implementation MUST indicate all capabilities supported by the device and driver implementation.
7 Future Proof Considerations
The Radio HAL is designed to be agnostic to different versions of the IEEE802.15.4 standard. A single radio device typically implements hardware acceleration for only one standard, whereas different standards are not always compatible. As an example, IEEE802.15.4--2006 devices do not support Enhanced Acknowledgement packets which are required by the TSCH layer of IEEE802.15.4--2012. For compatibility, a software MAC can provide such functionality. The Radio HAL adapts considerations to enable different versions of the IEEE802.15.4 MAC on top of the abstraction layer.
Transmission Modes
The Radio HAL interface defines three transmission modes to allow sending frames using (i) CSMA-CA, (ii) CCA, or (iii) directly without any contention mechanism. In that way, a MAC layer can easily send data frames benefiting from hardware accelerated CSMA-CA or Beacons that have to meet timing constraints and thus, require a direct send function.
A HAL implementation can provide several transmit modes, but it MUST implement at least one. It is recommended that the implementation provides modes that exploit the internal devices capabilities. Implementing a direct mode is desired for software MAC layers on top.
PHY Definition
PHY definitions are specific to a IEEE802.15.4 version. As an example, older
standards define PHY channels with a channel number
. In modern standards,
channels are represented using a (channel number
, channel page
, channel modulation
) tuple. The config_phy
function is called with a pointer to a
ieee802154_phy_conf_t
structure which describes the PHY configuration. In
order to support newer versions, this structure can be extended without changing
the Radio HAL API.
Future Radio Operations
The Radio Operations interface radio_ops
can be extended to support
functionalities of newer standards. As an example, most SubGHz radios support a
Listen Before Talk feature that can be implemented as a new and optional
operation.
8 Acknowledgements
Thanks to Peter Kietzmann, Benjamin Valentin, Marian Buschsieweke, Leandro Lanzieri and Martine Lenders for their reviews, comments and suggestions.
9 References
10 Revision
- Rev0: initial document
11 Contact
The author of this memo can be contacted via email at jose.alamos@haw-hamburg.de
Appendix A: Radio HAL header file (2023-02)
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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_ieee802154_hal IEEE802.15.4 Radio Hardware Abstraction Layer
* @ingroup drivers
* @experimental This API is experimental and in an early state - expect
* changes!
* @brief This is a Hardware Abstraction Layer for IEEE802.15.4 compatible
* radios.
* @{
*
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
*/
#ifndef NET_IEEE802154_RADIO_H
#define NET_IEEE802154_RADIO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "iolist.h"
#include "sys/uio.h"
#include "bitarithm.h"
#include "byteorder.h"
#include "net/eui64.h"
#include "net/ieee802154.h"
#include "errno.h"
/**
* @brief Forward declaration of the radio ops structure.
*/
typedef struct ieee802154_radio_ops ieee802154_radio_ops_t;
/**
* @brief IEEE802.15.4 Radio capabilities
*
* These flags represent the hardware capabilities of a given device.
*/
typedef enum {
/**
* @brief the device supports frame retransmissions with CSMA-CA
*
* The device supports sending with CSMA-CA and retransmissions. If the
* CSMA-CA fails, the device reports a @ref TX_STATUS_MEDIUM_BUSY when
* calling @ref ieee802154_radio_confirm_transmit. In case CSMA-CA
* succeeds and the ACK frame is expected, the
* device reports a @ref TX_STATUS_SUCCESS if the ACK frame is received
* during any retransmission attempt. Otherwise, it reports a @ref
* TX_STATUS_NO_ACK
*
* ACK frames are not indicated to the upper layer.
*
* @note it's implicit that a radio supports @ref
* IEEE802154_CAP_AUTO_CSMA if this cap is available
*/
IEEE802154_CAP_FRAME_RETRANS = BIT0,
/**
* @brief the device supports Auto CSMA-CA
*
* The device supports performing CSMA-CA before transmitting a frame. If
* CSMA-CA procedure succeeds, the device sends the frame and reports a
* @ref TX_STATUS_SUCCESS when calling @ref
* ieee802154_radio_confirm_transmit. If it fails, the device reports
* @ref TX_STATUS_MEDIUM_BUSY.
*/
IEEE802154_CAP_AUTO_CSMA = BIT1,
/**
* @brief the device support ACK timeout interrupt
*
* The device will automatically attempt to receive and handle the ACK
* frame if expected.
* If the ACK frame is not received, the device reports @ref
* TX_STATUS_NO_ACK when calling @ref ieee802154_radio_confirm_transmit.
* Otherwise, it reports @ref TX_STATUS_SUCCESS.
*
* The ACK frame is not indicated to the upper layer.
*/
IEEE802154_CAP_IRQ_ACK_TIMEOUT = BIT2,
/**
* @brief the device supports the IEEE802.15.4 2.4 GHz band
*
* It's assumed that @ref IEEE802154_CAP_IRQ_TX_DONE is present.
*/
IEEE802154_CAP_24_GHZ = BIT3,
/**
* @brief the device support the IEEE802.15.4 Sub GHz band
*/
IEEE802154_CAP_SUB_GHZ = BIT4,
/**
* @brief the device reports reception off frames with invalid CRC.
*/
IEEE802154_CAP_IRQ_CRC_ERROR = BIT5,
/**
* @brief the device reports when the transmission is done
*/
IEEE802154_CAP_IRQ_TX_DONE = BIT6,
/**
* @brief the device reports the start of a frame (SFD) when received.
*/
IEEE802154_CAP_IRQ_RX_START = BIT7,
/**
* @brief the device reports the start of a frame (SFD) was sent.
*/
IEEE802154_CAP_IRQ_TX_START = BIT8,
/**
* @brief the device reports the end of the CCA procedure
*/
IEEE802154_CAP_IRQ_CCA_DONE = BIT9,
/**
* @brief the device provides the number of retransmissions
*
* It's assumed that @ref IEEE802154_CAP_FRAME_RETRANS is present.
*/
IEEE802154_CAP_FRAME_RETRANS_INFO = BIT10,
/**
* @brief the device retains all register values when off.
*/
IEEE802154_CAP_REG_RETENTION = BIT11,
/**
* @brief Binary Phase Shift Keying PHY mode
*/
IEEE802154_CAP_PHY_BPSK = BIT12,
/**
* @brief Amplitude-Shift Keying PHY mode
*/
IEEE802154_CAP_PHY_ASK = BIT13,
/**
* @brief Offset Quadrature Phase-Shift Keying
*/
IEEE802154_CAP_PHY_OQPSK = BIT14,
/**
* @brief Multi-Rate Offset Quadrature Phase-Shift Keying PHY mode
*/
IEEE802154_CAP_PHY_MR_OQPSK = BIT15,
/**
* @brief Multi-Rate Orthogonal Frequency-Division Multiplexing PHY mode
*/
IEEE802154_CAP_PHY_MR_OFDM = BIT16,
/**
* @brief Multi-Rate Frequency Shift Keying PHY mode
*/
IEEE802154_CAP_PHY_MR_FSK = BIT17,
/**
* @brief the device supports source address match table.
*
* A Source Address Match table contains source addresses with pending
* data. When a coordinator device receives an IEEE 802.15.4 Data
* Request command from a child node, the Frame Pending bit of the ACK is
* set if the source address matches one from the table.
*/
IEEE802154_CAP_SRC_ADDR_MATCH = BIT18,
} ieee802154_rf_caps_t;
/**
* @brief Bit-mask for PHY modes capabilities.
*/
#define IEEE802154_RF_CAPS_PHY_MASK \
(IEEE802154_CAP_PHY_BPSK \
| IEEE802154_CAP_PHY_ASK \
| IEEE802154_CAP_PHY_OQPSK \
| IEEE802154_CAP_PHY_MR_OQPSK \
| IEEE802154_CAP_PHY_MR_OFDM \
| IEEE802154_CAP_PHY_MR_FSK) \
/**
* @brief Transmission status
*/
typedef enum {
/**
* @brief the transceiver successfully sent a frame.
*
* Depending of the type of transmissions and available caps, this could
* mean one of the following:
*
* If the device supports @ref IEEE802154_CAP_FRAME_RETRANS or
* @ref IEEE802154_CAP_IRQ_ACK_TIMEOUT this means either:
* - The frame was sent without ACK Req bit
* - The frame was sent with the ACK Req bit and a valid ACK was received.
*
* Otherwise, this notifies that a frame was sent.
*/
TX_STATUS_SUCCESS,
/**
* @brief the transceiver received a valid ACK with the frame pending bit
*
* This status is present only if the device supports @ref
* IEEE802154_CAP_FRAME_RETRANS or @ref IEEE802154_CAP_IRQ_ACK_TIMEOUT.
*/
TX_STATUS_FRAME_PENDING,
/**
* @brief the transceiver ran out of retransmission
*
* This status is present only if the device supports @ref
* IEEE802154_CAP_FRAME_RETRANS or @ref IEEE802154_CAP_IRQ_ACK_TIMEOUT.
*/
TX_STATUS_NO_ACK,
/**
* @brief the CSMA-CA algorithm or CCA failed to measure a clear channel
*/
TX_STATUS_MEDIUM_BUSY,
} ieee802154_tx_status_t;
/**
* @brief IEEE802.15.4 Radio HAL events
*
* To follow the IEEE802.15.4 convention, an event that responds to a Request
* is a confirmation (Confirm). Otherwise an Indication.
*/
typedef enum {
/**
* @brief the transceiver detected a valid SFD
*
* This event is present if radio has @ref IEEE802154_CAP_IRQ_RX_START cap.
*/
IEEE802154_RADIO_INDICATION_RX_START,
/**
* @brief the transceiver received a frame with an invalid crc.
*
* @note some radios won't flush the framebuffer on reception of a frame
* with invalid CRC. Therefore it's required to call @ref
* ieee802154_radio_read.
*
* @note since the behavior of radios after frame reception is undefined,
* the upper layer should set the transceiver state to IDLE as soon as
* possible before calling @ref ieee802154_radio_read
*/
IEEE802154_RADIO_INDICATION_CRC_ERROR,
/**
* @brief the transceiver sent out a valid SFD
*
* This event is present if radio has @ref IEEE802154_CAP_IRQ_TX_START cap.
*
* @note The SFD of an outgoing ACK (AUTOACK) should not be indicated
*/
IEEE802154_RADIO_INDICATION_TX_START,
/**
* @brief the transceiver received a frame and lies in the
* internal framebuffer.
*
* This indication should be generated only if CRC is valid and the frame
* passes the address matching filter (this includes ACK and Beacon frames).
* The latter only applies if the radio is not in promiscuous mode.
*
* The transceiver or driver MUST handle the ACK reply if the Ack Request
* bit is set in the received frame and promiscuous mode is disabled.
*
* The transceiver might be in a "FB Lock" state where no more frames are
* received. This is done in order to avoid overwriting the Frame Buffer
* with new frame arrivals. In order to leave this state, the upper layer
* must call @ref ieee802154_radio_read
*
* @note since the behavior of radios after frame reception is undefined,
* the upper layer should set the transceiver state to IDLE as soon as
* possible before calling @ref ieee802154_radio_read
*/
IEEE802154_RADIO_INDICATION_RX_DONE,
/**
* @brief the transceiver either finished sending a frame, the retransmission
* procedure or the channel activity detection prior transmission.
*
* This event is present if radio has @ref IEEE802154_CAP_IRQ_TX_DONE cap.
* The upper layer should immediately call @ref
* ieee802154_radio_confirm_transmit when on this event.
*/
IEEE802154_RADIO_CONFIRM_TX_DONE,
/**
* @brief the CCA procedure finished
*
* This event is present if radio has @ref IEEE802154_CAP_IRQ_CCA_DONE.
*/
IEEE802154_RADIO_CONFIRM_CCA,
} ieee802154_trx_ev_t;
/**
* @brief Source Address Match commands.
*/
typedef enum {
/**
* @brief Enable or disable source address match.
*
* Enabling it sets the frame pending to all ACK frames in
* response to a Data Request command (if the radio doesn't
* support Source Address Matching) or to a specific address
* in the Source Address Matching table
*/
IEEE802154_SRC_MATCH_EN,
/**
* @brief Add a short address to entry.
*
* This command should only be implemented if @ref IEEE802154_CAP_SRC_ADDR_MATCH
* is available.
*/
IEEE802154_SRC_MATCH_SHORT_ADD,
/**
* @brief Clear short address from entry.
* This command should only be implemented if @ref IEEE802154_CAP_SRC_ADDR_MATCH
* is available.
*/
IEEE802154_SRC_MATCH_SHORT_CLEAR,
/**
* @brief Add a extended address to entry.
* This command should only be implemented if @ref IEEE802154_CAP_SRC_ADDR_MATCH
* is available.
*/
IEEE802154_SRC_MATCH_EXT_ADD,
/**
* @brief Clear extended address from entry.
*
* This command should only be implemented if @ref IEEE802154_CAP_SRC_ADDR_MATCH
* is available.
*/
IEEE802154_SRC_MATCH_EXT_CLEAR,
} ieee802154_src_match_t;
/**
* @brief Address filter command
*/
typedef enum {
IEEE802154_AF_SHORT_ADDR, /**< Set short IEEE 802.15.4 address (network_uint16_t) */
IEEE802154_AF_EXT_ADDR, /**< Set extended IEEE 802.15.4 address (eui64_t) */
IEEE802154_AF_PANID, /**< Set PAN ID (uint16_t) */
IEEE802154_AF_PAN_COORD, /**< Set device as PAN coordinator (bool) */
} ieee802154_af_cmd_t;
/**
* @brief Frame Filter mode
*/
typedef enum {
/**
* @brief accept all valid frames that match address filter configuration
*/
IEEE802154_FILTER_ACCEPT,
/**
* @brief accept only ACK frames
*
* @note This mode should only be implemented if the transceiver doesn't
* handle ACK frame reception (when @ref IEEE802154_CAP_FRAME_RETRANS and
* @ref IEEE802154_CAP_IRQ_ACK_TIMEOUT are not present).
*/
IEEE802154_FILTER_ACK_ONLY,
/**
* @brief accept all valid frames
*
* @note This mode is optional
*/
IEEE802154_FILTER_PROMISC,
/**
* @brief accept all frames, regardless of FCS
*
* @note This mode is optional
*/
IEEE802154_FILTER_SNIFFER,
} ieee802154_filter_mode_t;
/**
* @brief CSMA-CA exponential backoff parameters.
*/
typedef struct {
uint8_t min; /**< minimum value of the exponential backoff */
uint8_t max; /**< maximum value of the exponential backoff */
} ieee802154_csma_be_t;
/**
* @brief RX information associated to a frame
*/
typedef struct {
/**
* @brief RSSI of the received frame.
*
* The RSSI is a measure of the RF power in dBm for the received frame.
* The minimum and maximum values are 0 (-174 dBm) and 254 (80 dBm).
*/
uint8_t rssi;
uint8_t lqi; /**< LQI of the received frame */
} ieee802154_rx_info_t;
/**
* @brief TX information of the last transmitted frame.
*/
typedef struct {
ieee802154_tx_status_t status; /**< status of the last transmission */
int8_t retrans; /**< number of frame retransmissions of the last TX */
} ieee802154_tx_info_t;
/**
* @brief Forward declaration of the IEEE802.15.4 device descriptor
*/
typedef struct ieee802154_dev ieee802154_dev_t;
/**
* @brief Prototype of the IEEE802.15.4 device event callback
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] status the status
*/
typedef void (*ieee802154_cb_t)(ieee802154_dev_t *dev,
ieee802154_trx_ev_t status);
/**
* @brief the IEEE802.15.4 device descriptor
*/
struct ieee802154_dev {
/**
* @brief pointer to the operations of the device
*/
const ieee802154_radio_ops_t *driver;
/**
* @brief pointer to the private descriptor of the device
*/
void *priv;
/**
* @brief the event callback of the device
*/
ieee802154_cb_t cb;
};
/**
* @brief IEEE802.15.4 CCA modes
*/
typedef enum {
/**
* @brief CCA using first mode (energy detection)
*/
IEEE802154_CCA_MODE_ED_THRESHOLD,
/**
* @brief CCA using second mode (carrier sensing)
*/
IEEE802154_CCA_MODE_CARRIER_SENSING,
/**
* @brief CCA using third mode (energy detection AND carrier sensing)
*/
IEEE802154_CCA_MODE_ED_THRESH_AND_CS,
/**
* @brief CCA using third mode (energy detection OR carrier sensing)
*/
IEEE802154_CCA_MODE_ED_THRESH_OR_CS,
} ieee802154_cca_mode_t;
/**
* @brief Holder of the PHY configuration
*/
typedef struct {
ieee802154_phy_mode_t phy_mode; /**< IEEE802.15.4 PHY mode */
uint16_t channel; /**< IEEE802.15.4 channel number */
uint8_t page; /**< IEEE802.15.4 channel page */
int8_t pow; /**< TX power in dBm */
} ieee802154_phy_conf_t;
/**
* @brief IEEE 802.15.4 radio operations
*/
typedef enum {
/**
* @brief Transmission of a preloaded frame.
*/
IEEE802154_HAL_OP_TRANSMIT,
/**
* @brief Set the transceiver state to RX.
*/
IEEE802154_HAL_OP_SET_RX,
/**
* @brief Set the transceiver state to IDLE (RX off).
*/
IEEE802154_HAL_OP_SET_IDLE,
/**
* @brief Request Clear Channel Assessment
*/
IEEE802154_HAL_OP_CCA,
/* add more as needed (e.g Energy Scanning, transmit slotted ACK) */
} ieee802154_hal_op_t;
/**
* @brief Radio ops struct declaration
*/
struct ieee802154_radio_ops {
/**
* @brief Radio device capabilities
*
* This field contains bitflags of supported capabilities
* (@ref ieee802154_rf_caps_t) by the device.
*/
const uint32_t caps;
/**
* @brief Write a frame into the framebuffer.
*
* This function shouldn't do any checks, so the frame MUST be valid. The
* previous content of the framebuffer is replaced by @p psdu.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] psdu PSDU frame to be sent
*
* @return 0 on success
* @return negative errno on error
*/
int (*write)(ieee802154_dev_t *dev, const iolist_t *psdu);
/**
* @brief Get the length of the received PSDU frame.
*
* @pre the device is on
* @pre the radio already received a frame (e.g
* @ref ieee802154_dev::cb with @ref IEEE802154_RADIO_INDICATION_RX_DONE).
*
* @post the frame buffer is still protected against new frame arrivals.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return length of the frame
*/
int (*len)(ieee802154_dev_t *dev);
/**
* @brief Read a frame from the internal framebuffer
*
* This function reads the received frame from the internal framebuffer.
* It should try to copy the received PSDU frame into @p buf. The FCS
* field will **not** be copied and its size **not** be taken into account
* for the return value. If the radio provides any kind of framebuffer
* protection, this function should release it.
*
* @post Don't call this function if there was no reception event
* (either @ref IEEE802154_RADIO_INDICATION_RX_DONE or @ref
* IEEE802154_RADIO_INDICATION_CRC_ERROR). Otherwise there's risk of RX
* underflow.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[out] buf buffer to write the received PSDU frame into.
* @param[in] size size of @p buf
* @param[in] info information of the received frame (LQI, RSSI). Can be
* NULL if this information is not needed.
*
* @return number of bytes written in @p buffer (0 if @p buf == NULL)
* @return -ENOBUFS if the frame doesn't fit in @p
*/
int (*read)(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_info_t *info);
/**
* @brief Turn off the device
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* When this function returns, the radio shall be off.
*
* @post the device is off
*
* @return 0 on success
* @return negative errno on error
*/
int (*off)(ieee802154_dev_t *dev);
/**
* @brief Request to turn on the device
*
* @note @ref ieee802154_radio_ops::confirm_on MUST be used to finish the
* procedure.
*
* @pre the init function of the radio succeeded.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return 0 on success
* @return negative errno on error
*/
int (*request_on)(ieee802154_dev_t *dev);
/**
* @brief Confirmation function for @ref ieee802154_radio_ops::request_on.
*
* @pre call to @ref ieee802154_radio_ops::request_on was successful.
*
* @post the transceiver state is IDLE
* During boot or in case the radio doesn't support @ref
* IEEE802154_CAP_REG_RETENTION when @ref off was called, the
* Physical Information Base will be undefined. Thus, take into
* consideration that the following functions should be called right after
* the radio is turned on again:
* - @ref set_cca_threshold
* - @ref set_cca_mode
* - @ref config_phy
* - @ref config_addr_filter
* - @ref set_csma_params
* - @ref set_frame_filter_mode
* - @ref config_src_addr_match
* - @ref set_frame_retrans (if available)
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return 0 if the device is on
* @return -EAGAIN if the device is still busy turning on
* @return negative errno on error
*/
int (*confirm_on)(ieee802154_dev_t *dev);
/**
* @brief Request a radio operation.
*
* This functions is used to request a radio operation. See @ref
* ieee802154_hal_op_t for a list of available operations.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] op operation to be executed
* @param[in] ctx operation specific context
*
* @return status of the request
*
* @retval 0 on success
* @retval negative errno on error
*/
int (*request_op)(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx);
/**
* @brief Confirmation function for @ref ieee802154_radio_ops::request_op
*
* This function must be called to finish a given @ref ieee802154_hal_op_t.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] op operation to be confirmed
* @param[in] ctx operation specific context
*
* @return status of the request
*
* @retval 0 on success
* @retval negative errno on error
*/
int (*confirm_op)(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx);
/**
* @brief Set the threshold for the Energy Detection (first mode of CCA)
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] threshold the threshold in dBm.
*
* @return 0 on success
* @return negative errno on error
*/
int (*set_cca_threshold)(ieee802154_dev_t *dev, int8_t threshold);
/**
* @brief Set CCA mode
*
* All radios MUST at least implement the first CCA mode (ED Threshold).
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] mode the CCA mode
*
* @return 0 on success
* @return -ENOTSUP if the mode is not supported
* @return negative errno on error
*/
int (*set_cca_mode)(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode);
/**
* @brief Set IEEE802.15.4 PHY configuration (channel, TX power)
*
* This function SHOULD NOT validate the PHY configurations unless
* it's specific to the device. The upper layer is responsible of all kind
* of validations.
* In case a configuration is not valid (e.g parameters out of range), this
* function should return -EINVAL
*
* @pre the device is on
* @pre the transceiver state is IDLE.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] conf the PHY configuration
*
* @return 0 on success
* @return -EINVAL if the configuration is not valid for the device.
* @return <0 error, return value is negative errno indicating the cause.
*/
int (*config_phy)(ieee802154_dev_t *dev, const ieee802154_phy_conf_t *conf);
/**
* @brief Set number of frame retransmissions
*
* @pre the device is on
*
* @note this function pointer can be NULL if the device doesn't support
* frame retransmissions
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] retrans the number of retransmissions attempts.
*
* @return 0 on success
* @return negative errno on error
*/
int (*set_frame_retrans)(ieee802154_dev_t *dev, uint8_t retrans);
/**
* @brief Set the CSMA-CA parameters.
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] bd parameters of the exponential backoff. If NULL, the
* parameters are not altered.
* @param[in] retries number of CSMA-CA retries. If @p retries < 0,
* retransmissions with CSMA-CA MUST be disabled.
* If @p retries == 0, the @ref
* ieee802154_radio_request_transmit function is
* equivalent to CCA send.
*
* @return 0 on success
* @return -EINVAL if the settings are not supported.
* @return negative errno on error
*/
int (*set_csma_params)(ieee802154_dev_t *dev, const ieee802154_csma_be_t *bd,
int8_t retries);
/**
* @brief Set the frame filter moder.
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] mode address filter mode
*
* @return 0 on success
* @return negative errno on error
*/
int (*set_frame_filter_mode)(ieee802154_dev_t *dev, ieee802154_filter_mode_t mode);
/**
* @brief Configure the address filter.
*
* This functions is used for configuring the address filter parameters
* required by the IEEE 802.15.4 standard.
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] cmd command for the address filter
* @param[in] value value for @p cmd.
*
* @return 0 on success
* @return negative errno on error
*/
int (*config_addr_filter)(ieee802154_dev_t *dev, ieee802154_af_cmd_t cmd, const void *value);
/**
* @brief Set the source address match configuration.
*
* This function configures the source address match filter in order to set
* the Frame Pending bit in ACK frames accordingly.
* In case the radio doesn't support @ref IEEE802154_CAP_SRC_ADDR_MATCH,
* this functions is used to activate the Frame Pending bit for all ACK
* frames (in order to be compliant with the IEEE 802.15.4 standard).
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] cmd command for the source address match configuration
* @param[in] value value associated to @p cmd.
*
* @return 0 on success
* @return negative errno on error
*/
int (*config_src_addr_match)(ieee802154_dev_t *dev, ieee802154_src_match_t cmd,
const void *value);
};
/**
* @brief Shortcut to @ref ieee802154_radio_ops::write
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] psdu PSDU frame to be sent
*
* @return result of @ref ieee802154_radio_ops::write
*/
static inline int ieee802154_radio_write(ieee802154_dev_t *dev, const iolist_t *psdu)
{
return dev->driver->write(dev, psdu);
}
/**
* @brief Transmit a preloaded frame
*
* This functions calls ieee802154_radio_ops::request_op with @ref
* IEEE802154_HAL_OP_TRANSMIT and NULL context.
*
* @pre The upper layer should have called set the transceiver to IDLE (see
* @ref ieee802154_radio_set_idle) and the frame is already in the framebuffer
* (@ref ieee802154_radio_ops_t::write).
* @pre the device is on
*
* @note @ref ieee802154_radio_confirm_transmit MUST be used to
* finish the transmission.
*
* @return result of @ref ieee802154_radio_request_transmit
*
* @retval 0 on success
* @retval negative errno on error
*/
static inline int ieee802154_radio_request_transmit(ieee802154_dev_t *dev)
{
return dev->driver->request_op(dev, IEEE802154_HAL_OP_TRANSMIT, NULL);
}
/**
* @brief Confirmation function for @ref ieee802154_radio_request_transmit
* This function must be called to finish the transmission procedure and
* get the transmission status. This function should be called on @ref
* IEEE802154_RADIO_CONFIRM_TX_DONE. If no interrupt is available, this
* function can be polled.
*
* This functions calls ieee802154_radio_ops::confirm_op with @ref
* IEEE802154_HAL_OP_TRANSMIT and sets the context to @p info.
*
* @pre the device is on
* @pre call to @ref ieee802154_radio_request_transmit was successful.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[out] info the TX information. Pass NULL
* if the information is not needed. If the radio supports AutoCCA, the
* status should indicate transmission done or channel busy. If the radio
* supports frame retransmissions, the status should indicate if medium
* was busy, no ACK was received or transmission succeeded.
*
* @retval whether the transmission finished or not
*
* @return 0 if the transmission finished
* @return -EAGAIN otherwise
*/
static inline int ieee802154_radio_confirm_transmit(ieee802154_dev_t *dev,
ieee802154_tx_info_t *info)
{
return dev->driver->confirm_op(dev, IEEE802154_HAL_OP_TRANSMIT, info);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::len
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return result of @ref ieee802154_radio_ops::len
*/
static inline int ieee802154_radio_len(ieee802154_dev_t *dev)
{
return dev->driver->len(dev);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::read
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[out] buf buffer to write the received frame into.
* @param[in] size size of @p buf
* @param[in] info information of the received frame (LQI, RSSI). Can be
* NULL if this information is not needed.
*
* @return result of @ref ieee802154_radio_ops::read
*/
static inline int ieee802154_radio_read(ieee802154_dev_t *dev,
void *buf,
size_t size,
ieee802154_rx_info_t *info)
{
return dev->driver->read(dev, buf, size, info);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::set_cca_threshold
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] threshold the threshold in dBm
*
* @return result of @ref ieee802154_radio_ops::set_cca_threshold
*/
static inline int ieee802154_radio_set_cca_threshold(ieee802154_dev_t *dev,
int8_t threshold)
{
return dev->driver->set_cca_threshold(dev, threshold);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::set_cca_mode
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] mode the CCA mode
*
* @return result of @ref ieee802154_radio_ops::set_cca_mode
*/
static inline int ieee802154_radio_set_cca_mode(ieee802154_dev_t *dev,
ieee802154_cca_mode_t mode)
{
return dev->driver->set_cca_mode(dev, mode);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::config_phy
*
* @pre the transceiver state is IDLE.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] conf the PHY configuration
*
* @return result of @ref ieee802154_radio_ops::config_phy
*/
static inline int ieee802154_radio_config_phy(ieee802154_dev_t *dev,
const ieee802154_phy_conf_t *conf)
{
return dev->driver->config_phy(dev, conf);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::config_src_addr_match
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] cmd command for the source address match configuration
* @param[in] value value associated to @p cmd.
*
* @return result of @ref ieee802154_radio_ops::config_src_addr_match
*/
static inline int ieee802154_radio_config_src_address_match(ieee802154_dev_t *dev,
ieee802154_src_match_t cmd,
const void *value)
{
return dev->driver->config_src_addr_match(dev, cmd, value);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::off
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @post the transceiver state is IDLE.
*
* @return result of @ref ieee802154_radio_ops::off
*/
static inline int ieee802154_radio_off(ieee802154_dev_t *dev)
{
return dev->driver->off(dev);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::config_addr_filter
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] cmd command for the address filter
* @param[in] value value for @p cmd.
*
* @return result of @ref ieee802154_radio_ops::config_addr_filter
*/
static inline int ieee802154_radio_config_addr_filter(ieee802154_dev_t *dev,
ieee802154_af_cmd_t cmd,
const void* value)
{
return dev->driver->config_addr_filter(dev, cmd, value);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::set_frame_filter_mode
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] mode frame filter mode
*
* @return result of @ref ieee802154_radio_ops::set_frame_filter_mode
*/
static inline int ieee802154_radio_set_frame_filter_mode(ieee802154_dev_t *dev,
ieee802154_filter_mode_t mode)
{
return dev->driver->set_frame_filter_mode(dev, mode);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::set_frame_retrans
*
* @pre the device is on
* @pre the device supports frame retransmissions
* (@ref ieee802154_radio_has_frame_retrans() == true)
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] retrans the number of retransmissions
*
* @return result of @ref ieee802154_radio_ops::set_frame_retrans
*/
static inline int ieee802154_radio_set_frame_retrans(ieee802154_dev_t *dev,
uint8_t retrans)
{
return dev->driver->set_frame_retrans(dev, retrans);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::set_csma_params
*
* @pre the device is on
* @pre the device supports frame retransmissions
* (@ref ieee802154_radio_has_frame_retrans() == true)
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] bd parameters of the exponential backoff
* @param[in] retries number of CSMA-CA retries. If @p restries < 0,
* retransmissions with CSMA-CA are disabled
*
* @return result of @ref ieee802154_radio_ops::set_csma_params
*/
static inline int ieee802154_radio_set_csma_params(ieee802154_dev_t *dev,
const ieee802154_csma_be_t *bd,
int8_t retries)
{
return dev->driver->set_csma_params(dev, bd, retries);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::request_on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return result of @ref ieee802154_radio_ops::request_on
*/
static inline int ieee802154_radio_request_on(ieee802154_dev_t *dev)
{
return dev->driver->request_on(dev);
}
/**
* @brief Shortcut to @ref ieee802154_radio_ops::confirm_on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return result of @ref ieee802154_radio_ops::confirm_on
*/
static inline int ieee802154_radio_confirm_on(ieee802154_dev_t *dev)
{
return dev->driver->confirm_on(dev);
}
/**
* @brief Request the transceiver state to IDLE.
*
* During IDLE, the radio won't be able to receive frames but it's still
* responsive to other HAL functions.
*
* This functions calls ieee802154_radio_ops::request_op with @ref
* IEEE802154_HAL_OP_SET_IDLE and sets the context to @p force
*
* @pre the device is on
*
* @note @ref ieee802154_radio_confirm_set_idle MUST be used to
* finish the state transition.
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] force whether the state transition should be forced or not. If
* forced, the transceiver aborts any ongoing operation.
*
* @return status of the request
*
* @retval 0 on success
* @retval negative errno on error
*/
static inline int ieee802154_radio_request_set_idle(ieee802154_dev_t *dev, bool force)
{
return dev->driver->request_op(dev, IEEE802154_HAL_OP_SET_IDLE, &force);
}
/**
* @brief Confirmation function for @ref ieee802154_radio_request_set_idle
*
* @pre call to @ref ieee802154_radio_request_set_idle was successful.
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return whether the state transition finished or not
*
* @return 0 if the transition finished
* @return -EAGAIN otherwise.
*/
static inline int ieee802154_radio_confirm_set_idle(ieee802154_dev_t *dev)
{
return dev->driver->confirm_op(dev, IEEE802154_HAL_OP_SET_IDLE, NULL);
}
/**
* @brief Request the transceiver state to RX.
*
* During RX, the radio will listen to incoming frames
*
* This functions calls ieee802154_radio_ops::request_op with @ref
* IEEE802154_HAL_OP_SET_RX and NULL context.
*
* @pre the device is on
*
* @note @ref ieee802154_radio_confirm_set_rx MUST be used to
* finish the state transition.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return status of the request
*
* @retval 0 on success
* @retval negative errno on error
*/
static inline int ieee802154_radio_request_set_rx(ieee802154_dev_t *dev)
{
return dev->driver->request_op(dev, IEEE802154_HAL_OP_SET_RX, NULL);
}
/**
* @brief Confirmation function for @ref ieee802154_radio_request_set_rx
*
* @pre call to @ref ieee802154_radio_request_set_rx was successful.
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return whether the state transition finished or not
*
* @return 0 if the transition finished
* @return -EAGAIN otherwise.
*/
static inline int ieee802154_radio_confirm_set_rx(ieee802154_dev_t *dev)
{
return dev->driver->confirm_op(dev, IEEE802154_HAL_OP_SET_RX, NULL);
}
/**
* @brief Set transceiver state to IDLE (blocking)
*
* This function will internally call @ref ieee802154_radio_request_set_idle
* and poll @ref ieee802154_radio_confirm_set_idle.
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
* @param[in] force whether the state transition should be forced or not. If
* forced, the transceiver aborts any ongoing operation.
*
* @return result of the state transition
*
* @retval 0 on success
* @retval negative errno on error
*/
static inline int ieee802154_radio_set_idle(ieee802154_dev_t *dev, bool force)
{
int res = ieee802154_radio_request_set_idle(dev, force);
if (res < 0) {
return res;
}
while (ieee802154_radio_confirm_set_idle(dev) == -EAGAIN) {}
return 0;
}
/**
* @brief Set transceiver state to RX (blocking)
*
* This function will internally call @ref ieee802154_radio_request_set_rx
* and poll @ref ieee802154_radio_confirm_set_rx.
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return result of the state transition
*
* @retval 0 on success
* @retval negative errno on error
*/
static inline int ieee802154_radio_set_rx(ieee802154_dev_t *dev)
{
int res = ieee802154_radio_request_set_rx(dev);
if (res < 0) {
return res;
}
while (ieee802154_radio_confirm_set_rx(dev) == -EAGAIN) {}
return 0;
}
/**
* @brief Request Stand-Alone Clear Channel Assessment
*
* This functions calls ieee802154_radio_ops::request_op with @ref
* IEEE802154_HAL_OP_CCA and NULL context.
*
* @pre the device is on
*
* @note @ref ieee802154_radio_confirm_cca MUST be used to
* finish the CCA procedure and get the channel status.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return 0 on success
* @return negative errno on error
*/
static inline int ieee802154_radio_request_cca(ieee802154_dev_t *dev)
{
return dev->driver->request_op(dev, IEEE802154_HAL_OP_CCA, NULL);
}
/**
* @brief Shortcut to @ref ieee802154_radio_confirm_cca
*
* This function must be called to finish the CCA procedure. This
* function should be called on @ref IEEE802154_RADIO_CONFIRM_CCA,
* If no interrupt is available, this function can be polled.
*
* This functions calls ieee802154_radio_ops::request_op with @ref
* IEEE802154_HAL_OP_CCA and sets the context to a boolean where the result
* of the CCA should be store. Setting it to true means the channel is clear.
*
* @pre call to @ref ieee802154_radio_request_cca was successful.
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return status of the CCA procedure
*
* @retval positive number if the channel is clear
* @retval 0 if the channel is busy
* @retval -EAGAIN if the CCA procedure hasn't finished.
*/
static inline int ieee802154_radio_confirm_cca(ieee802154_dev_t *dev)
{
bool clear;
int res = dev->driver->confirm_op(dev, IEEE802154_HAL_OP_CCA, &clear);
if (res < 0) {
return res;
}
return clear;
}
/**
* @brief Perform a Clear Channel Assessment (blocking)
*
* This function will internally call @ref ieee802154_radio_request_cca
* and poll @ref ieee802154_radio_confirm_cca.
*
* @pre the device is on
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return status of the CCA
*
* @retval positive number if the channel is clear
* @retval 0 if the channel is busy
* @retval negative errno on error
*/
static inline int ieee802154_radio_cca(ieee802154_dev_t *dev)
{
int res = ieee802154_radio_request_cca(dev);
if (res < 0) {
return res;
}
while ((res = ieee802154_radio_confirm_cca(dev)) == -EAGAIN) {}
return res;
}
/**
* @brief Check if the device supports ACK timeout
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_IRQ_ACK_TIMEOUT.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_irq_ack_timeout(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_IRQ_ACK_TIMEOUT);
}
/**
* @brief Check if the device supports frame retransmissions (with CSMA-CA).
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_FRAME_RETRANS.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_frame_retrans(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_FRAME_RETRANS);
}
/**
* @brief Check if the device supports Auto CSMA-CA for transmissions.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_AUTO_CSMA.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_auto_csma(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_AUTO_CSMA);
}
/**
* @brief Check if the device supports the IEEE802.15.4 Sub-GHz band
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_SUB_GHZ.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_sub_ghz(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_SUB_GHZ);
}
/**
* @brief Check if the device supports the IEEE802.15.4 2.4 GHz band
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_24_GHZ.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_24_ghz(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_24_GHZ);
}
/**
* @brief Check if the device supports TX done interrupt
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_IRQ_TX_DONE.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_irq_tx_done(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_IRQ_TX_DONE);
}
/**
* @brief Check if the device supports RX start interrupt
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_IRQ_RX_START.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_irq_rx_start(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_IRQ_RX_START);
}
/**
* @brief Check if the device supports TX start interrupt
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_IRQ_TX_START.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_irq_tx_start(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_IRQ_TX_START);
}
/**
* @brief Check if the device supports CCA done interrupt
*
* Internally this function reads ieee802154_radio_ops::caps with @ref
* IEEE802154_CAP_IRQ_CCA_DONE.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_irq_cca_done(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_IRQ_CCA_DONE);
}
/**
* @brief Check if the device reports the number of retransmissions of the last
* TX procedure.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_FRAME_RETRANS_INFO.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_frame_retrans_info(
ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_FRAME_RETRANS_INFO);
}
/**
* @brief Check if the device supports the BPSK PHY mode.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_PHY_BPSK.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_phy_bpsk(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_PHY_BPSK);
}
/**
* @brief Check if the device supports the ASK PHY mode.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_PHY_ASK.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_phy_ask(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_PHY_ASK);
}
/**
* @brief Check if the device supports the O-QPSK PHY mode.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_PHY_OQPSK.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_phy_oqpsk(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_PHY_OQPSK);
}
/**
* @brief Check if the device supports the MR-O-QPSK PHY mode.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_PHY_MR_OQPSK.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_phy_mr_oqpsk(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_PHY_MR_OQPSK);
}
/**
* @brief Check if the device supports the MR-OFDM PHY mode.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_PHY_MR_OFDM.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_phy_mr_ofdm(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_PHY_MR_OFDM);
}
/**
* @brief Check if the device supports the MR-FSK PHY mode.
*
* Internally this function reads ieee802154_radio_ops::caps and checks for
* @ref IEEE802154_CAP_PHY_MR_FSK.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return true if the device has support
* @return false otherwise
*/
static inline bool ieee802154_radio_has_phy_mr_fsk(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_CAP_PHY_MR_FSK);
}
/**
* @brief Get supported PHY modes of the device.
*
* Internally this function reads ieee802154_radio_ops::caps and returns only
* the bits from @ref IEEE802154_RF_CAPS_PHY_MASK.
*
* @param[in] dev IEEE802.15.4 device descriptor
*
* @return PHY modes bit mask.
*/
static inline uint32_t ieee802154_radio_get_phy_modes(ieee802154_dev_t *dev)
{
return (dev->driver->caps & IEEE802154_RF_CAPS_PHY_MASK);
}
/**
* @brief Convert a @ref ieee802154_phy_mode_t to a @ref ieee802154_rf_caps_t
* value.
*
* @param[in] phy_mode PHY mode
*
* @return Equivalent capability given the PHY mode.
* @return 0 on invalid values
* @return 0 when @ref IEEE802154_PHY_DISABLED is given as the parameter.
*/
static inline uint32_t ieee802154_phy_mode_to_cap(
ieee802154_phy_mode_t phy_mode)
{
switch (phy_mode) {
case IEEE802154_PHY_BPSK:
return IEEE802154_CAP_PHY_BPSK;
case IEEE802154_PHY_ASK:
return IEEE802154_CAP_PHY_ASK;
case IEEE802154_PHY_OQPSK:
return IEEE802154_CAP_PHY_OQPSK;
case IEEE802154_PHY_MR_OQPSK:
return IEEE802154_CAP_PHY_MR_OQPSK;
case IEEE802154_PHY_MR_OFDM:
return IEEE802154_CAP_PHY_MR_OFDM;
case IEEE802154_PHY_MR_FSK:
return IEEE802154_CAP_PHY_MR_FSK;
case IEEE802154_PHY_DISABLED:
default:
break;
}
return 0;
}
/**
* @brief Convert a @ref ieee802154_rf_caps_t to a @ref ieee802154_phy_mode_t
* value.
*
* @note The @p parameter must be one of the PHY capabilities.
*
* @param[in] cap The IEEE 802.15.4 capability.
*
* @return Equivalent phy mode given the capability.
* @return 0 on invalid values
*/
static inline ieee802154_phy_mode_t ieee802154_cap_to_phy_mode(uint32_t cap)
{
switch (cap) {
case IEEE802154_CAP_PHY_BPSK:
return IEEE802154_PHY_BPSK;
case IEEE802154_CAP_PHY_ASK:
return IEEE802154_PHY_ASK;
case IEEE802154_CAP_PHY_OQPSK:
return IEEE802154_PHY_OQPSK;
case IEEE802154_CAP_PHY_MR_OQPSK:
return IEEE802154_PHY_MR_OQPSK;
case IEEE802154_PHY_MR_OFDM:
return IEEE802154_PHY_MR_OFDM;
case IEEE802154_CAP_PHY_MR_FSK:
return IEEE802154_PHY_MR_FSK;
default:
break;
}
return IEEE802154_PHY_DISABLED;
}
#ifdef __cplusplus
}
#endif
#endif /* NET_IEEE802154_RADIO_H */
/** @} */