drivers: nrf_802154: Update the IEEE 802.15.4 component

This commit updates the nRF 802.15.4 radio driver to feature
the latest changes.

sdk-nrf-802154 commit: 9307dc01053c7f4ddb3081984a72a6d454ec8681

Signed-off-by: Jedrzej Ciupis <jedrzej.ciupis@nordicsemi.no>
This commit is contained in:
Jedrzej Ciupis 2021-04-21 09:23:30 +02:00 committed by Carles Cufí
parent fc301b9758
commit 9bd5891e3c
28 changed files with 1231 additions and 376 deletions

View File

@ -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

View File

@ -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.

View File

@ -43,126 +43,129 @@
#include <stdint.h>
#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
{

View File

@ -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;
}

View File

@ -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))
{

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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)

View File

@ -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();
}

View File

@ -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

View File

@ -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.

View File

@ -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,

View File

@ -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:

View File

@ -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.

View File

@ -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)

View File

@ -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:

View File

@ -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 |

View File

@ -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,

View File

@ -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.
*

View File

@ -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.

View File

@ -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.
*

View File

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

View File

@ -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);

View File

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

View File

@ -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),

View File

@ -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);

View File

@ -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.