diff --git a/drivers/nrf_802154/driver/CMakeLists.txt b/drivers/nrf_802154/driver/CMakeLists.txt index c16b22f..b96ed4d 100644 --- a/drivers/nrf_802154/driver/CMakeLists.txt +++ b/drivers/nrf_802154/driver/CMakeLists.txt @@ -64,8 +64,8 @@ else () endif () if (SL_OPENSOURCE OR NRF53_SERIES) - target_compile_definitions(nrf-802154-driver - PUBLIC + target_compile_definitions(nrf-802154-driver-interface + INTERFACE # Disable Frame Timestamps NRF_802154_FRAME_TIMESTAMP_ENABLED=0 # Disable DTRX @@ -74,8 +74,8 @@ if (SL_OPENSOURCE OR NRF53_SERIES) NRF_802154_IFS_ENABLED=0 ) else() - target_compile_definitions(nrf-802154-driver - PUBLIC + target_compile_definitions(nrf-802154-driver-interface + INTERFACE # Enable Frame Timestamps NRF_802154_FRAME_TIMESTAMP_ENABLED=1 # Enable DTRX diff --git a/drivers/nrf_802154/driver/include/nrf_802154.h b/drivers/nrf_802154/driver/include/nrf_802154.h index f258195..d4fc02d 100644 --- a/drivers/nrf_802154/driver/include/nrf_802154.h +++ b/drivers/nrf_802154/driver/include/nrf_802154.h @@ -56,7 +56,25 @@ extern "C" { /** * @brief Timestamp value indicating that the timestamp is inaccurate. */ -#define NRF_802154_NO_TIMESTAMP 0 +#define NRF_802154_NO_TIMESTAMP 0 + +/** + * @brief Invalid delayed timeslot identifier. + */ +#define NRF_802154_RESERVED_INVALID_ID UINT32_MAX + +/** + * @brief Reception window identifier reserved for immediate reception. + */ +#define NRF_802154_RESERVED_IMM_RX_WINDOW_ID (UINT32_MAX - 1) + +/** + * @brief Upper bound for delayed reception window identifiers used by the application. + * + * All integers ranging from 0 to @ref NRF_802154_RESERVED_DRX_ID_UPPER_BOUND (inclusive) + * can be used by the application as identifiers of delayed reception windows. + */ +#define NRF_802154_RESERVED_DRX_ID_UPPER_BOUND (UINT32_MAX - 4) /** * @brief Initializes the 802.15.4 driver. @@ -452,11 +470,19 @@ bool nrf_802154_receive(void); * * A scheduled reception can be cancelled by a call to @ref nrf_802154_receive_at_cancel. * - * @param[in] t0 Base of delay time - absolute time used by the Timer Scheduler, - * in microseconds (us). - * @param[in] dt Delta of delay time from @p t0, in microseconds (us). - * @param[in] timeout Reception timeout (counted from @p t0 + @p dt), in microseconds (us). - * @param[in] channel Radio channel on which the frame is to be received. + * @note The identifier @p id must be unique. It must not have the same value as identifiers + * of other delayed timeslots active at the moment, so that it can be mapped unambiguously + * to an active delayed operation if the request is successful. In particular, none of the reserved + * identifiers can be used. + * + * @param[in] t0 Base of delay time - absolute time used by the Timer Scheduler, + * in microseconds (us). + * @param[in] dt Delta of delay time from @p t0, in microseconds (us). + * @param[in] timeout Reception timeout (counted from @p t0 + @p dt), in microseconds (us). + * @param[in] channel Radio channel on which the frame is to be received. + * @param[in] id Identifier of the scheduled reception window. If the reception has been + * scheduled successfully, the value of this parameter can be used in + * @ref nrf_802154_receive_at_cancel to cancel it. * * @retval true The reception procedure was scheduled. * @retval false The driver could not schedule the reception procedure. @@ -464,7 +490,8 @@ bool nrf_802154_receive(void); bool nrf_802154_receive_at(uint32_t t0, uint32_t dt, uint32_t timeout, - uint8_t channel); + uint8_t channel, + uint32_t id); /** * @brief Cancels a delayed reception scheduled by a call to @ref nrf_802154_receive_at. @@ -473,10 +500,14 @@ bool nrf_802154_receive_at(uint32_t t0, * entering the receive window. If the receive window has been scheduled and has already started, * the radio remains in the receive state, but a window timeout will not be reported. * + * @param[in] id Identifier of the delayed reception window to be cancelled. If the provided + * value does not refer to any scheduled or active receive window, the function + * returns false. + * * @retval true The delayed reception was scheduled and successfully cancelled. * @retval false No delayed reception was scheduled. */ -bool nrf_802154_receive_at_cancel(void); +bool nrf_802154_receive_at_cancel(uint32_t id); #if NRF_802154_USE_RAW_API /** @@ -806,8 +837,13 @@ extern void nrf_802154_received_timestamp(uint8_t * p_data, * @brief Notifies that the reception of a frame failed. * * @param[in] error Error code that indicates the reason of the failure. + * @param[in] id Identifier of reception window the error occurred in. + * If the error is related to a delayed reception window requested through + * @ref nrf_802154_receive_at, the value of @p id equals the identifier + * of the scheduled reception window. Otherwise, the value of @p id equals + * @ref NRF_802154_RESERVED_IMM_RX_WINDOW_ID. */ -extern void nrf_802154_receive_failed(nrf_802154_rx_error_t error); +extern void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id); /** * @brief Notifies that transmitting a frame has started. diff --git a/drivers/nrf_802154/driver/include/nrf_802154_const.h b/drivers/nrf_802154/driver/include/nrf_802154_const.h index e0e33d0..26f08a5 100644 --- a/drivers/nrf_802154/driver/include/nrf_802154_const.h +++ b/drivers/nrf_802154/driver/include/nrf_802154_const.h @@ -43,126 +43,129 @@ #include #include "nrf_802154_config.h" -#define ACK_HEADER_WITH_PENDING 0x12 ///< The first byte of an ACK frame containing a pending bit. -#define ACK_HEADER_WITHOUT_PENDING 0x02 ///< The first byte of an ACK frame without a pending bit. +#define ACK_HEADER_WITH_PENDING 0x12 ///< The first byte of an ACK frame containing a pending bit. +#define ACK_HEADER_WITHOUT_PENDING 0x02 ///< The first byte of an ACK frame without a pending bit. -#define ACK_REQUEST_OFFSET 1 ///< Byte containing the ACK request bit (+1 for the frame length byte). -#define ACK_REQUEST_BIT (1 << 5) ///< ACK request bit. +#define ACK_REQUEST_OFFSET 1 ///< Byte containing the ACK request bit (+1 for the frame length byte). +#define ACK_REQUEST_BIT (1 << 5) ///< ACK request bit. -#define DEST_ADDR_TYPE_OFFSET 2 ///< Byte containing the destination address type (+1 for the frame length byte). -#define DEST_ADDR_TYPE_MASK 0x0c ///< Mask of bits containing the destination address type. -#define DEST_ADDR_TYPE_EXTENDED 0x0c ///< Bits containing the extended destination address type. -#define DEST_ADDR_TYPE_NONE 0x00 ///< Bits containing a not-present destination address type. -#define DEST_ADDR_TYPE_SHORT 0x08 ///< Bits containing the short destination address type. -#define DEST_ADDR_OFFSET 6 ///< Offset of the destination address in the Data frame (+1 for the frame length byte). +#define DEST_ADDR_TYPE_OFFSET 2 ///< Byte containing the destination address type (+1 for the frame length byte). +#define DEST_ADDR_TYPE_MASK 0x0c ///< Mask of bits containing the destination address type. +#define DEST_ADDR_TYPE_EXTENDED 0x0c ///< Bits containing the extended destination address type. +#define DEST_ADDR_TYPE_NONE 0x00 ///< Bits containing a not-present destination address type. +#define DEST_ADDR_TYPE_SHORT 0x08 ///< Bits containing the short destination address type. +#define DEST_ADDR_OFFSET 6 ///< Offset of the destination address in the Data frame (+1 for the frame length byte). -#define DSN_OFFSET 3 ///< Byte containing the DSN value (+1 for the frame length byte). -#define DSN_SUPPRESS_OFFSET 2 ///< Byte containing the DSN suppression field. -#define DSN_SUPPRESS_BIT 0x01 ///< Bits containing the DSN suppression field. +#define DSN_OFFSET 3 ///< Byte containing the DSN value (+1 for the frame length byte). +#define DSN_SUPPRESS_OFFSET 2 ///< Byte containing the DSN suppression field. +#define DSN_SUPPRESS_BIT 0x01 ///< Bits containing the DSN suppression field. -#define FRAME_COUNTER_SUPPRESS_BIT 0x20 ///< Bit containing the Frame Counter Suppression field. +#define FRAME_COUNTER_SUPPRESS_BIT 0x20 ///< Bit containing the Frame Counter Suppression field. -#define FRAME_PENDING_OFFSET 1 ///< Byte containing a pending bit (+1 for the frame length byte). -#define FRAME_PENDING_BIT (1 << 4) ///< Pending bit. +#define FRAME_PENDING_OFFSET 1 ///< Byte containing a pending bit (+1 for the frame length byte). +#define FRAME_PENDING_BIT (1 << 4) ///< Pending bit. -#define FRAME_TYPE_OFFSET 1 ///< Byte containing the frame type bits (+1 for the frame length byte). -#define FRAME_TYPE_MASK 0x07 ///< Mask of bits containing the frame type. -#define FRAME_TYPE_ACK 0x02 ///< Bits containing the ACK frame type. -#define FRAME_TYPE_BEACON 0x00 ///< Bits containing the Beacon frame type. -#define FRAME_TYPE_COMMAND 0x03 ///< Bits containing the Command frame type. -#define FRAME_TYPE_DATA 0x01 ///< Bits containing the Data frame type. -#define FRAME_TYPE_EXTENDED 0x07 ///< Bits containing the Extended frame type. -#define FRAME_TYPE_FRAGMENT 0x06 ///< Bits containing the Fragment or the Frak frame type. -#define FRAME_TYPE_MULTIPURPOSE 0x05 ///< Bits containing the Multipurpose frame type. +#define FRAME_TYPE_OFFSET 1 ///< Byte containing the frame type bits (+1 for the frame length byte). +#define FRAME_TYPE_MASK 0x07 ///< Mask of bits containing the frame type. +#define FRAME_TYPE_ACK 0x02 ///< Bits containing the ACK frame type. +#define FRAME_TYPE_BEACON 0x00 ///< Bits containing the Beacon frame type. +#define FRAME_TYPE_COMMAND 0x03 ///< Bits containing the Command frame type. +#define FRAME_TYPE_DATA 0x01 ///< Bits containing the Data frame type. +#define FRAME_TYPE_EXTENDED 0x07 ///< Bits containing the Extended frame type. +#define FRAME_TYPE_FRAGMENT 0x06 ///< Bits containing the Fragment or the Frak frame type. +#define FRAME_TYPE_MULTIPURPOSE 0x05 ///< Bits containing the Multipurpose frame type. -#define FRAME_VERSION_OFFSET 2 ///< Byte containing the frame version bits (+1 for the frame length byte). -#define FRAME_VERSION_MASK 0x30 ///< Mask of bits containing the frame version. -#define FRAME_VERSION_0 0x00 ///< Bits containing the frame version 0b00. -#define FRAME_VERSION_1 0x10 ///< Bits containing the frame version 0b01. -#define FRAME_VERSION_2 0x20 ///< Bits containing the frame version 0b10. -#define FRAME_VERSION_3 0x30 ///< Bits containing the frame version 0b11. +#define FRAME_VERSION_OFFSET 2 ///< Byte containing the frame version bits (+1 for the frame length byte). +#define FRAME_VERSION_MASK 0x30 ///< Mask of bits containing the frame version. +#define FRAME_VERSION_0 0x00 ///< Bits containing the frame version 0b00. +#define FRAME_VERSION_1 0x10 ///< Bits containing the frame version 0b01. +#define FRAME_VERSION_2 0x20 ///< Bits containing the frame version 0b10. +#define FRAME_VERSION_3 0x30 ///< Bits containing the frame version 0b11. -#define IE_HEADER_LENGTH_MASK 0x3f ///< Mask of bits containing the length of an IE header content. -#define IE_PRESENT_OFFSET 2 ///< Byte containing the IE Present bit. -#define IE_PRESENT_BIT 0x02 ///< Bits containing the IE Present field. +#define IE_HEADER_LENGTH_MASK 0x3f ///< Mask of bits containing the length of an IE header content. +#define IE_PRESENT_OFFSET 2 ///< Byte containing the IE Present bit. +#define IE_PRESENT_BIT 0x02 ///< Bits containing the IE Present field. -#define KEY_ID_MODE_MASK 0x18 ///< Mask of bits containing Key Identifier Mode in the Security Control field. -#define KEY_ID_MODE_0 0 ///< Bits containing the 0x00 Key Identifier Mode. -#define KEY_ID_MODE_1 0x08 ///< Bits containing the 0x01 Key Identifier Mode. -#define KEY_ID_MODE_2 0x10 ///< Bits containing the 0x10 Key Identifier Mode. -#define KEY_ID_MODE_3 0x18 ///< Bits containing the 0x11 Key Identifier Mode. +#define KEY_ID_MODE_MASK 0x18 ///< Mask of bits containing Key Identifier Mode in the Security Control field. +#define KEY_ID_MODE_0 0 ///< Bits containing the 0x00 Key Identifier Mode. +#define KEY_ID_MODE_1 0x08 ///< Bits containing the 0x01 Key Identifier Mode. +#define KEY_ID_MODE_2 0x10 ///< Bits containing the 0x10 Key Identifier Mode. +#define KEY_ID_MODE_3 0x18 ///< Bits containing the 0x11 Key Identifier Mode. -#define MAC_CMD_ASSOC_REQ 0x01 ///< Command frame identifier for MAC Association request. -#define MAC_CMD_ASSOC_RESP 0x02 ///< Command frame identifier for MAC Association response. -#define MAC_CMD_DISASSOC_NOTIFY 0x03 ///< Command frame identifier for MAC Disaccociation notification. -#define MAC_CMD_DATA_REQ 0x04 ///< Command frame identifier for MAC Data Requests. -#define MAC_CMD_PANID_CONFLICT 0x05 ///< Command frame identifier for MAC PAN ID conflict notification. -#define MAC_CMD_ORPHAN_NOTIFY 0x06 ///< Command frame identifier for MAC Orphan notification. -#define MAC_CMD_BEACON_REQ 0x07 ///< Command frame identifier for MAC Beacon. -#define MAC_CMD_COORD_REALIGN 0x08 ///< Command frame identifier for MAC Coordinator realignment. -#define MAC_CMD_GTS_REQUEST 0x09 ///< Command frame identifier for MAC GTS request. +#define MAC_CMD_ASSOC_REQ 0x01 ///< Command frame identifier for MAC Association request. +#define MAC_CMD_ASSOC_RESP 0x02 ///< Command frame identifier for MAC Association response. +#define MAC_CMD_DISASSOC_NOTIFY 0x03 ///< Command frame identifier for MAC Disaccociation notification. +#define MAC_CMD_DATA_REQ 0x04 ///< Command frame identifier for MAC Data Requests. +#define MAC_CMD_PANID_CONFLICT 0x05 ///< Command frame identifier for MAC PAN ID conflict notification. +#define MAC_CMD_ORPHAN_NOTIFY 0x06 ///< Command frame identifier for MAC Orphan notification. +#define MAC_CMD_BEACON_REQ 0x07 ///< Command frame identifier for MAC Beacon. +#define MAC_CMD_COORD_REALIGN 0x08 ///< Command frame identifier for MAC Coordinator realignment. +#define MAC_CMD_GTS_REQUEST 0x09 ///< Command frame identifier for MAC GTS request. -#define PAN_ID_COMPR_OFFSET 1 ///< Byte containing the PAN ID compression bit (+1 for the frame length byte). -#define PAN_ID_COMPR_MASK 0x40 ///< PAN ID compression bit. +#define PAN_ID_COMPR_OFFSET 1 ///< Byte containing the PAN ID compression bit (+1 for the frame length byte). +#define PAN_ID_COMPR_MASK 0x40 ///< PAN ID compression bit. -#define PAN_ID_OFFSET 4 ///< Offset of PAN ID in the Data frame (+1 for the frame length byte). +#define PAN_ID_OFFSET 4 ///< Offset of PAN ID in the Data frame (+1 for the frame length byte). -#define PHR_OFFSET 0 ///< Offset of the PHY header in a frame. +#define PHR_OFFSET 0 ///< Offset of the PHY header in a frame. -#define SECURITY_ENABLED_OFFSET 1 ///< Byte containing the Security Enabled bit. -#define SECURITY_ENABLED_BIT 0x08 ///< Bits containing the Security Enabled field. -#define SECURITY_LEVEL_MASK 0x07 ///< Mask of bits containing the Security level field. -#define SECURITY_LEVEL_MIC_32 0x01 ///< Bits containing the 32-bit Message Integrity Code (0b001). -#define SECURITY_LEVEL_MIC_64 0x02 ///< Bits containing the 64-bit Message Integrity Code (0b010). -#define SECURITY_LEVEL_MIC_128 0x03 ///< Bits containing the 128-bit Message Integrity Code (0b011). -#define SECURITY_LEVEL_ENC_MIC_32 0x05 ///< Bits containing the 32-bit Encrypted Message Integrity Code (0b101). -#define SECURITY_LEVEL_ENC_MIC_64 0x06 ///< Bits containing the 64-bit Encrypted Message Integrity Code (0b110). -#define SECURITY_LEVEL_ENC_MIC_128 0x07 ///< Bits containing the 128-bit Encrypted Message Integrity Code (0b111). +#define SECURITY_ENABLED_OFFSET 1 ///< Byte containing the Security Enabled bit. +#define SECURITY_ENABLED_BIT 0x08 ///< Bits containing the Security Enabled field. +#define SECURITY_LEVEL_MASK 0x07 ///< Mask of bits containing the Security level field. +#define SECURITY_LEVEL_MIC_32 0x01 ///< Bits containing the 32-bit Message Integrity Code (0b001). +#define SECURITY_LEVEL_MIC_64 0x02 ///< Bits containing the 64-bit Message Integrity Code (0b010). +#define SECURITY_LEVEL_MIC_128 0x03 ///< Bits containing the 128-bit Message Integrity Code (0b011). +#define SECURITY_LEVEL_ENC_MIC_32 0x05 ///< Bits containing the 32-bit Encrypted Message Integrity Code (0b101). +#define SECURITY_LEVEL_ENC_MIC_64 0x06 ///< Bits containing the 64-bit Encrypted Message Integrity Code (0b110). +#define SECURITY_LEVEL_ENC_MIC_128 0x07 ///< Bits containing the 128-bit Encrypted Message Integrity Code (0b111). -#define SRC_ADDR_TYPE_EXTENDED 0xc0 ///< Bits containing the extended source address type. -#define SRC_ADDR_TYPE_NONE 0x00 ///< Bits containing a not-present source address type. -#define SRC_ADDR_TYPE_MASK 0xc0 ///< Mask of bits containing the source address type. -#define SRC_ADDR_TYPE_OFFSET 2 ///< Byte containing the source address type (+1 for the frame length byte). -#define SRC_ADDR_TYPE_SHORT 0x80 ///< Bits containing the short source address type. +#define SRC_ADDR_TYPE_EXTENDED 0xc0 ///< Bits containing the extended source address type. +#define SRC_ADDR_TYPE_NONE 0x00 ///< Bits containing a not-present source address type. +#define SRC_ADDR_TYPE_MASK 0xc0 ///< Mask of bits containing the source address type. +#define SRC_ADDR_TYPE_OFFSET 2 ///< Byte containing the source address type (+1 for the frame length byte). +#define SRC_ADDR_TYPE_SHORT 0x80 ///< Bits containing the short source address type. -#define SRC_ADDR_OFFSET_SHORT_DST 8 ///< Offset of the source address in the Data frame if the destination address is short. -#define SRC_ADDR_OFFSET_EXTENDED_DST 14 ///< Offset of the source address in the Data frame if the destination address is extended. +#define SRC_ADDR_OFFSET_SHORT_DST 8 ///< Offset of the source address in the Data frame if the destination address is short. +#define SRC_ADDR_OFFSET_EXTENDED_DST 14 ///< Offset of the source address in the Data frame if the destination address is extended. -#define DSN_SIZE 1 ///< Size of the Sequence Number field. -#define FCF_SIZE 2 ///< Size of the FCF field. -#define FCS_SIZE 2 ///< Size of the FCS field. -#define FRAME_COUNTER_SIZE 4 ///< Size of the Frame Counter field. -#define IE_HEADER_SIZE 4 ///< Size of the obligatory IE Header field elements, including the header termination. -#define IMM_ACK_LENGTH 5 ///< Length of the ACK frame. -#define KEY_ID_MODE_1_SIZE 1 ///< Size of the 0x01 Key Identifier Mode field. -#define KEY_ID_MODE_2_SIZE 5 ///< Size of the 0x10 Key Identifier Mode field. -#define KEY_ID_MODE_3_SIZE 9 ///< Size of the 0x11 Key Identifier Mode field. -#define MAX_PACKET_SIZE 127 ///< Maximum size of the radio packet. -#define MIC_32_SIZE 4 ///< Size of MIC with the MIC-32 and ENC-MIC-32 security attributes. -#define MIC_64_SIZE 8 ///< Size of MIC with the MIC-64 and ENC-MIC-64 security attributes. -#define MIC_128_SIZE 16 ///< Size of MIC with the MIC-128 and ENC-MIC-128 security attributes. -#define PAN_ID_SIZE 2 ///< Size of the PAN ID. -#define PHR_SIZE 1 ///< Size of the PHR field. -#define SECURITY_CONTROL_SIZE 1 ///< Size of the Security Control field. +#define DSN_SIZE 1 ///< Size of the Sequence Number field. +#define FCF_SIZE 2 ///< Size of the FCF field. +#define FCS_SIZE 2 ///< Size of the FCS field. +#define FRAME_COUNTER_SIZE 4 ///< Size of the Frame Counter field. +#define IE_HEADER_SIZE 4 ///< Size of the obligatory IE Header field elements, including the header termination. +#define IMM_ACK_LENGTH 5 ///< Length of the ACK frame. +#define KEY_ID_MODE_1_SIZE 1 ///< Size of the 0x01 Key Identifier Mode field. +#define KEY_ID_MODE_2_SIZE 5 ///< Size of the 0x10 Key Identifier Mode field. +#define KEY_ID_MODE_3_SIZE 9 ///< Size of the 0x11 Key Identifier Mode field. +#define MAX_PACKET_SIZE 127 ///< Maximum size of the radio packet. +#define MIC_32_SIZE 4 ///< Size of MIC with the MIC-32 and ENC-MIC-32 security attributes. +#define MIC_64_SIZE 8 ///< Size of MIC with the MIC-64 and ENC-MIC-64 security attributes. +#define MIC_128_SIZE 16 ///< Size of MIC with the MIC-128 and ENC-MIC-128 security attributes. +#define PAN_ID_SIZE 2 ///< Size of the PAN ID. +#define PHR_SIZE 1 ///< Size of the PHR field. +#define SECURITY_CONTROL_SIZE 1 ///< Size of the Security Control field. -#define EXTENDED_ADDRESS_SIZE 8 ///< Size of the Extended Mac Address. -#define SHORT_ADDRESS_SIZE 2 ///< Size of the Short Mac Address. +#define EXTENDED_ADDRESS_SIZE 8 ///< Size of the Extended Mac Address. +#define SHORT_ADDRESS_SIZE 2 ///< Size of the Short Mac Address. -#define TURNAROUND_TIME 192UL ///< RX-to-TX or TX-to-RX turnaround time (aTurnaroundTime), in microseconds (us). -#define CCA_TIME 128UL ///< Time required to perform CCA detection (aCcaTime), in microseconds (us). -#define UNIT_BACKOFF_PERIOD (TURNAROUND_TIME + CCA_TIME) ///< Number of symbols in the basic time period used by CSMA-CA algorithm (aUnitBackoffPeriod), in (us). +#define TURNAROUND_TIME 192UL ///< RX-to-TX or TX-to-RX turnaround time (aTurnaroundTime), in microseconds (us). +#define CCA_TIME 128UL ///< Time required to perform CCA detection (aCcaTime), in microseconds (us). +#define UNIT_BACKOFF_PERIOD (TURNAROUND_TIME + CCA_TIME) ///< Number of symbols in the basic time period used by CSMA-CA algorithm (aUnitBackoffPeriod), in (us). -#define PHY_US_PER_SYMBOL 16 ///< Duration of a single symbol in microseconds (us). -#define PHY_SYMBOLS_PER_OCTET 2 ///< Number of symbols in a single byte (octet). -#define PHY_SHR_SYMBOLS 10 ///< Number of symbols in the Synchronization Header (SHR). +#define PHY_US_PER_SYMBOL 16 ///< Duration of a single symbol in microseconds (us). +#define PHY_SYMBOLS_PER_OCTET 2 ///< Number of symbols in a single byte (octet). +#define PHY_SHR_SYMBOLS 10 ///< Number of symbols in the Synchronization Header (SHR). -#define ED_RESULT_MAX 0xff ///< Maximal ED result. +#define ED_RESULT_MAX 0xff ///< Maximal ED result. -#define BROADCAST_ADDRESS ((uint8_t[SHORT_ADDRESS_SIZE]) {0xff, 0xff}) ///< Broadcast short address. +#define BROADCAST_ADDRESS ((uint8_t[SHORT_ADDRESS_SIZE]) {0xff, 0xff}) ///< Broadcast short address. -#define MIN_SIFS_PERIOD_US 192 ///< Minimum Short IFS period default value in us. -#define MIN_LIFS_PERIOD_US 640 ///< Minimum Long IFS period default value in us. -#define MAX_SIFS_FRAME_SIZE 18 ///< Maximum frame length which can be followed by the Short Interframe Space. +#define MIN_SIFS_PERIOD_US 192 ///< Minimum Short IFS period default value in us. +#define MIN_LIFS_PERIOD_US 640 ///< Minimum Long IFS period default value in us. +#define MAX_SIFS_FRAME_SIZE 18 ///< Maximum frame length which can be followed by the Short Interframe Space. + +#define NRF_802154_RESERVED_CSMACA_ID (UINT32_MAX - 2) ///< Delayed timeslot identifier reserved for CSMA/CA procedure. +#define NRF_802154_RESERVED_DTX_ID (UINT32_MAX - 3) ///< Delayed timeslot identifier reserved for delayed transmissions. typedef enum { diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ack_timeout.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ack_timeout.c index b8a94dc..dfd3b21 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ack_timeout.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ack_timeout.c @@ -80,7 +80,8 @@ static void timeout_timer_fired(void * p_context) if (nrf_802154_request_receive(NRF_802154_TERM_802154, REQ_ORIG_ACK_TIMEOUT, notify_tx_error, - false)) + false, + NRF_802154_RESERVED_IMM_RX_WINDOW_ID)) { m_procedure_is_active = false; } diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c index 225d10b..2d0070a 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c @@ -96,12 +96,15 @@ static bool procedure_is_running(void) */ static void procedure_stop(void) { - nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); + if (procedure_is_running()) + { + nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); - nrf_802154_rsch_delayed_timeslot_cancel(RSCH_DLY_CSMACA); - m_is_running = false; + nrf_802154_rsch_delayed_timeslot_cancel(NRF_802154_RESERVED_CSMACA_ID); + m_is_running = false; - nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); + nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); + } } static void priority_leverage(void) @@ -116,7 +119,8 @@ static void priority_leverage(void) if (first_transmit_attempt && coex_requires_boosted_prio) { // It should always be possible to update this timeslot's priority here - if (!nrf_802154_rsch_delayed_timeslot_priority_update(RSCH_DLY_CSMACA, RSCH_PRIO_TX)) + if (!nrf_802154_rsch_delayed_timeslot_priority_update(NRF_802154_RESERVED_CSMACA_ID, + RSCH_PRIO_TX)) { assert(false); } @@ -157,6 +161,7 @@ static void notify_busy_channel(bool result) */ static void frame_transmit(rsch_dly_ts_id_t dly_ts_id) { + assert(dly_ts_id == NRF_802154_RESERVED_CSMACA_ID); (void)dly_ts_id; nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -192,9 +197,10 @@ static void random_backoff_start(void) { .t0 = nrf_802154_timer_sched_time_get(), .dt = backoff_periods * UNIT_BACKOFF_PERIOD, - .id = RSCH_DLY_CSMACA, + .op = RSCH_DLY_TS_OP_CSMACA, .type = RSCH_DLY_TS_TYPE_RELAXED, .started_callback = frame_transmit, + .id = NRF_802154_RESERVED_CSMACA_ID, }; switch (nrf_802154_pib_coex_tx_request_mode_get()) @@ -219,6 +225,14 @@ static void random_backoff_start(void) break; } + if (m_nb != 0) + { + // Since CSMA/CA always requests delayed timeslot of type RSCH_DLY_TS_TYPE_RELAXED, + // it must be cancelled explicitly, so that the slot is released and available + // for the upcoming request. + nrf_802154_rsch_delayed_timeslot_cancel(NRF_802154_RESERVED_CSMACA_ID); + } + // Delayed timeslot with these parameters should always be scheduled if (!nrf_802154_rsch_delayed_timeslot_request(&backoff_ts_param)) { diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c index eccb8ff..af459ff 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c @@ -53,7 +53,9 @@ #include "nrf_802154_notification.h" #include "nrf_802154_pib.h" #include "nrf_802154_procedures_duration.h" +#include "nrf_802154_queue.h" #include "nrf_802154_request.h" +#include "nrf_802154_utils.h" #include "rsch/nrf_802154_rsch.h" #include "timer/nrf_802154_timer_sched.h" @@ -88,110 +90,293 @@ typedef struct } delayed_rx_frame_data_t; /** - * @brief TX delayed operation configuration. + * @brief RX delayed operation data. */ -static const uint8_t * mp_tx_data; ///< Pointer to a buffer containing PHR and PSDU of the frame requested to be transmitted. -static bool m_tx_cca; ///< If CCA should be performed prior to transmission. -static uint8_t m_tx_channel; ///< Channel number on which transmission should be performed. +typedef struct +{ + nrf_802154_timer_t timeout_timer; ///< Timer for delayed RX timeout handling. + volatile delayed_rx_frame_data_t extension_frame; ///< Data of frame that caused extension of RX window. + uint8_t channel; ///< Channel number on which reception should be performed. +} dly_rx_data_t; /** - * @brief RX delayed operation configuration. + * @brief TX delayed operation data. */ -static nrf_802154_timer_t m_timeout_timer; ///< Timer for delayed RX timeout handling. -static uint8_t m_rx_channel; ///< Channel number on which reception should be performed. +typedef struct +{ + const uint8_t * p_data; ///< Pointer to a buffer containing PHR and PSDU of the frame requested to be transmitted. + bool cca; ///< If CCA should be performed prior to transmission. + uint8_t channel; ///< Channel number on which transmission should be performed. +} dly_tx_data_t; /** - * @brief State of delayed operations. + * @brief Delayed operation data. */ -static volatile delayed_trx_op_state_t m_dly_op_state[RSCH_DLY_TS_NUM]; +typedef struct +{ + volatile delayed_trx_op_state_t state; ///< State of the delayed timeslot. + rsch_dly_ts_id_t id; ///< Identifier of the delayed timeslot. + rsch_dly_ts_op_t op; ///< Type of delayed operation to be performed. + + union + { + dly_tx_data_t tx; ///< Data specific for delayed transmission. + dly_rx_data_t rx; ///< Data specific for delayed reception. + }; +} dly_op_data_t; /** - * @brief RX delayed operation frame data. + * @brief Array of slots for RX delayed operations. */ -static volatile delayed_rx_frame_data_t m_dly_rx_frame; +static dly_op_data_t m_dly_rx_data[NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS]; + +/** + * @brief Array of slots for TX delayed operations. + */ +static dly_op_data_t m_dly_tx_data[NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS]; + +/** + * @brief Queue of RX delayed operations IDs to be processed. + */ +static nrf_802154_queue_t m_dly_rx_id_q; + +/** + * @brief Storage for RX delayed operations ID queue. + */ +static dly_op_data_t * m_dly_rx_id_q_mem[NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS]; + +/** + * @brief Search for a RX delayed operation with given ID. + * + * @param[in] id Identifier to search for. + * + * @return Pointer to matching slot. + */ +static dly_op_data_t * dly_rx_data_by_id_search(rsch_dly_ts_id_t id) +{ + dly_op_data_t * p_dly_op_data = NULL; + + for (uint32_t i = 0; i < sizeof(m_dly_rx_data) / sizeof(m_dly_rx_data[0]); i++) + { + if (m_dly_rx_data[i].id == id) + { + // Slot with a matching identifier found + if ((p_dly_op_data == NULL)) + { + // It's the first matching slot found + p_dly_op_data = &m_dly_rx_data[i]; + } + else + { + // There's already been a matching slot. We expect all active slots to have unique + // IDs and all inactive slots to have their IDs set to NRF_802154_RESERVED_INVALID_ID. + // If we ended up here then either we're searching for invalid ID or the IDs assigned + // to active slots aren't unique. Either way - assert. + assert(false); + } + } + } + + return p_dly_op_data; +} + +/** + * @brief Search for a TX delayed operation with given ID. + * + * @param[in] id Identifier to search for. + * + * @return Pointer to matching slot. + */ +static dly_op_data_t * dly_tx_data_by_id_search(rsch_dly_ts_id_t id) +{ + // Note that this function only supports a single slot. + assert(id == m_dly_tx_data[0].id); + + return &m_dly_tx_data[0]; +} + +/** + * @brief Check if there are any slots available. + * + * @param[in] p_dly_op_data_pool Pool of slots to check. + * @param[in] pool_len Total number of elements in the pool. + * + * @retval true The pool contains free slots. + * @retval false There are no available slots in the pool. + */ +static bool is_dly_ts_slot_available(const dly_op_data_t * p_dly_op_data_pool, uint32_t pool_len) +{ + for (uint32_t i = 0; i < pool_len; i++) + { + if (p_dly_op_data_pool[i].id == NRF_802154_RESERVED_INVALID_ID) + { + return true; + } + } + + return false; +} + +/** + * @brief Retrieve an available slot from a pool. + * + * @param[inout] p_dly_op_data_pool Pool of slots to allocate from. + * @param[in] pool_len Number of elements in the pool. + * + * @return Pointer to an available slot. + */ +static dly_op_data_t * available_dly_ts_slot_from_pool_get( + dly_op_data_t * p_dly_op_data_pool, uint32_t pool_len) +{ + for (uint32_t i = 0; i < pool_len; i++) + { + if (p_dly_op_data_pool[i].id == NRF_802154_RESERVED_INVALID_ID) + { + return &p_dly_op_data_pool[i]; + } + } + + return NULL; +} + +/** + * @brief Get a slot for TX delayed operation. + * + * @return Pointer to a slot. + */ +static dly_op_data_t * available_dly_tx_slot_get(void) +{ + return available_dly_ts_slot_from_pool_get( + m_dly_tx_data, + sizeof(m_dly_tx_data) / sizeof(m_dly_tx_data[0])); +} + +/** + * @brief Get a slot for RX delayed operation. + * + * @return Pointer to a slot. + */ +static dly_op_data_t * available_dly_rx_slot_get(void) +{ + return available_dly_ts_slot_from_pool_get( + m_dly_rx_data, + sizeof(m_dly_rx_data) / sizeof(m_dly_rx_data[0])); +} + +/** + * @brief Get an ongoing RX delayed operation slot. + * + * @return Pointer to a slot or NULL if no ongoing RX delayed operations exist at the moment. + */ +static dly_op_data_t * ongoing_dly_rx_slot_get(void) +{ + dly_op_data_t * p_dly_op_data = NULL; + + for (uint32_t i = 0; i < sizeof(m_dly_rx_data) / sizeof(m_dly_rx_data[0]); i++) + { + if (m_dly_rx_data[i].state == DELAYED_TRX_OP_STATE_ONGOING) + { + p_dly_op_data = &m_dly_rx_data[i]; + } + } + + return p_dly_op_data; +} + +static void dly_ts_slot_release(dly_op_data_t * p_dly_op_data) +{ + (void)nrf_802154_rsch_delayed_timeslot_cancel(p_dly_op_data->id); + + p_dly_op_data->id = NRF_802154_RESERVED_INVALID_ID; +} + +/** + * @brief Atomically push an ID to RX delayed operation ID queue. + * + * @param[in] id Identifier to be pushed to the queue. + */ +static void dly_rx_data_atomically_push(dly_op_data_t * p_dly_op_data) +{ + nrf_802154_mcu_critical_state_t mcu_cs; + + nrf_802154_mcu_critical_enter(mcu_cs); + + assert(!nrf_802154_queue_is_full(&m_dly_rx_id_q)); + + dly_op_data_t ** pp_op = (dly_op_data_t **)nrf_802154_queue_push_begin(&m_dly_rx_id_q); + + *pp_op = p_dly_op_data; + + nrf_802154_queue_push_commit(&m_dly_rx_id_q); + + nrf_802154_mcu_critical_exit(mcu_cs); +} + +/** + * @brief Atomically pop an ID from RX delayed operation ID queue. + * + * @param[out] p_id Pointer to identifier popped from the queue. + */ +static dly_op_data_t * dly_rx_data_atomically_pop(void) +{ + nrf_802154_mcu_critical_state_t mcu_cs; + + nrf_802154_mcu_critical_enter(mcu_cs); + + dly_op_data_t ** pp_op = (dly_op_data_t **)nrf_802154_queue_pop_begin(&m_dly_rx_id_q); + + nrf_802154_queue_pop_commit(&m_dly_rx_id_q); + + nrf_802154_mcu_critical_exit(mcu_cs); + + return *pp_op; +} /** * Set state of a delayed operation. * - * @param[in] expected_dly_rx_state Delayed RX current expected state. - * @param[in] new_dly_rx_state Delayed RX new state to be set. + * @param[in] p_dly_op_data Data of the delayed operation. + * @param[in] expected_state Expected delayed operation state prior state transition. + * @param[in] new_state Delayed operation state to enter. * * @retval true Successfully set the new state. * @retval false Failed to set the new state. */ -static bool dly_rx_state_set(delayed_trx_op_state_t expected_dly_rx_state, - delayed_trx_op_state_t new_dly_rx_state) -{ - volatile delayed_trx_op_state_t current_dly_rx_state; - - do - { - current_dly_rx_state = - (delayed_trx_op_state_t)__LDREXB((uint8_t *)&m_dly_op_state[RSCH_DLY_RX]); - - if (current_dly_rx_state != expected_dly_rx_state) - { - __CLREX(); - return false; - } - - } - while (__STREXB((uint8_t)new_dly_rx_state, (uint8_t *)&m_dly_op_state[RSCH_DLY_RX])); - - __DMB(); - - return true; -} - -/** - * Get state of a delayed operation. - * - * @param[in] dly_ts_id Delayed timeslot ID. - * - * @retval State of delayed operation. - */ -static delayed_trx_op_state_t dly_op_state_get(rsch_dly_ts_id_t dly_ts_id) -{ - assert(dly_ts_id < RSCH_DLY_TS_NUM); - - return m_dly_op_state[dly_ts_id]; -} - -/** - * Set state of a delayed operation. - * - * @param[in] dly_ts_id Delayed timeslot ID. - * @param[in] expected_state Expected delayed operation state prior state transition. - * @param[in] new_state Delayed operation state to enter. - */ -static void dly_op_state_set(rsch_dly_ts_id_t dly_ts_id, +static bool dly_op_state_set(dly_op_data_t * p_dly_op_data, delayed_trx_op_state_t expected_state, delayed_trx_op_state_t new_state) { assert(new_state < DELAYED_TRX_OP_STATE_NB); - switch (dly_ts_id) + switch (p_dly_op_data->op) { - case RSCH_DLY_TX: + case RSCH_DLY_TS_OP_DTX: + case RSCH_DLY_TS_OP_DRX: { - assert(m_dly_op_state[RSCH_DLY_TX] == expected_state); - m_dly_op_state[RSCH_DLY_TX] = new_state; - break; - } + volatile delayed_trx_op_state_t current_state; - case RSCH_DLY_RX: - { - bool result = dly_rx_state_set(expected_state, new_state); + do + { + current_state = (delayed_trx_op_state_t)__LDREXB((uint8_t *)&p_dly_op_data->state); - assert(result); - (void)result; - break; + if (current_state != expected_state) + { + __CLREX(); + return false; + } + + } + while (__STREXB((uint8_t)new_state, (uint8_t *)&p_dly_op_data->state)); + + __DMB(); + + return true; } default: { assert(false); - break; + return false; } } } @@ -199,24 +384,36 @@ static void dly_op_state_set(rsch_dly_ts_id_t dly_ts_id, /** * Start delayed operation. * - * @param[in] p_dly_ts_param Parameters of the requested delayed timeslot. + * @param[in] p_dly_ts_param Parameters of the requested delayed timeslot. + * @param[inout] p_dly_op_data Data of the delayed operation. */ -static bool dly_op_request(const rsch_dly_ts_param_t * p_dly_ts_param) +static bool dly_op_request(const rsch_dly_ts_param_t * p_dly_ts_param, + dly_op_data_t * p_dly_op_data) { // Set PENDING state before timeslot request, in case timeslot starts // immediately and interrupts current function execution. - dly_op_state_set(p_dly_ts_param->id, DELAYED_TRX_OP_STATE_STOPPED, - DELAYED_TRX_OP_STATE_PENDING); + bool state_set = dly_op_state_set( + p_dly_op_data, + DELAYED_TRX_OP_STATE_STOPPED, + DELAYED_TRX_OP_STATE_PENDING); + + assert(state_set); bool result = nrf_802154_rsch_delayed_timeslot_request(p_dly_ts_param); if (!result) { - dly_op_state_set(p_dly_ts_param->id, - DELAYED_TRX_OP_STATE_PENDING, - DELAYED_TRX_OP_STATE_STOPPED); + state_set = dly_op_state_set( + p_dly_op_data, + DELAYED_TRX_OP_STATE_PENDING, + DELAYED_TRX_OP_STATE_STOPPED); + + // In case of failure, the value of this parameter is undefined. Reset it + p_dly_op_data->id = NRF_802154_RESERVED_INVALID_ID; } + (void)state_set; + return result; } @@ -227,42 +424,46 @@ static bool dly_op_request(const rsch_dly_ts_param_t * p_dly_ts_param) */ static void notify_rx_timeout(void * p_context) { - (void)p_context; - nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); - assert(dly_op_state_get(RSCH_DLY_RX) != DELAYED_TRX_OP_STATE_PENDING); + dly_op_data_t * p_dly_op_data = (dly_op_data_t *)p_context; - if (dly_op_state_get(RSCH_DLY_RX) == DELAYED_TRX_OP_STATE_ONGOING) + assert(p_dly_op_data->state != DELAYED_TRX_OP_STATE_PENDING); + + if (p_dly_op_data->state == DELAYED_TRX_OP_STATE_ONGOING) { uint32_t now = nrf_802154_timer_sched_time_get(); - uint32_t sof_timestamp = m_dly_rx_frame.sof_timestamp; + uint32_t sof_timestamp = p_dly_op_data->rx.extension_frame.sof_timestamp; // Make sure that the timestamp has been latched safely. If frame reception preempts the code // after executing this line, the RX window will not be extended. __DMB(); - uint8_t psdu_length = m_dly_rx_frame.psdu_length; - bool ack_requested = m_dly_rx_frame.ack_requested; + uint8_t psdu_length = p_dly_op_data->rx.extension_frame.psdu_length; + bool ack_requested = p_dly_op_data->rx.extension_frame.ack_requested; uint32_t frame_length = nrf_802154_rx_duration_get(psdu_length, ack_requested); if (nrf_802154_timer_sched_time_is_in_future(now, sof_timestamp, frame_length)) { // @TODO protect against infinite extensions - allow only one timer extension - m_timeout_timer.t0 = sof_timestamp; - m_timeout_timer.dt = frame_length; + p_dly_op_data->rx.timeout_timer.t0 = sof_timestamp; + p_dly_op_data->rx.timeout_timer.dt = frame_length; - nrf_802154_timer_sched_add(&m_timeout_timer, true); + nrf_802154_timer_sched_add(&p_dly_op_data->rx.timeout_timer, true); } else { - if (dly_rx_state_set(DELAYED_TRX_OP_STATE_ONGOING, DELAYED_TRX_OP_STATE_STOPPED)) + if (dly_op_state_set(p_dly_op_data, + DELAYED_TRX_OP_STATE_ONGOING, + DELAYED_TRX_OP_STATE_STOPPED)) { - nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_TIMEOUT); + nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_TIMEOUT, + p_dly_op_data->id); + dly_ts_slot_release(p_dly_op_data); } // even if the set operation failed, the delayed RX state // should be set to STOPPED from other context anyway - assert(dly_op_state_get(RSCH_DLY_RX) == DELAYED_TRX_OP_STATE_STOPPED); + assert(p_dly_op_data->state == DELAYED_TRX_OP_STATE_STOPPED); } } @@ -276,17 +477,25 @@ static void notify_rx_timeout(void * p_context) */ static void dly_tx_result_notify(bool result) { - (void)result; + nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); + + // Currently there's only a single delayed transmission possible at a time + dly_op_data_t * p_dly_op_data = &m_dly_tx_data[0]; // To avoid attaching to every possible transmit hook, in order to be able // to switch from ONGOING to STOPPED state, ONGOING state is not used at all // and state is changed to STOPPED right after transmit request. - m_dly_op_state[RSCH_DLY_TX] = DELAYED_TRX_OP_STATE_STOPPED; + p_dly_op_data->state = DELAYED_TRX_OP_STATE_STOPPED; if (!result) { - nrf_802154_notify_transmit_failed(mp_tx_data, NRF_802154_TX_ERROR_TIMESLOT_DENIED); + nrf_802154_notify_transmit_failed(p_dly_op_data->tx.p_data, + NRF_802154_TX_ERROR_TIMESLOT_DENIED); } + + dly_ts_slot_release(p_dly_op_data); + + nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); } /** @@ -296,27 +505,122 @@ static void dly_tx_result_notify(bool result) */ static void dly_rx_result_notify(bool result) { + nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); + + dly_op_data_t * p_dly_op_data = dly_rx_data_atomically_pop(); + + if (p_dly_op_data == NULL) + { + assert(false); + return; + } + if (result) { - uint32_t now; + bool state_set; + uint32_t now; + dly_op_data_t * p_parallel_ongoing_dly_op_data = ongoing_dly_rx_slot_get(); - dly_op_state_set(RSCH_DLY_RX, DELAYED_TRX_OP_STATE_PENDING, DELAYED_TRX_OP_STATE_ONGOING); + if (p_parallel_ongoing_dly_op_data != NULL) + { + // There's another ongoing delayed RX operation. Close it now + state_set = dly_op_state_set(p_parallel_ongoing_dly_op_data, + DELAYED_TRX_OP_STATE_ONGOING, + DELAYED_TRX_OP_STATE_STOPPED); + + assert(state_set); + (void)state_set; + + nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_ABORTED, + p_parallel_ongoing_dly_op_data->id); + dly_ts_slot_release(p_parallel_ongoing_dly_op_data); + } + + state_set = dly_op_state_set( + p_dly_op_data, + DELAYED_TRX_OP_STATE_PENDING, + DELAYED_TRX_OP_STATE_ONGOING); + + assert(state_set); + (void)state_set; now = nrf_802154_timer_sched_time_get(); - m_timeout_timer.t0 = now; - m_dly_rx_frame.sof_timestamp = now; - m_dly_rx_frame.psdu_length = 0; - m_dly_rx_frame.ack_requested = false; + p_dly_op_data->rx.timeout_timer.t0 = now; + p_dly_op_data->rx.timeout_timer.p_context = p_dly_op_data; + p_dly_op_data->rx.extension_frame.sof_timestamp = now; + p_dly_op_data->rx.extension_frame.psdu_length = 0; + p_dly_op_data->rx.extension_frame.ack_requested = false; - nrf_802154_timer_sched_add(&m_timeout_timer, true); + nrf_802154_timer_sched_add(&p_dly_op_data->rx.timeout_timer, true); } else { - dly_op_state_set(RSCH_DLY_RX, DELAYED_TRX_OP_STATE_PENDING, DELAYED_TRX_OP_STATE_STOPPED); + bool state_set = dly_op_state_set( + p_dly_op_data, + DELAYED_TRX_OP_STATE_PENDING, + DELAYED_TRX_OP_STATE_STOPPED); - nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_TIMESLOT_DENIED); + assert(state_set); + (void)state_set; + + nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_TIMESLOT_DENIED, + p_dly_op_data->id); + dly_ts_slot_release(p_dly_op_data); } + + nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); +} + +static void transmit_attempt(dly_op_data_t * p_dly_op_data) +{ + nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); + + // No need to enqueue transmit attempts. Proceed to transmission immediately + nrf_802154_pib_channel_set(p_dly_op_data->tx.channel); + + if (nrf_802154_request_channel_update(REQ_ORIG_DELAYED_TRX)) + { + (void)nrf_802154_request_transmit(NRF_802154_TERM_802154, + REQ_ORIG_DELAYED_TRX, + p_dly_op_data->tx.p_data, + p_dly_op_data->tx.cca, + true, + dly_tx_result_notify); + } + else + { + dly_tx_result_notify(false); + } + + nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); +} + +static void receive_attempt(dly_op_data_t * p_dly_op_data) +{ + nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); + + // This function is expected to result in calling @ref dly_rx_result_notify. + // In order for that function to differentiate between different delayed RX + // windows, we atomically insert the ID of the current delayed RX into a FIFO queue. + dly_rx_data_atomically_push(p_dly_op_data); + + nrf_802154_pib_channel_set(p_dly_op_data->rx.channel); + + if (nrf_802154_request_channel_update(REQ_ORIG_DELAYED_TRX)) + { + (void)nrf_802154_request_receive(NRF_802154_TERM_802154, + REQ_ORIG_DELAYED_TRX, + dly_rx_result_notify, + true, + p_dly_op_data->id); + } + else + { + dly_rx_result_notify(false); + } + + nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); } /** @@ -328,32 +632,23 @@ static void tx_timeslot_started_callback(rsch_dly_ts_id_t dly_ts_id) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); - assert(dly_ts_id == RSCH_DLY_TX); + dly_op_data_t * p_dly_op_data = dly_tx_data_by_id_search(dly_ts_id); - switch (dly_op_state_get(dly_ts_id)) + if (p_dly_op_data == NULL) + { + assert(false); + return; + } + + switch (p_dly_op_data->state) { case DELAYED_TRX_OP_STATE_PENDING: - { - nrf_802154_pib_channel_set(m_tx_channel); - - if (nrf_802154_request_channel_update()) - { - (void)nrf_802154_request_transmit(NRF_802154_TERM_802154, - REQ_ORIG_DELAYED_TRX, - mp_tx_data, - m_tx_cca, - true, - dly_tx_result_notify); - } - else - { - dly_tx_result_notify(false); - } - + transmit_attempt(p_dly_op_data); break; - } case DELAYED_TRX_OP_STATE_STOPPED: + // TODO: is it certain that p_dly_op_data->id has a valid value here? + dly_ts_slot_release(p_dly_op_data); break; default: @@ -373,30 +668,23 @@ static void rx_timeslot_started_callback(rsch_dly_ts_id_t dly_ts_id) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); - assert(dly_ts_id == RSCH_DLY_RX); + dly_op_data_t * p_dly_op_data = dly_rx_data_by_id_search(dly_ts_id); - switch (dly_op_state_get(dly_ts_id)) + if (p_dly_op_data == NULL) + { + assert(false); + return; + } + + switch (p_dly_op_data->state) { case DELAYED_TRX_OP_STATE_PENDING: - { - nrf_802154_pib_channel_set(m_rx_channel); - - if (nrf_802154_request_channel_update()) - { - (void)nrf_802154_request_receive(NRF_802154_TERM_802154, - REQ_ORIG_DELAYED_TRX, - dly_rx_result_notify, - true); - } - else - { - dly_rx_result_notify(false); - } - + receive_attempt(p_dly_op_data); break; - } case DELAYED_TRX_OP_STATE_STOPPED: + // TODO: is it certain that p_dly_op_data->id has a valid value here? + dly_ts_slot_release(p_dly_op_data); break; default: @@ -407,13 +695,44 @@ static void rx_timeslot_started_callback(rsch_dly_ts_id_t dly_ts_id) nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); } +#ifdef TEST +#include "string.h" +void nrf_802154_delayed_trx_module_reset(void) +{ + memset(m_dly_rx_data, 0, sizeof(m_dly_rx_data)); + memset(m_dly_tx_data, 0, sizeof(m_dly_tx_data)); + memset(&m_dly_rx_id_q, 0, sizeof(m_dly_rx_id_q)); + memset(m_dly_rx_id_q_mem, 0, sizeof(m_dly_rx_id_q_mem)); +} + +#endif // TEST + +void nrf_802154_delayed_trx_init(void) +{ + nrf_802154_queue_init(&m_dly_rx_id_q, + m_dly_rx_id_q_mem, + sizeof(m_dly_rx_id_q_mem), + sizeof(m_dly_rx_id_q_mem[0])); + + for (uint32_t i = 0; i < sizeof(m_dly_rx_data) / sizeof(m_dly_rx_data[0]); i++) + { + m_dly_rx_data[i].id = NRF_802154_RESERVED_INVALID_ID; + } + + for (uint32_t i = 0; i < sizeof(m_dly_tx_data) / sizeof(m_dly_tx_data[0]); i++) + { + m_dly_tx_data[i].id = NRF_802154_RESERVED_INVALID_ID; + } +} + bool nrf_802154_delayed_trx_transmit(const uint8_t * p_data, bool cca, uint32_t t0, uint32_t dt, uint8_t channel) { - bool result = dly_op_state_get(RSCH_DLY_TX) == DELAYED_TRX_OP_STATE_STOPPED; + bool result = is_dly_ts_slot_available(m_dly_tx_data, + sizeof(m_dly_tx_data) / sizeof(m_dly_tx_data[0])); if (result) { @@ -425,21 +744,27 @@ bool nrf_802154_delayed_trx_transmit(const uint8_t * p_data, dt -= nrf_802154_cca_before_tx_duration_get(); } - mp_tx_data = p_data; - m_tx_cca = cca; - m_tx_channel = channel; + dly_op_data_t * p_dly_tx_data = available_dly_tx_slot_get(); + + p_dly_tx_data->op = RSCH_DLY_TS_OP_DTX; + + p_dly_tx_data->tx.p_data = p_data; + p_dly_tx_data->tx.cca = cca; + p_dly_tx_data->tx.channel = channel; + p_dly_tx_data->id = NRF_802154_RESERVED_DTX_ID; rsch_dly_ts_param_t dly_ts_param = { .t0 = t0, .dt = dt, .prio = RSCH_PRIO_TX, - .id = RSCH_DLY_TX, + .op = RSCH_DLY_TS_OP_DTX, .type = RSCH_DLY_TS_TYPE_PRECISE, .started_callback = tx_timeslot_started_callback, + .id = NRF_802154_RESERVED_DTX_ID, }; - result = dly_op_request(&dly_ts_param); + result = dly_op_request(&dly_ts_param, p_dly_tx_data); } return result; @@ -448,35 +773,42 @@ bool nrf_802154_delayed_trx_transmit(const uint8_t * p_data, bool nrf_802154_delayed_trx_receive(uint32_t t0, uint32_t dt, uint32_t timeout, - uint8_t channel) + uint8_t channel, + uint32_t id) { - bool result = dly_op_state_get(RSCH_DLY_RX) == DELAYED_TRX_OP_STATE_STOPPED; + bool result = is_dly_ts_slot_available(m_dly_rx_data, + sizeof(m_dly_rx_data) / sizeof(m_dly_rx_data[0])); if (result) { dt -= RX_SETUP_TIME; dt -= RX_RAMP_UP_TIME; - m_timeout_timer.dt = timeout + RX_RAMP_UP_TIME; - m_timeout_timer.callback = notify_rx_timeout; - m_timeout_timer.p_context = NULL; + dly_op_data_t * p_dly_rx_data = available_dly_rx_slot_get(); - m_rx_channel = channel; + p_dly_rx_data->op = RSCH_DLY_TS_OP_DRX; - // remove timer in case it was left after abort operation - nrf_802154_timer_sched_remove(&m_timeout_timer, NULL); + p_dly_rx_data->rx.timeout_timer.dt = timeout + RX_RAMP_UP_TIME; + p_dly_rx_data->rx.timeout_timer.callback = notify_rx_timeout; + + p_dly_rx_data->rx.channel = channel; + p_dly_rx_data->id = id; + + // Remove timer in case it was left after abort operation + nrf_802154_timer_sched_remove(&p_dly_rx_data->rx.timeout_timer, NULL); rsch_dly_ts_param_t dly_ts_param = { .t0 = t0, .dt = dt, .prio = RSCH_PRIO_IDLE_LISTENING, - .id = RSCH_DLY_RX, + .op = RSCH_DLY_TS_OP_DRX, .type = RSCH_DLY_TS_TYPE_PRECISE, .started_callback = rx_timeslot_started_callback, + .id = id, }; - result = dly_op_request(&dly_ts_param); + result = dly_op_request(&dly_ts_param, p_dly_rx_data); } return result; @@ -484,21 +816,40 @@ bool nrf_802154_delayed_trx_receive(uint32_t t0, bool nrf_802154_delayed_trx_transmit_cancel(void) { - bool result = nrf_802154_rsch_delayed_timeslot_cancel(RSCH_DLY_TX); + // This function does not provide any ID because it assumes that only a single delayed + // transmission can be scheduled at a time. Therefore use the first (and only) entry + // of m_dly_tx_data + dly_op_data_t * p_dly_op_data = &m_dly_tx_data[0]; + bool result = false; - m_dly_op_state[RSCH_DLY_TX] = DELAYED_TRX_OP_STATE_STOPPED; + if (p_dly_op_data->id != NRF_802154_RESERVED_INVALID_ID) + { + result = nrf_802154_rsch_delayed_timeslot_cancel(p_dly_op_data->id); + + p_dly_op_data->state = DELAYED_TRX_OP_STATE_STOPPED; + p_dly_op_data->id = NRF_802154_RESERVED_INVALID_ID; + } return result; } -bool nrf_802154_delayed_trx_receive_cancel(void) +bool nrf_802154_delayed_trx_receive_cancel(uint32_t id) { - bool result = nrf_802154_rsch_delayed_timeslot_cancel(RSCH_DLY_RX); + dly_op_data_t * p_dly_op_data = dly_rx_data_by_id_search(id); + + if (p_dly_op_data == NULL) + { + // Delayed receive window with provided ID could not be found. + return false; + } + + bool result = nrf_802154_rsch_delayed_timeslot_cancel(id); bool was_running = false; - nrf_802154_timer_sched_remove(&m_timeout_timer, &was_running); + nrf_802154_timer_sched_remove(&p_dly_op_data->rx.timeout_timer, &was_running); - m_dly_op_state[RSCH_DLY_RX] = DELAYED_TRX_OP_STATE_STOPPED; + p_dly_op_data->state = DELAYED_TRX_OP_STATE_STOPPED; + p_dly_op_data->id = NRF_802154_RESERVED_INVALID_ID; result = result || was_running; @@ -507,24 +858,25 @@ bool nrf_802154_delayed_trx_receive_cancel(void) bool nrf_802154_delayed_trx_abort(nrf_802154_term_t term_lvl, req_originator_t req_orig) { - bool result = true; + bool result = true; + dly_op_data_t * p_dly_op_data = ongoing_dly_rx_slot_get(); - if (req_orig == REQ_ORIG_DELAYED_TRX) - { - // Ignore if self-request. - } - else if (dly_op_state_get(RSCH_DLY_RX) == DELAYED_TRX_OP_STATE_ONGOING) + if (p_dly_op_data != NULL) { if (term_lvl >= NRF_802154_TERM_802154) { - if (dly_rx_state_set(DELAYED_TRX_OP_STATE_ONGOING, DELAYED_TRX_OP_STATE_STOPPED)) + if (dly_op_state_set(p_dly_op_data, + DELAYED_TRX_OP_STATE_ONGOING, + DELAYED_TRX_OP_STATE_STOPPED)) { - nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_ABORTED); + nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_DELAYED_ABORTED, + p_dly_op_data->id); + dly_ts_slot_release(p_dly_op_data); } - // even if the set operation failed, the delayed RX state + // Even if the set operation failed, the delayed RX state // should be set to STOPPED from other context anyway - assert(dly_op_state_get(RSCH_DLY_RX) == DELAYED_TRX_OP_STATE_STOPPED); + assert(p_dly_op_data->state == DELAYED_TRX_OP_STATE_STOPPED); } else { @@ -537,11 +889,14 @@ bool nrf_802154_delayed_trx_abort(nrf_802154_term_t term_lvl, req_originator_t r void nrf_802154_delayed_trx_rx_started_hook(const uint8_t * p_frame) { - if (dly_op_state_get(RSCH_DLY_RX) == DELAYED_TRX_OP_STATE_ONGOING) + dly_op_data_t * p_dly_op_data = ongoing_dly_rx_slot_get(); + + if (p_dly_op_data != NULL) { - m_dly_rx_frame.sof_timestamp = nrf_802154_timer_sched_time_get(); - m_dly_rx_frame.psdu_length = p_frame[PHR_OFFSET]; - m_dly_rx_frame.ack_requested = nrf_802154_frame_parser_ar_bit_is_set(p_frame); + p_dly_op_data->rx.extension_frame.sof_timestamp = nrf_802154_timer_sched_time_get(); + p_dly_op_data->rx.extension_frame.psdu_length = p_frame[PHR_OFFSET]; + p_dly_op_data->rx.extension_frame.ack_requested = nrf_802154_frame_parser_ar_bit_is_set( + p_frame); } } diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.h b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.h index 4db5fd0..f2dfc37 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.h +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.h @@ -53,6 +53,11 @@ * modes. */ +/** + * @brief Initializes delayed transmission and reception window features. + */ +void nrf_802154_delayed_trx_init(void); + /** * @brief Requests transmission of a frame at a given time. * @@ -98,25 +103,41 @@ bool nrf_802154_delayed_trx_transmit_cancel(void); * to a denied timeslot request or the reception timeout expires, * the @ref nrf_802154_receive_failed function is called. * + * @note The identifier @p id must be unique. It must not have the same value as identifiers + * of other delayed timeslots active at the moment, so that it can be mapped unambiguously + * to an active delayed operation if the request is successful. In particular, none of the reserved + * identifiers can be used. + * * @param[in] t0 Base of delay time in microseconds. * @param[in] dt Delta of delay time from @p t0 in microseconds. * @param[in] timeout Reception timeout (counted from @p t0 + @p dt) in microseconds. * @param[in] channel Number of the channel on which the frame is to be received. + * @param[in] id Identifier of the scheduled reception window. If the reception has been + * scheduled successfully, the value of this parameter can be used in + * @ref nrf_802154_delayed_trx_receive_cancel to cancel it. + * + * @retval true The reception procedure was scheduled. + * @retval false The driver could not schedule the reception procedure. */ bool nrf_802154_delayed_trx_receive(uint32_t t0, uint32_t dt, uint32_t timeout, - uint8_t channel); + uint8_t channel, + uint32_t id); /** * @brief Cancels a reception scheduled by a call to @ref nrf_802154_delayed_trx_receive. * * After a call to this function, no reception timeout event will be notified. * + * @param[in] id Identifier of the delayed reception window to be cancelled. If the provided + * value does not refer to any scheduled or active receive window, the function + * returns false. + * * @retval true Successfully cancelled a scheduled transmission. * @retval false No delayed reception was scheduled. */ -bool nrf_802154_delayed_trx_receive_cancel(void); +bool nrf_802154_delayed_trx_receive_cancel(uint32_t id); /** * @brief Aborts an ongoing delayed reception procedure. diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_precise_ack_timeout.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_precise_ack_timeout.c index da907fa..3a2b4ac 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_precise_ack_timeout.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_precise_ack_timeout.c @@ -83,7 +83,8 @@ static void timeout_timer_fired(void * p_context) if (nrf_802154_request_receive(NRF_802154_TERM_802154, REQ_ORIG_ACK_TIMEOUT, notify_tx_error, - false)) + false, + NRF_802154_RESERVED_IMM_RX_WINDOW_ID)) { m_procedure_is_active = false; } diff --git a/drivers/nrf_802154/driver/src/nrf_802154.c b/drivers/nrf_802154/driver/src/nrf_802154.c index 1b2bba7..625e7be 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154.c +++ b/drivers/nrf_802154/driver/src/nrf_802154.c @@ -116,7 +116,7 @@ void nrf_802154_channel_set(uint8_t channel) if (changed) { - (void)nrf_802154_request_channel_update(); + (void)nrf_802154_request_channel_update(REQ_ORIG_HIGHER_LAYER); } } @@ -219,6 +219,9 @@ void nrf_802154_init(void) nrf_802154_temperature_init(); nrf_802154_timer_coord_init(); nrf_802154_timer_sched_init(); +#if NRF_802154_DELAYED_TRX_ENABLED + nrf_802154_delayed_trx_init(); +#endif } void nrf_802154_deinit(void) @@ -411,7 +414,11 @@ bool nrf_802154_receive(void) nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); - result = nrf_802154_request_receive(NRF_802154_TERM_802154, REQ_ORIG_HIGHER_LAYER, NULL, true); + result = nrf_802154_request_receive(NRF_802154_TERM_802154, + REQ_ORIG_HIGHER_LAYER, + NULL, + true, + NRF_802154_RESERVED_IMM_RX_WINDOW_ID); nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW); return result; @@ -489,25 +496,26 @@ bool nrf_802154_transmit_at_cancel(void) bool nrf_802154_receive_at(uint32_t t0, uint32_t dt, uint32_t timeout, - uint8_t channel) + uint8_t channel, + uint32_t id) { bool result; nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); - result = nrf_802154_delayed_trx_receive(t0, dt, timeout, channel); + result = nrf_802154_delayed_trx_receive(t0, dt, timeout, channel, id); nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW); return result; } -bool nrf_802154_receive_at_cancel(void) +bool nrf_802154_receive_at_cancel(uint32_t id) { bool result; nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); - result = nrf_802154_delayed_trx_receive_cancel(); + result = nrf_802154_delayed_trx_receive_cancel(id); nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW); return result; @@ -899,7 +907,9 @@ __WEAK void nrf_802154_tx_ack_started(const uint8_t * p_data) #if NRF_802154_USE_RAW_API __WEAK void nrf_802154_received_raw(uint8_t * p_data, int8_t power, uint8_t lqi) { - nrf_802154_received_timestamp_raw(p_data, power, lqi, + nrf_802154_received_timestamp_raw(p_data, + power, + lqi, nrf_802154_stat_timestamp_read(last_rx_end_timestamp)); } @@ -938,9 +948,10 @@ __WEAK void nrf_802154_received_timestamp(uint8_t * p_data, #endif // !NRF_802154_USE_RAW_API -__WEAK void nrf_802154_receive_failed(nrf_802154_rx_error_t error) +__WEAK void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { (void)error; + (void)id; } __WEAK void nrf_802154_tx_started(const uint8_t * p_frame) diff --git a/drivers/nrf_802154/driver/src/nrf_802154_core.c b/drivers/nrf_802154/driver/src/nrf_802154_core.c index 9bf4878..a0fe300 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_core.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_core.c @@ -147,6 +147,9 @@ static nrf_802154_timer_t m_rx_prestarted_timer; /** @brief Value of Coex TX Request mode */ static nrf_802154_coex_tx_request_mode_t m_coex_tx_request_mode; +/** @brief Identifier of currently active reception window. */ +static uint32_t m_rx_window_id; + #if NRF_802154_TOTAL_TIMES_MEASUREMENT_ENABLED #if !NRF_802154_FRAME_TIMESTAMP_ENABLED #error NRF_802154_FRAME_TIMESTAMP_ENABLED == 0 when NRF_802154_TOTAL_TIMES_MEASUREMENT_ENABLED != 0 @@ -181,7 +184,8 @@ static void state_set(radio_state_t state) m_state = state; nrf_802154_log_local_event(NRF_802154_LOG_VERBOSITY_LOW, - NRF_802154_LOG_LOCAL_EVENT_ID_CORE__SET_STATE, (uint32_t)state); + NRF_802154_LOG_LOCAL_EVENT_ID_CORE__SET_STATE, + (uint32_t)state); request_preconditions_for_state(state); } @@ -292,7 +296,7 @@ static void receive_failed_notify(nrf_802154_rx_error_t error) { nrf_802154_critical_section_nesting_allow(); - nrf_802154_notify_receive_failed(error); + nrf_802154_notify_receive_failed(error, m_rx_window_id); nrf_802154_critical_section_nesting_deny(); } @@ -671,7 +675,7 @@ static void operation_terminated_notify(radio_state_t state, bool receiving_psdu case RADIO_STATE_RX: if (receiving_psdu_now) { - nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_ABORTED); + nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_ABORTED, m_rx_window_id); } break; @@ -1621,7 +1625,7 @@ uint8_t nrf_802154_trx_receive_frame_bcmatched(uint8_t bcc) // which could result in spurious RF emission. rx_init(); - nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_TIMESLOT_ENDED); + nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_TIMESLOT_ENDED, m_rx_window_id); } } @@ -1741,7 +1745,8 @@ void nrf_802154_trx_receive_frame_crcerror(void) #endif #if NRF_802154_TOTAL_TIMES_MEASUREMENT_ENABLED - update_total_times_on_receive_end(listening_start_hp_timestamp, receive_end_hp_timestamp, + update_total_times_on_receive_end(listening_start_hp_timestamp, + receive_end_hp_timestamp, mp_current_rx_buffer->data[PHR_OFFSET]); #endif @@ -1762,7 +1767,8 @@ void nrf_802154_trx_receive_ack_crcerror(void) uint32_t receive_end_hp_timestamp = nrf_802154_hp_timer_timestamp_get(); uint32_t listening_start_hp_timestamp = m_listening_start_hp_timestamp; - update_total_times_on_receive_end(listening_start_hp_timestamp, receive_end_hp_timestamp, + update_total_times_on_receive_end(listening_start_hp_timestamp, + receive_end_hp_timestamp, mp_current_rx_buffer->data[PHR_OFFSET]); #endif @@ -1781,7 +1787,8 @@ void nrf_802154_trx_receive_frame_received(void) uint32_t receive_end_hp_timestamp = nrf_802154_hp_timer_timestamp_get(); uint32_t listening_start_hp_timestamp = m_listening_start_hp_timestamp; - update_total_times_on_receive_end(listening_start_hp_timestamp, receive_end_hp_timestamp, + update_total_times_on_receive_end(listening_start_hp_timestamp, + receive_end_hp_timestamp, mp_current_rx_buffer->data[PHR_OFFSET]); #endif @@ -2192,7 +2199,8 @@ void nrf_802154_trx_receive_ack_received(void) uint32_t receive_end_hp_timestamp = nrf_802154_hp_timer_timestamp_get(); uint32_t listening_start_hp_timestamp = m_listening_start_hp_timestamp; - update_total_times_on_receive_end(listening_start_hp_timestamp, receive_end_hp_timestamp, + update_total_times_on_receive_end(listening_start_hp_timestamp, + receive_end_hp_timestamp, mp_current_rx_buffer->data[PHR_OFFSET]); #endif @@ -2405,7 +2413,8 @@ bool nrf_802154_core_sleep(nrf_802154_term_t term_lvl) bool nrf_802154_core_receive(nrf_802154_term_t term_lvl, req_originator_t req_orig, nrf_802154_notification_func_t notify_function, - bool notify_abort) + bool notify_abort, + uint32_t id) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -2423,6 +2432,7 @@ bool nrf_802154_core_receive(nrf_802154_term_t term_lvl, { m_trx_receive_frame_notifications_mask = make_trx_frame_receive_notification_mask(); + m_rx_window_id = id; state_set(RADIO_STATE_RX); rx_init(); } @@ -2653,7 +2663,7 @@ bool nrf_802154_core_notify_buffer_free(uint8_t * p_data) return true; } -bool nrf_802154_core_channel_update(void) +bool nrf_802154_core_channel_update(req_originator_t req_orig) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -2669,7 +2679,7 @@ bool nrf_802154_core_channel_update(void) switch (m_state) { case RADIO_STATE_RX: - if (current_operation_terminate(NRF_802154_TERM_NONE, REQ_ORIG_CORE, true)) + if (current_operation_terminate(NRF_802154_TERM_802154, req_orig, true)) { rx_init(); } diff --git a/drivers/nrf_802154/driver/src/nrf_802154_core.h b/drivers/nrf_802154/driver/src/nrf_802154_core.h index 9f430a6..8bc6231 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_core.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_core.h @@ -121,6 +121,7 @@ bool nrf_802154_core_sleep(nrf_802154_term_t term_lvl); * @param[in] req_orig Module that originates this request. * @param[in] notify_function Function called to notify the status of this procedure. May be NULL. * @param[in] notify_abort If abort notification is to be triggered. + * @param[in] id Identifier of reception window. * * @retval true Entering the receive state succeeded. * @retval false Entering the receive state failed (the driver is performing other procedure). @@ -128,7 +129,8 @@ bool nrf_802154_core_sleep(nrf_802154_term_t term_lvl); bool nrf_802154_core_receive(nrf_802154_term_t term_lvl, req_originator_t req_orig, nrf_802154_notification_func_t notify_function, - bool notify_abort); + bool notify_abort, + uint32_t id); /** * @brief Requests the transition to the @ref RADIO_STATE_TX state. @@ -225,8 +227,10 @@ bool nrf_802154_core_notify_buffer_free(uint8_t * p_data); * in the @ref RADIO_STATE_RX, in the @ref RADIO_STATE_CONTINUOUS_CARRIER * or in the @ref RADIO_STATE_MODULATED_CARRIER state, the transceiver is disabled * and enabled again to use the new channel. + * + * @param[in] req_orig Module that originates this request. */ -bool nrf_802154_core_channel_update(void); +bool nrf_802154_core_channel_update(req_originator_t req_orig); /** * @brief Notifies the core module that the next higher layer requested the change diff --git a/drivers/nrf_802154/driver/src/nrf_802154_notification.h b/drivers/nrf_802154/driver/src/nrf_802154_notification.h index 36c57f5..4a08316 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_notification.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_notification.h @@ -79,8 +79,13 @@ void nrf_802154_notify_received(uint8_t * p_data, int8_t power, uint8_t lqi); * @brief Notifies the next higher layer that the reception of a frame failed. * * @param[in] error Error code that indicates the reason of the failure. + * @param[in] id Identifier of reception window the error occurred in. + * If the error is related to a delayed reception window requested through + * @ref nrf_802154_receive_at, the value of @p id equals the identifier + * of the scheduled reception window. Otherwise, the value of @p id equals + * @ref NRF_802154_RESERVED_IMM_RX_WINDOW_ID. */ -void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error); +void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error, uint32_t id); /** * @brief Notifies the next higher layer that a frame was transmitted. diff --git a/drivers/nrf_802154/driver/src/nrf_802154_notification_direct.c b/drivers/nrf_802154/driver/src/nrf_802154_notification_direct.c index 20c7074..72d0642 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_notification_direct.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_notification_direct.c @@ -63,9 +63,9 @@ void nrf_802154_notify_received(uint8_t * p_data, int8_t power, uint8_t lqi) #endif // NRF_802154_USE_RAW_API } -void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error) +void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { - nrf_802154_receive_failed(error); + nrf_802154_receive_failed(error, id); } void nrf_802154_notify_transmitted(const uint8_t * p_frame, diff --git a/drivers/nrf_802154/driver/src/nrf_802154_notification_swi.c b/drivers/nrf_802154/driver/src/nrf_802154_notification_swi.c index a66bea0..27404dd 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_notification_swi.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_notification_swi.c @@ -95,6 +95,7 @@ typedef struct struct { nrf_802154_rx_error_t error; ///< An error code that indicates reason of the failure. + uint32_t id; ///< Identifier of reception window the error occured in. } receive_failed; struct @@ -196,12 +197,13 @@ void swi_notify_received(uint8_t * p_data, int8_t power, uint8_t lqi) * * @param[in] error Error code that indicates reason of the failure. */ -void swi_notify_receive_failed(nrf_802154_rx_error_t error) +void swi_notify_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { nrf_802154_ntf_data_t * p_slot = ntf_enter(); p_slot->type = NTF_TYPE_RECEIVE_FAILED; p_slot->data.receive_failed.error = error; + p_slot->data.receive_failed.id = id; ntf_exit(); } @@ -320,7 +322,8 @@ void swi_notify_cca_failed(nrf_802154_cca_error_t error) void nrf_802154_notification_init(void) { - nrf_802154_queue_init(&m_notifications_queue, m_notifications_queue_memory, + nrf_802154_queue_init(&m_notifications_queue, + m_notifications_queue_memory, sizeof(m_notifications_queue_memory), sizeof(m_notifications_queue_memory[0])); @@ -334,9 +337,9 @@ void nrf_802154_notify_received(uint8_t * p_data, int8_t power, uint8_t lqi) swi_notify_received(p_data, power, lqi); } -void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error) +void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { - swi_notify_receive_failed(error); + swi_notify_receive_failed(error, id); } void nrf_802154_notify_transmitted(const uint8_t * p_frame, @@ -396,7 +399,8 @@ static void irq_handler_ntf_event(void) break; case NTF_TYPE_RECEIVE_FAILED: - nrf_802154_receive_failed(p_slot->data.receive_failed.error); + nrf_802154_receive_failed(p_slot->data.receive_failed.error, + p_slot->data.receive_failed.id); break; case NTF_TYPE_TRANSMITTED: diff --git a/drivers/nrf_802154/driver/src/nrf_802154_request.h b/drivers/nrf_802154/driver/src/nrf_802154_request.h index 78c6999..3b1461d 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_request.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_request.h @@ -75,6 +75,7 @@ bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl); * @param[in] req_orig Module that originates this request. * @param[in] notify_function Function called to notify the status of this procedure. May be NULL. * @param[in] notify_abort If the abort notification is to be triggered automatically. + * @param[in] id Identifier of a reception window. * * @retval true The driver will enter the receive state. * @retval false The driver cannot enter the receive state due to ongoing operation. @@ -82,7 +83,8 @@ bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl); bool nrf_802154_request_receive(nrf_802154_term_t term_lvl, req_originator_t req_orig, nrf_802154_notification_func_t notify_function, - bool notify_abort); + bool notify_abort, + uint32_t id); /** * @brief Request entering the @ref RADIO_STATE_TX state for the driver. @@ -162,8 +164,10 @@ bool nrf_802154_request_antenna_update(void); /** * @brief Requests the driver to update the channel number used by the RADIO peripheral. + * + * @param[in] req_orig Module that originates this request. */ -bool nrf_802154_request_channel_update(void); +bool nrf_802154_request_channel_update(req_originator_t req_orig); /** * @brief Requests the driver to update the CCA configuration used by the RADIO peripheral. diff --git a/drivers/nrf_802154/driver/src/nrf_802154_request_direct.c b/drivers/nrf_802154/driver/src/nrf_802154_request_direct.c index a07906d..46001de 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_request_direct.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_request_direct.c @@ -73,13 +73,15 @@ bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl) bool nrf_802154_request_receive(nrf_802154_term_t term_lvl, req_originator_t req_orig, nrf_802154_notification_func_t notify_function, - bool notify_abort) + bool notify_abort, + uint32_t id) { REQUEST_FUNCTION_PARMS(nrf_802154_core_receive, term_lvl, req_orig, notify_function, - notify_abort) + notify_abort, + id) } bool nrf_802154_request_transmit(nrf_802154_term_t term_lvl, @@ -129,9 +131,9 @@ bool nrf_802154_request_antenna_update(void) REQUEST_FUNCTION(nrf_802154_core_antenna_update) } -bool nrf_802154_request_channel_update(void) +bool nrf_802154_request_channel_update(req_originator_t req_orig) { - REQUEST_FUNCTION(nrf_802154_core_channel_update) + REQUEST_FUNCTION_PARMS(nrf_802154_core_channel_update, req_orig) } bool nrf_802154_request_cca_cfg_update(void) diff --git a/drivers/nrf_802154/driver/src/nrf_802154_request_swi.c b/drivers/nrf_802154/driver/src/nrf_802154_request_swi.c index 5f71b61..aa15d18 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_request_swi.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_request_swi.c @@ -106,6 +106,7 @@ typedef struct nrf_802154_term_t term_lvl; ///< Request priority. req_originator_t req_orig; ///< Request originator. bool notif_abort; ///< If function termination should be notified. + uint32_t id; ///< Identifier of a reception window. bool * p_result; ///< Receive request result. } receive; ///< Receive request details. @@ -154,8 +155,9 @@ typedef struct struct { - bool * p_result; ///< Channel update request result. - } channel_update; ///< Channel update request details. + req_originator_t req_orig; ///< Request originator. + bool * p_result; ///< Channel update request result. + } channel_update; ///< Channel update request details. struct { @@ -293,12 +295,14 @@ static void swi_sleep(nrf_802154_term_t term_lvl, bool * p_result) * @param[in] req_orig Module that originates this request. * @param[in] notify_function Function called to notify the status of the procedure. May be NULL. * @param[in] notify_abort If abort notification should be triggered automatically. + * @param[in] id Identifier of the reception window. * @param[out] p_result Result of entering the receive state. */ static void swi_receive(nrf_802154_term_t term_lvl, req_originator_t req_orig, nrf_802154_notification_func_t notify_function, bool notify_abort, + uint32_t id, bool * p_result) { nrf_802154_req_data_t * p_slot = req_enter(); @@ -308,6 +312,7 @@ static void swi_receive(nrf_802154_term_t term_lvl, p_slot->data.receive.req_orig = req_orig; p_slot->data.receive.notif_func = notify_function; p_slot->data.receive.notif_abort = notify_abort; + p_slot->data.receive.id = id; p_slot->data.receive.p_result = p_result; req_exit(); @@ -467,12 +472,13 @@ static void swi_antenna_update(bool * p_result) * @param[out] p_result Pointer where the result to be returned by * nrf_802154_request_channel_update should be written by the swi handler. */ -static void swi_channel_update(bool * p_result) +static void swi_channel_update(req_originator_t req_orig, bool * p_result) { nrf_802154_req_data_t * p_slot = req_enter(); p_slot->type = REQ_TYPE_CHANNEL_UPDATE; p_slot->data.channel_update.p_result = p_result; + p_slot->data.channel_update.req_orig = req_orig; req_exit(); } @@ -529,8 +535,10 @@ static void swi_rssi_measurement_get(int8_t * p_rssi, bool * p_result) void nrf_802154_request_init(void) { - nrf_802154_queue_init(&m_requests_queue, m_requests_queue_memory, - sizeof(m_requests_queue_memory), sizeof(m_requests_queue_memory[0])); + nrf_802154_queue_init(&m_requests_queue, + m_requests_queue_memory, + sizeof(m_requests_queue_memory), + sizeof(m_requests_queue_memory[0])); nrf_egu_int_enable(NRF_802154_EGU_INSTANCE, REQ_INT); @@ -545,14 +553,16 @@ bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl) bool nrf_802154_request_receive(nrf_802154_term_t term_lvl, req_originator_t req_orig, nrf_802154_notification_func_t notify_function, - bool notify_abort) + bool notify_abort, + uint32_t id) { REQUEST_FUNCTION(nrf_802154_core_receive, swi_receive, term_lvl, req_orig, notify_function, - notify_abort) + notify_abort, + id) } bool nrf_802154_request_transmit(nrf_802154_term_t term_lvl, @@ -588,7 +598,8 @@ bool nrf_802154_request_cca(nrf_802154_term_t term_lvl) bool nrf_802154_request_continuous_carrier(nrf_802154_term_t term_lvl) { - REQUEST_FUNCTION(nrf_802154_core_continuous_carrier, swi_continuous_carrier, + REQUEST_FUNCTION(nrf_802154_core_continuous_carrier, + swi_continuous_carrier, term_lvl) } @@ -611,9 +622,9 @@ bool nrf_802154_request_antenna_update(void) REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_antenna_update, swi_antenna_update) } -bool nrf_802154_request_channel_update(void) +bool nrf_802154_request_channel_update(req_originator_t req_orig) { - REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_channel_update, swi_channel_update) + REQUEST_FUNCTION(nrf_802154_core_channel_update, swi_channel_update, req_orig) } bool nrf_802154_request_cca_cfg_update(void) @@ -653,7 +664,8 @@ static void irq_handler_req_event(void) nrf_802154_core_receive(p_slot->data.receive.term_lvl, p_slot->data.receive.req_orig, p_slot->data.receive.notif_func, - p_slot->data.receive.notif_abort); + p_slot->data.receive.notif_abort, + p_slot->data.receive.id); break; case REQ_TYPE_TRANSMIT: @@ -695,7 +707,8 @@ static void irq_handler_req_event(void) break; case REQ_TYPE_CHANNEL_UPDATE: - *(p_slot->data.channel_update.p_result) = nrf_802154_core_channel_update(); + *(p_slot->data.channel_update.p_result) = + nrf_802154_core_channel_update(p_slot->data.channel_update.req_orig); break; case REQ_TYPE_CCA_CFG_UPDATE: diff --git a/drivers/nrf_802154/driver/src/nrf_802154_trx.c b/drivers/nrf_802154/driver/src/nrf_802154_trx.c index aa6375d..a31e0f8 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_trx.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_trx.c @@ -244,7 +244,8 @@ static void nrf_radio_reset(void) nrf_radio_power_set(NRF_RADIO, true); nrf_802154_log_global_event(NRF_802154_LOG_VERBOSITY_LOW, - NRF_802154_LOG_GLOBAL_EVENT_ID_RADIO_RESET, 0U); + NRF_802154_LOG_GLOBAL_EVENT_ID_RADIO_RESET, + 0U); nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW); } @@ -605,7 +606,8 @@ void nrf_802154_trx_disable(void) m_trx_state = TRX_STATE_DISABLED; nrf_802154_log_global_event(NRF_802154_LOG_VERBOSITY_LOW, - NRF_802154_LOG_GLOBAL_EVENT_ID_RADIO_RESET, 0U); + NRF_802154_LOG_GLOBAL_EVENT_ID_RADIO_RESET, + 0U); } else { @@ -2040,7 +2042,8 @@ static void txframe_finish_disable_ints(void) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH); - nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_PHYEND_MASK | + nrf_radio_int_disable(NRF_RADIO, + NRF_RADIO_INT_PHYEND_MASK | NRF_RADIO_INT_CCAIDLE_MASK | NRF_RADIO_INT_CCABUSY_MASK | NRF_RADIO_INT_ADDRESS_MASK | diff --git a/drivers/nrf_802154/driver/src/nrf_802154_trx_ppi.c b/drivers/nrf_802154/driver/src/nrf_802154_trx_ppi.c index d066506..ab53000 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_trx_ppi.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_trx_ppi.c @@ -69,7 +69,8 @@ void nrf_802154_trx_ppi_for_ramp_up_set(nrf_radio_task_t ramp_up_task, bool star // Clr event EGU (needed for nrf_802154_trx_ppi_for_ramp_up_was_triggered) nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, EGU_EVENT); - nrf_ppi_channel_and_fork_endpoint_setup(NRF_PPI, PPI_EGU_RAMP_UP, + nrf_ppi_channel_and_fork_endpoint_setup(NRF_PPI, + PPI_EGU_RAMP_UP, nrf_egu_event_address_get( NRF_802154_EGU_INSTANCE, EGU_EVENT), @@ -79,7 +80,8 @@ void nrf_802154_trx_ppi_for_ramp_up_set(nrf_radio_task_t ramp_up_task, bool star if (start_timer) { - nrf_ppi_channel_endpoint_setup(NRF_PPI, PPI_EGU_TIMER_START, + nrf_ppi_channel_endpoint_setup(NRF_PPI, + PPI_EGU_TIMER_START, nrf_egu_event_address_get(NRF_802154_EGU_INSTANCE, EGU_EVENT), nrf_timer_task_address_get(NRF_802154_TIMER_INSTANCE, diff --git a/drivers/nrf_802154/serialization/include/host/nrf_802154.h b/drivers/nrf_802154/serialization/include/host/nrf_802154.h index 3227511..1730b33 100644 --- a/drivers/nrf_802154/serialization/include/host/nrf_802154.h +++ b/drivers/nrf_802154/serialization/include/host/nrf_802154.h @@ -48,6 +48,11 @@ #include "nrf_802154_config.h" #include "nrf_802154_types.h" +/** + * @brief Reception window identifier reserved for immediate reception. + */ +#define NRF_802154_RESERVED_IMM_RX_WINDOW_ID (UINT32_MAX - 1) + /** * @brief Select the source matching algorithm. * @@ -61,6 +66,59 @@ */ void nrf_802154_src_addr_matching_method_set(nrf_802154_src_addr_match_t match_method); +/** + * @brief Adds the address of a peer node for which the provided ACK data + * is to be added to the pending bit list. + * + * The pending bit list works differently, depending on the upper layer for which the source + * address matching method is selected: + * - For Thread, @ref NRF_802154_SRC_ADDR_MATCH_THREAD + * - For Zigbee, @ref NRF_802154_SRC_ADDR_MATCH_ZIGBEE + * - For Standard-compliant, @ref NRF_802154_SRC_ADDR_MATCH_ALWAYS_1 + * For more information, see @ref nrf_802154_src_addr_match_t. + * + * The method can be set during initialization phase by calling @ref nrf_802154_src_matching_method. + * + * @param[in] p_addr Array of bytes containing the address of the node (little-endian). + * @param[in] extended If the given address is an extended MAC address or a short MAC address. + * @param[in] p_data Pointer to the buffer containing data to be set. + * @param[in] length Length of @p p_data. + * @param[in] data_type Type of data to be set. Refer to the @ref nrf_802154_ack_data_t type. + * + * @retval True Address successfully added to the list. + * @retval False Not enough memory to store this address in the list. + */ +bool nrf_802154_ack_data_set(const uint8_t * p_addr, + bool extended, + const void * p_data, + uint16_t length, + nrf_802154_ack_data_t data_type); + +/** + * @brief Removes the address of a peer node for which the ACK data is set from the pending bit list. + * + * The ACK data that was previously set for the given address is automatically removed. + * + * The pending bit list works differently, depending on the upper layer for which the source + * address matching method is selected: + * - For Thread, @ref NRF_802154_SRC_ADDR_MATCH_THREAD + * - For Zigbee, @ref NRF_802154_SRC_ADDR_MATCH_ZIGBEE + * - For Standard-compliant, @ref NRF_802154_SRC_ADDR_MATCH_ALWAYS_1 + * For more information, see @ref nrf_802154_src_addr_match_t. + * + * The method can be set during initialization phase by calling @ref nrf_802154_src_matching_method. + * + * @param[in] p_addr Array of bytes containing the address of the node (little-endian). + * @param[in] extended If the given address is an extended MAC address or a short MAC address. + * @param[in] data_type Type of data to be removed. Refer to the @ref nrf_802154_ack_data_t type. + * + * @retval True Address removed from the list. + * @retval False Address not found in the list. + */ +bool nrf_802154_ack_data_clear(const uint8_t * p_addr, + bool extended, + nrf_802154_ack_data_t data_type); + /** * @brief Enables or disables setting a pending bit in automatically transmitted ACK frames. * diff --git a/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h b/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h index caca23d..fbc73d1 100644 --- a/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h +++ b/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h @@ -131,8 +131,13 @@ extern void nrf_802154_received_timestamp_raw(uint8_t * p_data, * @brief Notifies that the reception of a frame failed. * * @param[in] error Error code that indicates the reason of the failure. + * @param[in] id Identifier of reception window the error occurred in. + * If the error is related to a delayed reception window requested through + * @ref nrf_802154_receive_at, the value of @p id equals the identifier + * of the scheduled reception window. Otherwise, the value of @p id equals + * @ref NRF_802154_RESERVED_IMM_RX_WINDOW_ID. */ -extern void nrf_802154_receive_failed(nrf_802154_rx_error_t error); +extern void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id); /** * @brief Notifies that a frame was transmitted. diff --git a/drivers/nrf_802154/serialization/include/host/nrf_802154_types.h b/drivers/nrf_802154/serialization/include/host/nrf_802154_types.h index f28cb27..8f924aa 100644 --- a/drivers/nrf_802154/serialization/include/host/nrf_802154_types.h +++ b/drivers/nrf_802154/serialization/include/host/nrf_802154_types.h @@ -89,6 +89,14 @@ typedef uint8_t nrf_802154_cca_error_t; #define NRF_802154_CCA_ERROR_ABORTED 0x01 // !< Procedure was aborted by another operation. +/** + * @brief Types of data that can be set in an ACK message. + */ +typedef uint8_t nrf_802154_ack_data_t; + +#define NRF_802154_ACK_DATA_PENDING_BIT 0x00 +#define NRF_802154_ACK_DATA_IE 0x01 + /** * @brief Methods of source address matching. * diff --git a/drivers/nrf_802154/serialization/src/include/nrf_802154_spinel_datatypes.h b/drivers/nrf_802154/serialization/src/include/nrf_802154_spinel_datatypes.h index d9019bb..52a60ed 100644 --- a/drivers/nrf_802154/serialization/src/include/nrf_802154_spinel_datatypes.h +++ b/drivers/nrf_802154/serialization/src/include/nrf_802154_spinel_datatypes.h @@ -254,6 +254,18 @@ typedef enum */ SPINEL_PROP_VENDOR_NORDIC_NRF_802154_CAPABILITIES_GET = SPINEL_PROP_VENDOR_NORDIC_NRF_802154__BEGIN + 31, + + /** + * Vendor property for nrf_802154_ack_data_set serialization. + */ + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET = + SPINEL_PROP_VENDOR_NORDIC_NRF_802154__BEGIN + 32, + + /** + * Vendor property for nrf_802154_ack_data_clear serialization. + */ + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR = + SPINEL_PROP_VENDOR_NORDIC_NRF_802154__BEGIN + 33, } spinel_prop_vendor_key_t; /** @@ -424,7 +436,8 @@ typedef enum * @brief Spinel data type description for nrf_802154_receive_failed */ #define SPINEL_DATATYPE_NRF_802154_RECEIVE_FAILED \ - SPINEL_DATATYPE_UINT8_S /* error */ \ + SPINEL_DATATYPE_UINT8_S /* error */ \ + SPINEL_DATATYPE_UINT32_S /* id */ /** * @brief Spinel data type description for nrf_802154_tx_ack_started @@ -489,6 +502,35 @@ typedef enum */ #define SPINEL_DATATYPE_NRF_802154_SRC_ADDR_MATCHING_METHOD_SET SPINEL_DATATYPE_UINT8_S +/** + * @brief Spinel data type desription for nrf_802154_ack_data_set. + * + * SPINEL_DATATYPE_ARRAY_S encoding is not implemented, SPINEL_DATATYPE_DATA_S has to be used instead. + */ +#define SPINEL_DATATYPE_NRF_802154_ACK_DATA_SET \ + SPINEL_DATATYPE_DATA_WLEN_S /* Address */ \ + SPINEL_DATATYPE_DATA_WLEN_S /* Data to be set */ \ + SPINEL_DATATYPE_UINT8_S /* Type of the data */ \ + +/** + * @brief Spinel data type desription for nrf_802154_ack_data_set return value. + */ +#define SPINEL_DATATYPE_NRF_802154_ACK_DATA_SET_RET SPINEL_DATATYPE_BOOL_S + +/** + * @brief Spinel data type desription for nrf_802154_ack_data_clear. + * + * SPINEL_DATATYPE_ARRAY_S encoding is not implemented, SPINEL_DATATYPE_DATA_S has to be used instead. + */ +#define SPINEL_DATATYPE_NRF_802154_ACK_DATA_CLEAR \ + SPINEL_DATATYPE_DATA_WLEN_S /* Address */ \ + SPINEL_DATATYPE_UINT8_S /* Type of the data */ + +/** + * @brief Spinel data type desription for nrf_802154_ack_data_clear return value. + */ +#define SPINEL_DATATYPE_NRF_802154_ACK_DATA_CLEAR_RET SPINEL_DATATYPE_BOOL_S + /** * @brief Spinel data type description for nrf_802154_transmit_csma_ca_raw. */ diff --git a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c index 48f5b2c..88435e1 100644 --- a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c +++ b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c @@ -502,6 +502,82 @@ bail: SERIALIZATION_ERROR_RAISE_IF_FAILED(error); } +bool nrf_802154_ack_data_set(const uint8_t * p_addr, + bool extended, + const void * p_data, + uint16_t length, + nrf_802154_ack_data_t data_type) +{ + nrf_802154_ser_err_t res; + bool ack_data_set_res = false; + + SERIALIZATION_ERROR_INIT(error); + + NRF_802154_SPINEL_LOG_BANNER_CALLING(); + NRF_802154_SPINEL_LOG_BUFF(p_addr, extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE); + NRF_802154_SPINEL_LOG_VAR_NAMED("%s", (extended ? "true" : "false"), "extended"); + + nrf_802154_spinel_response_notifier_lock_before_request( + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET); + + res = nrf_802154_spinel_send_cmd_prop_value_set( + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET, + SPINEL_DATATYPE_NRF_802154_ACK_DATA_SET, + p_addr, + extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE, + p_data, + length, + data_type); + + SERIALIZATION_ERROR_CHECK(res, error, bail); + + res = net_generic_bool_response_await(&ack_data_set_res, + CONFIG_NRF_802154_SER_DEFAULT_RESPONSE_TIMEOUT); + + SERIALIZATION_ERROR_CHECK(res, error, bail); + +bail: + SERIALIZATION_ERROR_RAISE_IF_FAILED(error); + + return ack_data_set_res; +} + +bool nrf_802154_ack_data_clear(const uint8_t * p_addr, + bool extended, + nrf_802154_ack_data_t data_type) +{ + nrf_802154_ser_err_t res; + bool ack_data_clear_res = false; + + SERIALIZATION_ERROR_INIT(error); + + NRF_802154_SPINEL_LOG_BANNER_CALLING(); + NRF_802154_SPINEL_LOG_BUFF(p_addr, extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE); + NRF_802154_SPINEL_LOG_VAR_NAMED("%s", (extended ? "true" : "false"), "extended"); + + nrf_802154_spinel_response_notifier_lock_before_request( + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR); + + res = nrf_802154_spinel_send_cmd_prop_value_set( + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR, + SPINEL_DATATYPE_NRF_802154_ACK_DATA_CLEAR, + p_addr, + extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE, + data_type); + + SERIALIZATION_ERROR_CHECK(res, error, bail); + + res = net_generic_bool_response_await(&ack_data_clear_res, + CONFIG_NRF_802154_SER_DEFAULT_RESPONSE_TIMEOUT); + + SERIALIZATION_ERROR_CHECK(res, error, bail); + +bail: + SERIALIZATION_ERROR_RAISE_IF_FAILED(error); + + return ack_data_clear_res; +} + void nrf_802154_auto_pending_bit_set(bool enabled) { nrf_802154_ser_err_t res; @@ -535,7 +611,7 @@ bool nrf_802154_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended) SERIALIZATION_ERROR_INIT(error); NRF_802154_SPINEL_LOG_BANNER_CALLING(); - NRF_802154_SPINEL_LOG_BUFF(p_addr, extended ? 8 : 2); + NRF_802154_SPINEL_LOG_BUFF(p_addr, extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE); NRF_802154_SPINEL_LOG_VAR_NAMED("%s", (extended ? "true" : "false"), "extended"); nrf_802154_spinel_response_notifier_lock_before_request( @@ -545,7 +621,7 @@ bool nrf_802154_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended) SPINEL_PROP_VENDOR_NORDIC_NRF_802154_PENDING_BIT_FOR_ADDR_SET, SPINEL_DATATYPE_NRF_802154_PENDING_BIT_FOR_ADDR_SET, p_addr, - extended ? 8 : 2); + extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE); SERIALIZATION_ERROR_CHECK(res, error, bail); @@ -568,7 +644,7 @@ bool nrf_802154_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended SERIALIZATION_ERROR_INIT(error); NRF_802154_SPINEL_LOG_BANNER_CALLING(); - NRF_802154_SPINEL_LOG_BUFF(p_addr, extended ? 8 : 2); + NRF_802154_SPINEL_LOG_BUFF(p_addr, extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE); NRF_802154_SPINEL_LOG_VAR_NAMED("%s", (extended ? "true" : "false"), "extended"); nrf_802154_spinel_response_notifier_lock_before_request( @@ -578,7 +654,7 @@ bool nrf_802154_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended SPINEL_PROP_VENDOR_NORDIC_NRF_802154_PENDING_BIT_FOR_ADDR_CLEAR, SPINEL_DATATYPE_NRF_802154_PENDING_BIT_FOR_ADDR_CLEAR, p_addr, - extended ? 8 : 2); + extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE); SERIALIZATION_ERROR_CHECK(res, error, bail); diff --git a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_app.c b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_app.c index 92e799c..20be930 100644 --- a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_app.c +++ b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_app.c @@ -221,19 +221,21 @@ static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_receive_failed( const void * p_property_data, size_t property_data_len) { - uint8_t error; + uint8_t error; + uint32_t id; spinel_ssize_t siz = spinel_datatype_unpack(p_property_data, property_data_len, SPINEL_DATATYPE_NRF_802154_RECEIVE_FAILED, - &error); + &error, + &id); if (siz < 0) { return NRF_802154_SERIALIZATION_ERROR_DECODING_FAILURE; } - nrf_802154_receive_failed(error); + nrf_802154_receive_failed(error, id); return NRF_802154_SERIALIZATION_ERROR_OK; } @@ -514,6 +516,10 @@ nrf_802154_ser_err_t nrf_802154_spinel_decode_cmd_prop_value_is( // fall through case SPINEL_PROP_VENDOR_NORDIC_NRF_802154_PENDING_BIT_FOR_ADDR_CLEAR: // fall through + case SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET: + // fall through + case SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR: + // fall through case SPINEL_PROP_VENDOR_NORDIC_NRF_802154_TRANSMIT_RAW: nrf_802154_spinel_response_notifier_property_notify(property, p_property_data, @@ -594,9 +600,10 @@ __WEAK void nrf_802154_received_timestamp_raw(uint8_t * p_data, // Intentionally empty } -__WEAK void nrf_802154_receive_failed(nrf_802154_rx_error_t error) +__WEAK void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { (void)error; + (void)id; // Intentionally empty } diff --git a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c index 4f02905..db3d7f6 100644 --- a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c +++ b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c @@ -399,11 +399,11 @@ static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_pending_bit_for_addr_s return NRF_802154_SERIALIZATION_ERROR_DECODING_FAILURE; } - if (addr_len == 8) + if (addr_len == EXTENDED_ADDRESS_SIZE) { extended = true; } - else if (addr_len == 2) + else if (addr_len == SHORT_ADDRESS_SIZE) { extended = false; } @@ -448,11 +448,11 @@ static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_pending_bit_for_addr_c return NRF_802154_SERIALIZATION_ERROR_DECODING_FAILURE; } - if (addr_len == 8) + if (addr_len == EXTENDED_ADDRESS_SIZE) { extended = true; } - else if (addr_len == 2) + else if (addr_len == SHORT_ADDRESS_SIZE) { extended = false; } @@ -539,6 +539,115 @@ static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_src_addr_matching_meth return nrf_802154_spinel_send_prop_last_status_is(SPINEL_STATUS_OK); } +/** + * @brief Decode and dispatch SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET. + * + * @param[in] p_property_data Pointer to a buffer that contains data to be decoded. + * @param[in] property_data_len Size of the @ref p_data buffer. + * + */ +static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_ack_data_set( + const void * p_property_data, + size_t property_data_len) +{ + void * p_addr; + size_t addr_len; + void * p_data; + size_t length; + nrf_802154_ack_data_t data_type; + spinel_ssize_t siz; + bool extended; + + siz = spinel_datatype_unpack(p_property_data, + property_data_len, + SPINEL_DATATYPE_NRF_802154_ACK_DATA_SET, + &p_addr, + &addr_len, + &p_data, + &length, + &data_type); + + if (siz < 0) + { + return NRF_802154_SERIALIZATION_ERROR_DECODING_FAILURE; + } + + if (addr_len == EXTENDED_ADDRESS_SIZE) + { + extended = true; + } + else if (addr_len == SHORT_ADDRESS_SIZE) + { + extended = false; + } + else + { + return NRF_802154_SERIALIZATION_ERROR_REQUEST_INVALID; + } + + bool ack_data_set_res = nrf_802154_ack_data_set( + (const uint8_t *)p_addr, + extended, + (const void *)p_data, + (uint16_t)length, + data_type); + + return nrf_802154_spinel_send_cmd_prop_value_is( + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET, + SPINEL_DATATYPE_NRF_802154_ACK_DATA_SET_RET, + ack_data_set_res); +} + +/** + * @brief Decode and dispatch SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR. + * + * @param[in] p_property_data Pointer to a buffer that contains data to be decoded. + * @param[in] property_data_len Size of the @ref p_data buffer. + * + */ +static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_ack_data_clear( + const void * p_property_data, + size_t property_data_len) +{ + const uint8_t * p_addr; + size_t addr_len; + bool extended; + nrf_802154_ack_data_t data_type; + spinel_ssize_t siz; + + siz = spinel_datatype_unpack(p_property_data, + property_data_len, + SPINEL_DATATYPE_NRF_802154_ACK_DATA_CLEAR, + &p_addr, + &addr_len, + &data_type); + + if (siz < 0) + { + return NRF_802154_SERIALIZATION_ERROR_DECODING_FAILURE; + } + + if (addr_len == EXTENDED_ADDRESS_SIZE) + { + extended = true; + } + else if (addr_len == SHORT_ADDRESS_SIZE) + { + extended = false; + } + else + { + return NRF_802154_SERIALIZATION_ERROR_REQUEST_INVALID; + } + + bool ack_data_clear_res = nrf_802154_ack_data_clear(p_addr, extended, data_type); + + return nrf_802154_spinel_send_cmd_prop_value_is( + SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR, + SPINEL_DATATYPE_NRF_802154_ACK_DATA_CLEAR_RET, + ack_data_clear_res); +} + /** * @brief Decode and dispatch SPINEL_DATATYPE_NRF_802154_TRANSMIT_CSMA_CA_RAW. * @@ -864,6 +973,14 @@ nrf_802154_ser_err_t nrf_802154_spinel_decode_cmd_prop_value_set(const void * p_ return spinel_decode_prop_nrf_802154_capabilities_get(p_property_data, property_data_len); + case SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_SET: + return spinel_decode_prop_nrf_802154_ack_data_set(p_property_data, + property_data_len); + + case SPINEL_PROP_VENDOR_NORDIC_NRF_802154_ACK_DATA_CLEAR: + return spinel_decode_prop_nrf_802154_ack_data_clear(p_property_data, + property_data_len); + default: NRF_802154_SPINEL_LOG_RAW("Unsupported property: %s(%u)\n", spinel_prop_key_to_cstr(property), diff --git a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_net.c b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_net.c index 133a272..c488aff 100644 --- a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_net.c +++ b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_net.c @@ -253,7 +253,7 @@ bail: return; } -void nrf_802154_receive_failed(nrf_802154_rx_error_t error) +void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { nrf_802154_ser_err_t res; @@ -269,7 +269,8 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error) res = nrf_802154_spinel_send_cmd_prop_value_is( SPINEL_PROP_VENDOR_NORDIC_NRF_802154_RECEIVE_FAILED, SPINEL_DATATYPE_NRF_802154_RECEIVE_FAILED, - error); + error, + id); SERIALIZATION_ERROR_CHECK(res, ser_error, bail); diff --git a/drivers/nrf_802154/sl/include/rsch/nrf_802154_rsch.h b/drivers/nrf_802154/sl/include/rsch/nrf_802154_rsch.h index f5f4758..fd60e39 100644 --- a/drivers/nrf_802154/sl/include/rsch/nrf_802154_rsch.h +++ b/drivers/nrf_802154/sl/include/rsch/nrf_802154_rsch.h @@ -61,6 +61,35 @@ extern "C" { * granted access to the RADIO peripheral. */ +/** + * @brief Maximum number of DTX delayed timeslots that can be scheduled simultaneously. + */ +#ifndef NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS +#define NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS 1 +#endif + +/** + * @brief Maximum number of DRX delayed timeslots that can be scheduled simultaneously. + */ +#ifndef NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS +#define NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS 2 +#endif + +/** + * @brief Maximum number of CSMA/CA delayed timeslots that can be scheduled simultaneously. + */ +#ifndef NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS +#define NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS 1 +#endif + +/** + * @brief Number of available slots for all delayed timeslots. + */ +#define NRF_802154_RSCH_DLY_TS_SLOTS \ + NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS + \ + NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS + \ + NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS + /** * @brief List of the preconditions that have to be met before any radio activity. */ @@ -88,16 +117,19 @@ typedef enum } rsch_prio_t; /** - * @brief Enumeration of the delayed timeslot IDs. + * @brief Enumeration of the delayed timeslot operation types. */ typedef enum { - RSCH_DLY_TX, ///< Timeslot for delayed TX operation. - RSCH_DLY_RX, ///< Timeslot for delayed RX operation. - RSCH_DLY_CSMACA, ///< Timeslot for CSMA/CA operation. + RSCH_DLY_TS_OP_DTX, ///< Timeslot for delayed TX operation. + RSCH_DLY_TS_OP_DRX, ///< Timeslot for delayed RX operation. + RSCH_DLY_TS_OP_CSMACA, ///< Timeslot for CSMA/CA operation. +} rsch_dly_ts_op_t; - RSCH_DLY_TS_NUM, ///< Number of delayed timeslots. -} rsch_dly_ts_id_t; +/** + * @brief Identifier of a delayed timeslot. + */ +typedef uint32_t rsch_dly_ts_id_t; /** * @brief Enumeration of the precondition requesting strategies. @@ -121,6 +153,8 @@ typedef enum /** * @brief Function pointer used for notifying about delayed timeslot start. + * + * @param[in] dly_ts_id Identifier of the started delayed timeslot. */ typedef void (* rsch_dly_ts_started_callback_t)(rsch_dly_ts_id_t dly_ts_id); @@ -132,9 +166,10 @@ typedef struct uint32_t t0; ///< Base time of the timestamp of the timeslot start, in microseconds. uint32_t dt; ///< Time delta between @p t0 and the timestamp of the timeslot start, in microseconds. rsch_prio_t prio; ///< Priority level required for the delayed timeslot. - rsch_dly_ts_id_t id; ///< ID of the requested timeslot. + rsch_dly_ts_op_t op; ///< Operation to be performed in the requested timeslot. rsch_dly_ts_type_t type; ///< Type of the requested timeslot. rsch_dly_ts_started_callback_t started_callback; ///< Callback called when delayed timeslot starts. + rsch_dly_ts_id_t id; ///< Identifier of the timeslot provided by its owner. Its value must be unique, to unambigously map to an active slot. } rsch_dly_ts_param_t; /** @@ -200,12 +235,26 @@ bool nrf_802154_rsch_timeslot_request(uint32_t length_us); * the timeslot is supposed to start and how long it is to last. When the requested timeslot starts, * @p p_dly_ts_param->started_callback is called. * + * For a given type of operation to be performed in the delayed timeslot, @p p_dly_ts_param->op, + * there's a limited number of delayed timeslots that can be scheduled at the same time: + * - for delayed transmissions it's @ref NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS; + * - for delayed receptions it's @ref NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS; + * - for CSMA/CA it's @ref NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS. + * + * If the API user requests more delayed timeslots with given @p p_dly_ts_param->op than specified + * by these constants, the request will fail unconditionally. It also implies that there can only + * be as many delayed timeslots scheduled simultaneously in total as the sum of these constants. + * + * @note Every call to this function must be paired with a call to + * @ref nrf_802154_rsch_delayed_timeslot_cancel so that the assigned slot becomes + * available for future requests. + * * @note @p p_dly_ts_param->started_callback can be delayed and it is up to * the called module to check the delay and decide if it causes any issues. * * @note The time parameters use the same units that are used in the Timer Scheduler module. * - * @param[in] p_dly_ts_param Parameters of the requested delayed timeslot. + * @param[in] p_dly_ts_param Parameters of the requested delayed timeslot. * * @retval true Requested timeslot has been scheduled. * @retval false Requested timeslot cannot be scheduled and will not be granted. @@ -215,7 +264,8 @@ bool nrf_802154_rsch_delayed_timeslot_request(const rsch_dly_ts_param_t * p_dly_ /** * @brief Cancels a requested future timeslot. * - * @param[in] dly_ts_id ID of the requested timeslot. + * @param[in] dly_ts_id Identifier of the requested timeslot. If the provided value does not refer + * to any scheduled delayed timeslot, the function returns false. * * @retval true Scheduled timeslot has been cancelled. * @retval false No scheduled timeslot has been requested (nothing to cancel). @@ -225,7 +275,9 @@ bool nrf_802154_rsch_delayed_timeslot_cancel(rsch_dly_ts_id_t dly_ts_id); /** * @brief Updates priority of a requested delayed timeslot. * - * @param[in] dly_ts_id ID of the requested timeslot. + * @param[in] dly_ts_id Identifier of the requested timeslot. If the provided value does not + * refer to any scheduled or active delayed timeslot, the function + * returns false. * @param[in] dly_ts_prio Priority to be assigned to the requested timeslot. * * @retval true Scheduled timeslot's priority has been updated.