diff --git a/doc/memos/README.md b/doc/memos/README.md index 7f8e10f5b7..e43d959ea4 100644 --- a/doc/memos/README.md +++ b/doc/memos/README.md @@ -4,6 +4,7 @@ The index below lists the RDMs that were published so far. - [RDM0 : RIOT Developer Memo Format, Publishing and Maintenance Process](./rdm0000.md) - [RDM1 : RIOT Design Goals](./rdm0001.md) +- [RDM2 : The 802.15.4 Radio HAL](./rdm0002.md) # RDM development process diff --git a/doc/memos/rdm0002.md b/doc/memos/rdm0002.md new file mode 100644 index 0000000000..e930413255 --- /dev/null +++ b/doc/memos/rdm0002.md @@ -0,0 +1,2226 @@ +- RDM: 2 +- Title: The IEEE802.15.4 radio HAL +- Authors: José Álamos +- Status: Active +- 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](https://www.ietf.org/rfc/rfc2119.txt) 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](https://github.com/RIOT-OS/RIOT/issues/13771) +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. The `netdev` 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 a `netdev` + 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: +1. 802.15.4 Radio HAL: hardware-agnostic interface to drive radio devices + (proposed in this RDM). +2. 802.15.4 MAC: full link layer including PHY definition. +3. 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](http://www.makelinux.net/ldd3/chp-10-sect-4.shtml) + +## 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: + +1. Set up IRQ callback +2. Reset the device +3. Confirm connectivity and perform self tests +4. Bring device into a low power state +5. 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 + +- [Uniform Network Stack Integration](https://github.com/RIOT-OS/RIOT/issues/13771) +- [Top and Bottom Halves](http://www.makelinux.net/ldd3/chp-10-sect-4.shtml) + +# 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) + +```c +/* + * 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 + */ + +#ifndef NET_IEEE802154_RADIO_H +#define NET_IEEE802154_RADIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#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 */ +/** @} */ +```