From 50ee0d864e5acb2ea64777713f5e2db69e224690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Mi=C5=9B?= Date: Tue, 27 Jun 2017 17:51:58 +0200 Subject: [PATCH] [nRF52840] Update radio driver (#1941) --- examples/platforms/nrf52840/radio.c | 5 +- .../drivers/radio/nrf_drv_radio802154.c | 25 +- .../drivers/radio/nrf_drv_radio802154.h | 21 +- .../nrf_drv_radio802154_ack_pending_bit.c | 14 +- .../drivers/radio/nrf_drv_radio802154_const.h | 71 ++-- .../nrf_drv_radio802154_critical_section.c | 19 +- .../drivers/radio/nrf_drv_radio802154_debug.c | 12 + .../drivers/radio/nrf_drv_radio802154_debug.h | 97 +++--- .../drivers/radio/nrf_drv_radio802154_fsm.c | 325 ++++++++++++------ .../drivers/radio/nrf_drv_radio802154_fsm.h | 3 +- .../drivers/radio/nrf_drv_radio802154_pib.c | 18 +- .../radio/nrf_drv_radio802154_request.h | 3 +- .../nrf_drv_radio802154_request_direct.c | 4 +- .../radio/nrf_drv_radio802154_request_swi.c | 55 ++- .../radio/nrf_drv_radio802154_rx_buffer.c | 2 +- .../drivers/radio/nrf_drv_radio802154_swi.c | 186 +++++++--- .../drivers/radio/nrf_drv_radio802154_swi.h | 2 + .../raal/softdevice/nrf_raal_softdevice.c | 31 +- 18 files changed, 598 insertions(+), 295 deletions(-) diff --git a/examples/platforms/nrf52840/radio.c b/examples/platforms/nrf52840/radio.c index ff0e39931..e531399b7 100644 --- a/examples/platforms/nrf52840/radio.c +++ b/examples/platforms/nrf52840/radio.c @@ -324,7 +324,7 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) aFrame->mPsdu[-1] = aFrame->mLength; - if (nrf_drv_radio802154_transmit(&aFrame->mPsdu[-1], aFrame->mChannel, aFrame->mPower)) + if (nrf_drv_radio802154_transmit(&aFrame->mPsdu[-1], aFrame->mChannel, aFrame->mPower, true)) { clearPendingEvents(); } @@ -637,7 +637,8 @@ void nrf_drv_radio802154_busy_channel(void) void nrf_drv_radio802154_energy_detected(int8_t result) { - sEnergyDetected = result; + // TODO: Correct RSSI calculation after lab tests. + sEnergyDetected = 94 - result; setPendingEvent(kPendingEventEnergyDetected); } diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c index 03c37b13f..e9f9454a8 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c @@ -165,12 +165,12 @@ void nrf_drv_radio802154_receive(uint8_t channel) nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RECEIVE); } -bool nrf_drv_radio802154_transmit(const uint8_t * p_data, uint8_t channel, int8_t power) +bool nrf_drv_radio802154_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca) { bool result; nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_TRANSMIT); - result = nrf_drv_radio802154_request_transmit(p_data, channel, power); + result = nrf_drv_radio802154_request_transmit(p_data, channel, power, cca); nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_TRANSMIT); return result; @@ -246,23 +246,38 @@ void nrf_drv_radio802154_pending_bit_for_addr_reset(bool extended) nrf_drv_radio802154_ack_pending_bit_for_addr_reset(extended); } +__WEAK void nrf_drv_radio802154_rx_started(void) +{ + // Intentionally empty +} + __WEAK void nrf_drv_radio802154_received(uint8_t * p_data, int8_t power, int8_t lqi) { - (void) p_data; (void) power; (void) lqi; + + nrf_drv_radio802154_buffer_free(p_data); +} + +__WEAK void nrf_drv_radio802154_tx_started(void) +{ + // Intentionally empty } __WEAK void nrf_drv_radio802154_transmitted(uint8_t * p_ack, int8_t power, int8_t lqi) { - (void) p_ack; (void) power; (void) lqi; + + if (p_ack != NULL) + { + nrf_drv_radio802154_buffer_free(p_ack); + } } __WEAK void nrf_drv_radio802154_busy_channel(void) { - + // Intentionally empty } __WEAK void nrf_drv_radio802154_energy_detected(int8_t result) diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h index bbad02655..78ce280d5 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h @@ -176,11 +176,12 @@ void nrf_drv_radio802154_receive(uint8_t channel); * @param[in] channel Channel number on which radio will transmit given frame. * @param[in] power Transmission power [dBm]. Given value is rounded up to nearest permitted * value. + * @param[in] cca If the driver should perform CCA procedure before transmission. * * @return true If the transmission procedure was scheduled. * @return false If the driver could not schedule the transmission procedure. */ -bool nrf_drv_radio802154_transmit(const uint8_t *p_data, uint8_t channel, int8_t power); +bool nrf_drv_radio802154_transmit(const uint8_t *p_data, uint8_t channel, int8_t power, bool cca); /** * @brief Change radio state to Energy Detection. @@ -206,6 +207,15 @@ bool nrf_drv_radio802154_energy_detection(uint8_t channel, uint32_t time_us); * @section Calls to higher layer. */ +/** + * @brief Notify that receiving frame has started. + * + * @note It is possible the frame is dropped during receive procedure and + * @sa nrf_drv_radio802154_received won't be called. + * @note This function should be very short to prevent dropping frames by the driver. + */ +extern void nrf_drv_radio802154_rx_started(void); + /** * @brief Notify that frame was received. * @@ -221,6 +231,15 @@ bool nrf_drv_radio802154_energy_detection(uint8_t channel, uint32_t time_us); */ extern void nrf_drv_radio802154_received(uint8_t * p_data, int8_t power, int8_t lqi); +/** + * @brief Notify that transmitting frame has started. + * + * @note It is possible that transmit procedure is interrupted and + * @sa nrf_drv_radio802154_transmitted won't be called. + * @note This function should be very short to prevent dropping frames by the driver. + */ +extern void nrf_drv_radio802154_tx_started(void); + /** * @brief Notify that frame was transmitted. * diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_ack_pending_bit.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_ack_pending_bit.c index f0200c39b..b0c59e17b 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_ack_pending_bit.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_ack_pending_bit.c @@ -45,20 +45,20 @@ #include "hal/nrf_radio.h" -// Maximum number of Short Addresses of nodes for which there is pending data in buffer. +/// Maximum number of Short Addresses of nodes for which there is pending data in buffer. #define NUM_PENDING_SHORT_ADDRESSES RADIO_PENDING_SHORT_ADDRESSES -// Maximum number of Extended Addresses of nodes for which there is pending data in buffer. +/// Maximum number of Extended Addresses of nodes for which there is pending data in buffer. #define NUM_PENDING_EXTENDED_ADDRESSES RADIO_PENDING_EXTENDED_ADDRESSES -// Value used to mark Short Address as unused. +/// Value used to mark Short Address as unused. #define UNUSED_PENDING_SHORT_ADDRESS ((uint8_t [SHORT_ADDRESS_SIZE]) {0xff, 0xff}) -// Value used to mark Extended Address as unused. +/// Value used to mark Extended Address as unused. #define UNUSED_PENDING_EXTENDED_ADDRESS ((uint8_t [EXTENDED_ADDRESS_SIZE]) {0}) -// If pending bit in ACK frame should be set to valid or default value. +/// If pending bit in ACK frame should be set to valid or default value. static bool m_setting_pending_bit_enabled; -// Array of Short Addresses of nodes for which there is pending data in the buffer. +/// Array of Short Addresses of nodes for which there is pending data in the buffer. static uint8_t m_pending_short[NUM_PENDING_SHORT_ADDRESSES][SHORT_ADDRESS_SIZE]; -// Array of Extended Addresses of nodes for which there is pending data in the buffer. +/// Array of Extended Addresses of nodes for which there is pending data in the buffer. static uint8_t m_pending_extended[NUM_PENDING_EXTENDED_ADDRESSES][EXTENDED_ADDRESS_SIZE]; void nrf_drv_radio802154_ack_pending_bit_init(void) diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h index b505c6ba7..ad0cfd998 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h @@ -36,47 +36,40 @@ #ifndef NRF_DRV_RADIO802154_CONST_H_ #define NRF_DRV_RADIO802154_CONST_H_ -#define ACK_HEADER_WITH_PENDING 0x12 // First byte of ACK frame containing pending bit -#define ACK_HEADER_WITHOUT_PENDING 0x02 // First byte of ACK frame without pending bit +#define ACK_HEADER_WITH_PENDING 0x12 ///< First byte of ACK frame containing pending bit +#define ACK_HEADER_WITHOUT_PENDING 0x02 ///< First byte of ACK frame without pending bit -#define ACK_LENGTH 5 // Length of ACK frame -#define ACK_REQUEST_BIT (1 << 5) // Ack request bit -#define ACK_REQUEST_OFFSET 1 // Byte containing Ack request bit (+1 for frame length byte) -#define DEST_ADDR_TYPE_EXTENDED 0x0c // Bits containing extended destination address type -#define DEST_ADDR_TYPE_MASK 0x0c // Mask of bits containing destination address type -#define DEST_ADDR_TYPE_OFFSET 2 // Byte containing destination address type (+1 for frame length byte) -#define DEST_ADDR_TYPE_SHORT 0x08 // Bits containing short destination address type -#define DEST_ADDR_OFFSET 5 // Offset of destination address in Data frame -#define DSN_OFFSET 3 // Byte containing DSN value (+1 for frame length byte) -#define FRAME_PENDING_BIT (1 << 4) // Pending bit -#define FRAME_PENDING_OFFSET 1 // Byte containing pending bit (+1 for frame length byte) -#define FRAME_TYPE_ACK 0x02 // Bits containing ACK frame type -#define FRAME_TYPE_BEACON 0x00 // Bits containing Beacon frame type -#define FRAME_TYPE_COMMAND 0x03 // Bits containing Command frame type -#define FRAME_TYPE_DATA 0x01 // Bits containing Data frame type -#define FRAME_TYPE_MASK 0x07 // Mask of bits containing frame type -#define FRAME_TYPE_OFFSET 1 // Byte containing frame type bits (+1 for frame length byte) -#define PAN_ID_COMPR_OFFSET 1 // Byte containing Pan Id compression bit (+1 for frame length byte) -#define PAN_ID_COMPR_MASK 0x40 // Pan Id compression bit -#define PAN_ID_OFFSET 3 // Offset of Pan Id in Data frame -#define SRC_ADDR_TYPE_EXTENDED 0xc0 // Bits containing extended source address type -#define SRC_ADDR_TYPE_MASK 0xc0 // Mask of bits containing source address type -#define SRC_ADDR_TYPE_OFFSET 2 // Byte containing source address type (+1 for frame length byte) -#define SRC_ADDR_TYPE_SHORT 0x80 // Bits containing short source address type -#define SRC_ADDR_OFFSET_SHORT_DST 8 // Offset of source address in Data frame if destination address is short -#define SRC_ADDR_OFFSET_EXTENDED_DST 14 // Offset of source address in Data frame if destination address is extended +#define ACK_LENGTH 5 ///< Length of ACK frame +#define ACK_REQUEST_BIT (1 << 5) ///< Ack request bit +#define ACK_REQUEST_OFFSET 1 ///< Byte containing Ack request bit (+1 for frame length byte) +#define DEST_ADDR_TYPE_EXTENDED 0x0c ///< Bits containing extended destination address type +#define DEST_ADDR_TYPE_MASK 0x0c ///< Mask of bits containing destination address type +#define DEST_ADDR_TYPE_OFFSET 2 ///< Byte containing destination address type (+1 for frame length byte) +#define DEST_ADDR_TYPE_SHORT 0x08 ///< Bits containing short destination address type +#define DEST_ADDR_OFFSET 5 ///< Offset of destination address in Data frame +#define DSN_OFFSET 3 ///< Byte containing DSN value (+1 for frame length byte) +#define FRAME_PENDING_BIT (1 << 4) ///< Pending bit +#define FRAME_PENDING_OFFSET 1 ///< Byte containing pending bit (+1 for frame length byte) +#define FRAME_TYPE_ACK 0x02 ///< Bits containing ACK frame type +#define FRAME_TYPE_BEACON 0x00 ///< Bits containing Beacon frame type +#define FRAME_TYPE_COMMAND 0x03 ///< Bits containing Command frame type +#define FRAME_TYPE_DATA 0x01 ///< Bits containing Data frame type +#define FRAME_TYPE_MASK 0x07 ///< Mask of bits containing frame type +#define FRAME_TYPE_OFFSET 1 ///< Byte containing frame type bits (+1 for frame length byte) +#define PAN_ID_COMPR_OFFSET 1 ///< Byte containing Pan Id compression bit (+1 for frame length byte) +#define PAN_ID_COMPR_MASK 0x40 ///< Pan Id compression bit +#define PAN_ID_OFFSET 3 ///< Offset of Pan Id in Data frame +#define SRC_ADDR_TYPE_EXTENDED 0xc0 ///< Bits containing extended source address type +#define SRC_ADDR_TYPE_MASK 0xc0 ///< Mask of bits containing source address type +#define SRC_ADDR_TYPE_OFFSET 2 ///< Byte containing source address type (+1 for frame length byte) +#define SRC_ADDR_TYPE_SHORT 0x80 ///< Bits containing short source address type +#define SRC_ADDR_OFFSET_SHORT_DST 8 ///< Offset of source address in Data frame if destination address is short +#define SRC_ADDR_OFFSET_EXTENDED_DST 14 ///< Offset of source address in Data frame if destination address is extended -#define CRC_LENGTH 2 // Length of CRC in 802.15.4 frames [bytes] -#define CRC_POLYNOMIAL 0x011021 // Polynomial used for CRC calculation in 802.15.4 frames - -#define MHMU_MASK 0xff000700 // Mask of known bytes in ACK packet -#define MHMU_PATTERN 0x00000200 // Values of known bytes in ACK packet -#define MHMU_PATTERN_DSN_OFFSET 24 // Offset of DSN in MHMU_PATTER [bits] - -#define PAN_ID_SIZE 2 // Size of Pan Id -#define SHORT_ADDRESS_SIZE 2 // Size of Short Mac Address -#define EXTENDED_ADDRESS_SIZE 8 // Size of Extended Mac Address -#define MAX_PACKET_SIZE 127 // Maximal size of radio packet +#define PAN_ID_SIZE 2 ///< Size of Pan Id +#define SHORT_ADDRESS_SIZE 2 ///< Size of Short Mac Address +#define EXTENDED_ADDRESS_SIZE 8 ///< Size of Extended Mac Address +#define MAX_PACKET_SIZE 127 ///< Maximal size of radio packet #endif // NRD_DRV_RADIO802154_CONST_H_ diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_critical_section.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_critical_section.c index dae2ebcd7..e101c16e2 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_critical_section.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_critical_section.c @@ -48,22 +48,27 @@ #if RAAL_SOFTDEVICE // When Softdevice is selected as arbiter critical sections should not be nested. -static volatile bool m_in_critical_section; +#define PREVENT_NESTED_CRIT_SECTIONS 1 #endif // RAAL_SOFTDEVICE +#if PREVENT_NESTED_CRIT_SECTIONS +/// Flag indicating if the driver entered critical section. +static volatile bool m_in_critical_section; +#endif // PREVENT_NESTED_CRIT_SECTIONS + void nrf_drv_radio802154_critical_section_enter(void) { nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_CRIT_SECT_ENTER); radio_state_t state; -#if RAAL_SOFTDEVICE +#if PREVENT_NESTED_CRIT_SECTIONS __disable_irq(); __DSB(); __ISB(); assert(!m_in_critical_section); m_in_critical_section = true; -#endif // RAAL_SOFTDEVICE +#endif // PREVENT_NESTED_CRIT_SECTIONS nrf_raal_critical_section_enter(); @@ -79,9 +84,9 @@ void nrf_drv_radio802154_critical_section_enter(void) #endif // !RAAL_SOFTDEVICE } -#if RAAL_SOFTDEVICE +#if PREVENT_NESTED_CRIT_SECTIONS __enable_irq(); -#endif // RAAL_SOFTDEVICE +#endif // PREVENT_NESTED_CRIT_SECTIONS nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_CRIT_SECT_ENTER); } @@ -90,10 +95,10 @@ void nrf_drv_radio802154_critical_section_exit(void) { nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_CRIT_SECT_EXIT); -#if RAAL_SOFTDEVICE +#if PREVENT_NESTED_CRIT_SECTIONS assert(m_in_critical_section); m_in_critical_section = false; -#endif // RAAL_SOFTDEVICE +#endif // PREVENT_NESTED_CRIT_SECTIONS radio_state_t state; diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.c index 2c18fdce7..778219f02 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.c @@ -44,11 +44,16 @@ #include "nrf.h" #if ENABLE_DEBUG_LOG +/// Buffer used to store debug log messages. volatile uint32_t nrf_drv_radio802154_debug_log_buffer[NRF_DRV_RADIO802154_DEBUG_LOG_BUFFER_LEN]; +/// Index of the log buffer pointing to the element that should be filled with next log message. volatile uint32_t nrf_drv_radio802154_debug_log_ptr = 0; #endif #if ENABLE_DEBUG_GPIO +/** + * @brief Initialize PPI to toggle GPIO pins on radio events. + */ static void radio_event_gpio_toggle_init(void) { nrf_gpio_cfg_output(PIN_DBG_RADIO_EVT_END); @@ -82,6 +87,9 @@ static void radio_event_gpio_toggle_init(void) nrf_ppi_channel_enable(NRF_PPI_CHANNEL4); } +/** + * @brief Initialize GPIO to set it simulated arbiter events. + */ static void raal_simulator_gpio_init(void) { #if RAAL_SIMULATOR @@ -90,6 +98,10 @@ static void raal_simulator_gpio_init(void) #endif } +/** + * @brief Initialize PPI to toggle GPIO pins on Softdevice events. Initialize GPIO to set it + * according to Softdevice arbiter client events. + */ static void raal_softdevice_event_gpio_toggle_init(void) { #if RAAL_SOFTDEVICE diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h index b9c4056ec..bf69b605d 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h @@ -44,61 +44,64 @@ extern "C" { #define NRF_DRV_RADIO802154_DEBUG_LOG_BUFFER_LEN 1024 -#define EVENT_TRACE_ENTER 0x0001UL -#define EVENT_TRACE_EXIT 0x0002UL -#define EVENT_MUTEX_LOCK 0x0003UL -#define EVENT_MUTEX_UNLOCK 0x0004UL -#define EVENT_SET_STATE 0x0005UL -#define EVENT_RADIO_RESET 0x0006UL +#define EVENT_TRACE_ENTER 0x0001UL +#define EVENT_TRACE_EXIT 0x0002UL +#define EVENT_MUTEX_LOCK 0x0003UL +#define EVENT_MUTEX_UNLOCK 0x0004UL +#define EVENT_SET_STATE 0x0005UL +#define EVENT_RADIO_RESET 0x0006UL -#define FUNCTION_SLEEP 0x0001UL -#define FUNCTION_RECEIVE 0x0002UL -#define FUNCTION_TRANSMIT 0x0003UL -#define FUNCTION_ENERGY_DETECTION 0x0004UL -#define FUNCTION_BUFFER_FREE 0x0005UL +#define FUNCTION_SLEEP 0x0001UL +#define FUNCTION_RECEIVE 0x0002UL +#define FUNCTION_TRANSMIT 0x0003UL +#define FUNCTION_ENERGY_DETECTION 0x0004UL +#define FUNCTION_BUFFER_FREE 0x0005UL -#define FUNCTION_IRQ_HANDLER 0x0100UL -#define FUNCTION_EVENT_FRAMESTART 0x0101UL -#define FUNCTION_EVENT_BCMATCH 0x0102UL -#define FUNCTION_EVENT_END 0x0103UL -#define FUNCTION_EVENT_DISABLED 0x0104UL -#define FUNCTION_EVENT_READY 0x0105UL -#define FUNCTION_EVENT_CCAIDLE 0x0106UL -#define FUNCTION_EVENT_CCABUSY 0x0107UL -#define FUNCTION_EVENT_EDEND 0x0108UL +#define FUNCTION_IRQ_HANDLER 0x0100UL +#define FUNCTION_EVENT_FRAMESTART 0x0101UL +#define FUNCTION_EVENT_BCMATCH 0x0102UL +#define FUNCTION_EVENT_END 0x0103UL +#define FUNCTION_EVENT_DISABLED 0x0104UL +#define FUNCTION_EVENT_READY 0x0105UL +#define FUNCTION_EVENT_CCAIDLE 0x0106UL +#define FUNCTION_EVENT_CCABUSY 0x0107UL +#define FUNCTION_EVENT_EDEND 0x0108UL -#define FUNCTION_AUTO_ACK_ABORT 0x0201UL -#define FUNCTION_TIMESLOT_STARTED 0x0202UL -#define FUNCTION_TIMESLOT_ENDED 0x0203UL -#define FUNCTION_CRIT_SECT_ENTER 0x0204UL -#define FUNCTION_CRIT_SECT_EXIT 0x0205UL +#define FUNCTION_AUTO_ACK_ABORT 0x0201UL +#define FUNCTION_TIMESLOT_STARTED 0x0202UL +#define FUNCTION_TIMESLOT_ENDED 0x0203UL +#define FUNCTION_CRIT_SECT_ENTER 0x0204UL +#define FUNCTION_CRIT_SECT_EXIT 0x0205UL -#define FUNCTION_RAAL_CRIT_SECT_ENTER 0x0301UL -#define FUNCTION_RAAL_CRIT_SECT_EXIT 0x0302UL -#define FUNCTION_RAAL_CONTINUOUS_ENTER 0x0303UL -#define FUNCTION_RAAL_CONTINUOUS_EXIT 0x0304UL +#define FUNCTION_RAAL_CRIT_SECT_ENTER 0x0301UL +#define FUNCTION_RAAL_CRIT_SECT_EXIT 0x0302UL +#define FUNCTION_RAAL_CONTINUOUS_ENTER 0x0303UL +#define FUNCTION_RAAL_CONTINUOUS_EXIT 0x0304UL -#define FUNCTION_RAAL_SIG_HANDLER 0x0400UL -#define FUNCTION_RAAL_SIG_EVENT_START 0x0401UL -#define FUNCTION_RAAL_SIG_EVENT_MARGIN 0x0402UL -#define FUNCTION_RAAL_SIG_EVENT_EXTEND 0x0403UL -#define FUNCTION_RAAL_SIG_EVENT_ENDED 0x0404UL +#define FUNCTION_RAAL_SIG_HANDLER 0x0400UL +#define FUNCTION_RAAL_SIG_EVENT_START 0x0401UL +#define FUNCTION_RAAL_SIG_EVENT_MARGIN 0x0402UL +#define FUNCTION_RAAL_SIG_EVENT_EXTEND 0x0403UL +#define FUNCTION_RAAL_SIG_EVENT_ENDED 0x0404UL +#define FUNCTION_RAAL_SIG_EVENT_RADIO 0x0405UL +#define FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS 0x0406UL +#define FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL 0x0407UL -#define PIN_DBG_RADIO_EVT_END 11 -#define PIN_DBG_RADIO_EVT_DISABLED 12 -#define PIN_DBG_RADIO_EVT_READY 13 -#define PIN_DBG_RADIO_EVT_FRAMESTART 14 -#define PIN_DBG_RADIO_EVT_EDEND 25 +#define PIN_DBG_RADIO_EVT_END 11 +#define PIN_DBG_RADIO_EVT_DISABLED 12 +#define PIN_DBG_RADIO_EVT_READY 13 +#define PIN_DBG_RADIO_EVT_FRAMESTART 14 +#define PIN_DBG_RADIO_EVT_EDEND 25 -#define PIN_DBG_TIMESLOT_ACTIVE 3 -#define PIN_DBG_TIMESLOT_EXTEND_REQ 4 -#define PIN_DBG_TIMESLOT_SESSION_IDLE 16 -#define PIN_DBG_TIMESLOT_RADIO_IRQ 28 -#define PIN_DBG_TIMESLOT_FAILED 29 -#define PIN_DBG_TIMESLOT_BLOCKED 30 -#define PIN_DBG_RAAL_CRITICAL_SECTION 15 +#define PIN_DBG_TIMESLOT_ACTIVE 3 +#define PIN_DBG_TIMESLOT_EXTEND_REQ 4 +#define PIN_DBG_TIMESLOT_SESSION_IDLE 16 +#define PIN_DBG_TIMESLOT_RADIO_IRQ 28 +#define PIN_DBG_TIMESLOT_FAILED 29 +#define PIN_DBG_TIMESLOT_BLOCKED 30 +#define PIN_DBG_RAAL_CRITICAL_SECTION 15 -#define PIN_DBG_RTC0_EVT_REM 31 +#define PIN_DBG_RTC0_EVT_REM 31 #if ENABLE_DEBUG_LOG extern volatile uint32_t nrf_drv_radio802154_debug_log_buffer[ diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c index 879821f6b..0455ba228 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c @@ -41,6 +41,7 @@ #include #include +#include "nrf_drv_radio802154.h" #include "nrf_drv_radio802154_ack_pending_bit.h" #include "nrf_drv_radio802154_config.h" #include "nrf_drv_radio802154_const.h" @@ -53,46 +54,62 @@ #include "hal/nrf_radio.h" #include "raal/nrf_raal_api.h" +/// Value set to SHORTS register when no shorts should be enabled. #define SHORTS_IDLE 0 +/// Value set to SHORTS register when receiver is waiting for incoming frame. #define SHORTS_RX_INITIAL (NRF_RADIO_SHORT_END_DISABLE_MASK | NRF_RADIO_SHORT_DISABLED_TXEN_MASK | \ NRF_RADIO_SHORT_FRAMESTART_BCSTART_MASK) +/// Value set to SHORTS register when receiver started receiving a frame. #define SHORTS_RX_FOLLOWING (NRF_RADIO_SHORT_END_DISABLE_MASK | NRF_RADIO_SHORT_READY_START_MASK | \ NRF_RADIO_SHORT_FRAMESTART_BCSTART_MASK) +/// Value set to SHORTS register when received frame should be acknowledged. #define SHORTS_TX_ACK (NRF_RADIO_SHORT_END_DISABLE_MASK) #if RADIO_SHORT_CCAIDLE_TXEN +/// Value set to SHORTS register during transmission of a frame #define SHORTS_TX_FRAME (NRF_RADIO_SHORT_END_DISABLE_MASK | NRF_RADIO_SHORT_READY_START_MASK | \ NRF_RADIO_SHORT_CCAIDLE_TXEN_MASK) #else +/// Value set to SHORTS register during transmission of a frame #define SHORTS_TX_FRAME (NRF_RADIO_SHORT_END_DISABLE_MASK | NRF_RADIO_SHORT_READY_START_MASK) #endif -// Delay before sending ACK (10sym = 192uS) +/// Delay before sending ACK (12sym = 192uS) #define TIFS_ACK_US 192 -// Delay before first check of received frame: 16 bits is MAC Frame Control field. +/// Delay before first check of received frame: 16 bits is MAC Frame Control field. #define BCC_INIT (2 * 8) -// Delay before second check of received frame if destination address is short. +/// Delay before second check of received frame if destination address is short. #define BCC_SHORT_ADDR ((DEST_ADDR_OFFSET + SHORT_ADDRESS_SIZE) * 8) -// Delay before second check of received frame if destination address is extended. +/// Delay before second check of received frame if destination address is extended. #define BCC_EXTENDED_ADDR ((DEST_ADDR_OFFSET + EXTENDED_ADDRESS_SIZE) * 8) -// Duration of single iteration of Energy Detection procedure +/// Duration of single iteration of Energy Detection procedure #define ED_ITER_DURATION 128U -// Overhead of hardware preparation for ED procedure (aTurnaroundTime) [number of iterations] +/// Overhead of hardware preparation for ED procedure (aTurnaroundTime) [number of iterations] #define ED_ITERS_OVERHEAD 2U -// Get LQI of given received packet. If CRC is calculated by hardware LQI is included instead of CRC -// in the frame. Length is stored in byte with index 0; CRC is 2 last bytes. +#define CRC_LENGTH 2 ///< Length of CRC in 802.15.4 frames [bytes] +#define CRC_POLYNOMIAL 0x011021 ///< Polynomial used for CRC calculation in 802.15.4 frames + +#define MHMU_MASK 0xff000700 ///< Mask of known bytes in ACK packet +#define MHMU_PATTERN 0x00000200 ///< Values of known bytes in ACK packet +#define MHMU_PATTERN_DSN_OFFSET 24 ///< Offset of DSN in MHMU_PATTER [bits] + +/** Get LQI of given received packet. If CRC is calculated by hardware LQI is included instead of CRC + * in the frame. Length is stored in byte with index 0; CRC is 2 last bytes. + */ #define RX_FRAME_LQI(psdu) ((psdu)[(psdu)[0] - 1]) #if RADIO_RX_BUFFERS > 1 -static rx_buffer_t * mp_current_rx_buffer; // Pointer to currently used receive buffer. +/// Pointer to currently used receive buffer. +static rx_buffer_t * mp_current_rx_buffer; #else -static rx_buffer_t * const mp_current_rx_buffer = &nrf_drv_radio802154_rx_buffers[0]; // If there is only one buffer use const pointer. +/// If there is only one buffer use const pointer to the receive buffer. +static rx_buffer_t * const mp_current_rx_buffer = &nrf_drv_radio802154_rx_buffers[0]; #endif #if defined ( __GNUC__ ) -// Ack frame buffer (EasyDMA cannot address whole RAM. Place buffer in the special section.) +/// Ack frame buffer (EasyDMA cannot address whole RAM. Place buffer in the special section.) static uint8_t m_ack_psdu[ACK_LENGTH + 1] __attribute__ ((section ("nrf_radio_buffer.m_ack_psdu"))); @@ -103,27 +120,26 @@ static uint8_t m_ack_psdu[ACK_LENGTH + 1]; #endif -static const uint8_t * mp_tx_data; // Pointer to data to transmit. -static uint32_t m_ed_time_left; // Remaining time of current energy detection procedure [us]. -static uint8_t m_ed_result; // Result of current energy detection procedure. +static const uint8_t * mp_tx_data; ///< Pointer to data to transmit. +static uint32_t m_ed_time_left; ///< Remaining time of current energy detection procedure [us]. +static uint8_t m_ed_result; ///< Result of current energy detection procedure. -static volatile radio_state_t m_state = RADIO_STATE_SLEEP; // State of the radio driver +static volatile radio_state_t m_state = RADIO_STATE_SLEEP; ///< State of the radio driver typedef struct { - bool prevent_ack :1; // If frame being received is not destined to this node (promiscuous mode). + bool prevent_ack :1; ///< If frame being received is not destined to this node (promiscuous mode). } nrf_radio802154_flags_t; -static nrf_radio802154_flags_t m_flags; +static nrf_radio802154_flags_t m_flags; ///< Flags used to store current driver state. -// Mutex preventing race condition. -static volatile uint8_t m_mutex; +static volatile uint8_t m_mutex; ///< Mutex preventing race condition. /*************************************************************************************************** * @section Mutex **************************************************************************************************/ -// Lock mutex to prevent run conditions. +/// Lock mutex to prevent race conditions. static bool mutex_lock(void) { do @@ -149,7 +165,7 @@ static bool mutex_lock(void) return true; } -// Unlock mutex. +/// Unlock mutex. static void mutex_unlock(void) { assert(m_state == RADIO_STATE_SLEEP || @@ -166,7 +182,10 @@ static void mutex_unlock(void) * @section FSM common operations **************************************************************************************************/ -// Set radio state +/** Set driver state. + * + * @param[in] state Driver state to set. + */ static inline void state_set(radio_state_t state) { m_state = state; @@ -174,7 +193,7 @@ static inline void state_set(radio_state_t state) nrf_drv_radio802154_log(EVENT_SET_STATE, (uint32_t)state); } -// Set state to SLEEP, exit timeslot, stop clock, unlock mutex. +/// Common procedure when the driver enters SLEEP state. static inline void sleep_start(void) { state_set(RADIO_STATE_SLEEP); @@ -182,24 +201,33 @@ static inline void sleep_start(void) mutex_unlock(); } -// Start receiver to wait for frames. +/// Start receiver to wait for frames. static inline void rx_start(void) { nrf_radio_packet_ptr_set(mp_current_rx_buffer->psdu); nrf_radio_task_trigger(NRF_RADIO_TASK_START); +} + +/// Start receiver to wait for frame that can be acknowledged. +static inline void rx_frame_start(void) +{ + rx_start(); // Just after starting receiving to receive buffer set packet pointer to ACK frame that can be // sent automatically. nrf_radio_packet_ptr_set(m_ack_psdu); } -// Get result of last RSSI measurement +/** Get result of last RSSI measurement. + * + * @returns Result of last RSSI measurement [dBm]. + */ static inline int8_t rssi_last_measurement_get(void) { return -((int8_t)nrf_radio_rssi_sample_get()); } -// Notify MAC layer that a frame was received. +/// Notify MAC layer that a frame was received. static inline void received_frame_notify(void) { mp_current_rx_buffer->free = false; @@ -208,6 +236,10 @@ static inline void received_frame_notify(void) RX_FRAME_LQI(mp_current_rx_buffer->psdu)); // lqi } +/** Set currently used rx buffer to given address. + * + * @param[in] p_rx_buffer Pointer to receive buffer that should be used now. + */ static inline void rx_buffer_in_use_set(rx_buffer_t * p_rx_buffer) { #if RADIO_RX_BUFFERS > 1 @@ -222,19 +254,30 @@ static inline void rx_buffer_in_use_set(rx_buffer_t * p_rx_buffer) * @section Radio parameters calculators **************************************************************************************************/ -// Set radio channel +/** Set radio channel + * + * @param[in] channel Channel number to set (11-26). + */ static void channel_set(uint8_t channel) { + assert(channel >= 11 && channel <= 26); + nrf_radio_frequency_set(5 + (5 * (channel - 11))); } -// Get radio channel +/** Get radio channel. + * + * @returns Currently set channel number. + */ static uint8_t channel_get(void) { return ((nrf_radio_frequency_get() - 5) / 5) + 11; } -// Set transmit power +/** Set transmit power. + * + * @param[in] dbm Transmit power to set [dbm]. + */ static void tx_power_set(int8_t dbm) { const int8_t allowed_values[] = {-40, -20, -16, -12, -8, -4, 0, 2, 3, 4, 5, 6, 7, 8, 9}; @@ -263,21 +306,20 @@ static void tx_power_set(int8_t dbm) * @section Shorts management **************************************************************************************************/ -// Disable peripheral shorts. +/// Disable peripheral shorts. static inline void shorts_disable(void) { nrf_radio_shorts_set(SHORTS_IDLE); nrf_radio_ifs_set(0); } -// Enable peripheral shorts used during data frame transmission. +/// Enable peripheral shorts used during data frame transmission. static inline void shorts_tx_frame_set(void) { nrf_radio_shorts_set(SHORTS_TX_FRAME); } -// Enable peripheral shorts used during automatic ACK transmission. -// TIFS shorts are splitted +/// Enable peripheral shorts used in receive state to enable automatic ACK procedure. static inline void shorts_rx_initial_set(void) { nrf_radio_ifs_set(TIFS_ACK_US); @@ -286,14 +328,13 @@ static inline void shorts_rx_initial_set(void) nrf_radio_shorts_set(SHORTS_RX_INITIAL); } -// Enable peripheral shorts used during automatic ACK transmission. +/// Enable peripheral shorts used during automatic ACK transmission. static inline void shorts_rx_following_set(void) { nrf_radio_shorts_set(SHORTS_RX_FOLLOWING); } -// Disable peripheral shorts used during automatic ACK transmission if ACK is transmitted -// (short disabling transmitter persists). +/// Disable peripheral shorts used during automatic ACK transmission when ACK is being transmitted static inline void shorts_tx_ack_set(void) { // If ACK is sent END_DISABLE short should persist to disable transmitter automatically. @@ -306,14 +347,14 @@ static inline void shorts_tx_ack_set(void) * @section ACK transmission management **************************************************************************************************/ -// Set valid sequence number in ACK frame. +/// Set valid sequence number in ACK frame. static inline void ack_prepare(void) { // Copy sequence number from received frame to ACK frame. m_ack_psdu[DSN_OFFSET] = mp_current_rx_buffer->psdu[DSN_OFFSET]; } -// Set pending bit in ACK frame. +/// Set pending bit in ACK frame. static inline void ack_pending_bit_set(void) { m_ack_psdu[FRAME_PENDING_OFFSET] = ACK_HEADER_WITH_PENDING; @@ -324,13 +365,22 @@ static inline void ack_pending_bit_set(void) } } -// Check if ACK is requested in given frame. +/** Check if ACK is requested in given frame. + * + * @param[in] p_frame Pointer to a frame to check. + * + * @retval true ACK is requested in given frame. + * @retval false ACK is not requested in given frame. + */ static inline bool ack_is_requested(const uint8_t * p_frame) { return (p_frame[ACK_REQUEST_OFFSET] & ACK_REQUEST_BIT) ? true : false; } -// Abort automatic sending ACK. +/** Abort automatic ACK procedure. + * + * @param[in] state_to_set Driver state that shall be set after the procedure is aborted. + */ static void auto_ack_abort(radio_state_t state_to_set) { nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_AUTO_ACK_ABORT); @@ -367,6 +417,7 @@ static void auto_ack_abort(radio_state_t state_to_set) * @section ACK receiving management **************************************************************************************************/ +/// Enable hardware ACK matching accelerator. static inline void ack_matching_enable(void) { nrf_radio_event_clear(NRF_RADIO_EVENT_MHRMATCH); @@ -375,18 +426,25 @@ static inline void ack_matching_enable(void) MHMU_PATTERN_DSN_OFFSET)); } +/// Disable hardware ACK matching accelerator. static inline void ack_matching_disable(void) { nrf_radio_mhmu_search_pattern_set(0); nrf_radio_event_clear(NRF_RADIO_EVENT_MHRMATCH); } +/** Check if hardware ACK matching accelerator matched ACK pattern in received frame. + * + * @retval true ACK matching accelerator matched ACK pattern. + * @retval false ACK matching accelerator did not match ACK pattern. + */ static inline bool ack_is_matched(void) { return (nrf_radio_event_get(NRF_RADIO_EVENT_MHRMATCH)) && (nrf_radio_crc_status_get() == NRF_RADIO_CRC_STATUS_OK); } +/// Start receiver to receive data after receiving of ACK frame. static inline void frame_rx_start_after_ack_rx(void) { ack_matching_disable(); @@ -398,7 +456,7 @@ static inline void frame_rx_start_after_ack_rx(void) * @section RADIO peripheral management **************************************************************************************************/ -// Initialize radio peripheral +/// Initialize radio peripheral static void nrf_radio_init(void) { nrf_radio_mode_set(NRF_RADIO_MODE_IEEE802154_250KBIT); @@ -434,7 +492,7 @@ static void nrf_radio_init(void) nrf_radio_int_enable(NRF_RADIO_INT_EDEND_MASK); } -// Reset radio peripheral +/// Reset radio peripheral static void nrf_radio_reset(void) { nrf_radio_power_set(false); @@ -443,7 +501,7 @@ static void nrf_radio_reset(void) nrf_drv_radio802154_log(EVENT_RADIO_RESET, 0); } -// Initialize interrupts for radio peripheral +/// Initialize interrupts for radio peripheral static void irq_init(void) { NVIC_SetPriority(RADIO_IRQn, RADIO_IRQ_PRIORITY); @@ -451,7 +509,7 @@ static void irq_init(void) NVIC_EnableIRQ(RADIO_IRQn); } -// Deinitialize interrupts for radio peripheral +/// Deinitialize interrupts for radio peripheral static void irq_deinit(void) { NVIC_DisableIRQ(RADIO_IRQn); @@ -467,6 +525,17 @@ static void irq_deinit(void) * @section Energy detection management **************************************************************************************************/ +/** Setup next iteration of energy detection procedure. + * + * Energy detection procedure is performed in iterations to make sure it is performed for requested + * time regardless radio arbitration. + * + * @param[in] Remaining time of energy detection procedure [us]. + * + * @retval true Next iteration of energy detection procedure will be performed now. + * @retval false Next iteration of energy detection procedure will not be performed now due to + * ending timeslot. + */ static inline bool ed_iter_setup(uint32_t time_us) { uint32_t us_left_in_timeslot = nrf_raal_timeslot_us_left_get(); @@ -592,7 +661,7 @@ void nrf_raal_timeslot_ended(void) * @section RADIO interrupt handler **************************************************************************************************/ -// When the radio starts receiving a frame it generates this event. +/// This event is handled when the radio starts receiving a frame. static inline void irq_framestart_state_waiting_rx_frame(void) { if (mutex_lock()) @@ -611,6 +680,8 @@ static inline void irq_framestart_state_waiting_rx_frame(void) else { nrf_radio_task_trigger(NRF_RADIO_TASK_RSSISTART); + + nrf_drv_radio802154_rx_started(); } } @@ -641,7 +712,7 @@ static inline void irq_framestart_state_waiting_rx_frame(void) } } -// When the radio starts receiving an ACK frame this event is generated. +/// This event is handled when the radio starts receiving an ACK frame. static inline void irq_framestart_state_rx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -660,7 +731,13 @@ static inline void irq_framestart_state_rx_ack(void) } } -// This event is handled when MHR was received +/// This event is handled when the radio starts transmitting a requested frame. +static inline void irq_framestart_state_tx_frame(void) +{ + nrf_drv_radio802154_tx_started(); +} + +/// This event is handled when MHR is received static inline void irq_bcmatch_mhr(void) { // Verify if time slot for receiving is available. @@ -726,7 +803,7 @@ static inline void irq_bcmatch_mhr(void) } } -// This event is generated when destination address fields are received +/// This event is generated when destination address fields are received. static inline void irq_bcmatch_address(void) { if (nrf_drv_radio802154_pib_dest_addr_matches(mp_current_rx_buffer->psdu)) @@ -750,9 +827,9 @@ static inline void irq_bcmatch_address(void) } } -// This event is generated two times during frame reception: -// When MHR is received -// When destination address fields are received +/** This event is generated twice during frame reception: + * when MHR is received and when destination address fields are received. + */ static inline void irq_bcmatch_state_rx_header(void) { assert(nrf_radio_shorts_get() == SHORTS_RX_INITIAL); @@ -795,8 +872,9 @@ static inline void irq_bcmatch_state_rx_header(void) } } -// This event is generated when radio receives invalid frame with length set to 0 or started -// receiving a frame after other procedure locked mutex. +/** This event is generated when radio receives invalid frame with length set to 0 or started + * receiving a frame after other procedure locked mutex. + */ static inline void irq_end_state_waiting_rx_frame(void) { // Radio state is not asserted here. It can be a lot of states due to shorts. @@ -816,7 +894,7 @@ static inline void irq_end_state_waiting_rx_frame(void) } } -// This event is generated if frame being received is shorter than expected MAC header length. +/// This event is generated if frame being received is shorter than expected MAC header length. static inline void irq_end_state_rx_header(void) { // Frame ended before header was received. @@ -824,7 +902,7 @@ static inline void irq_end_state_rx_header(void) nrf_radio_event_clear(NRF_RADIO_EVENT_READY); } -// This event is generated when radio peripheral ends receiving of a complete frame. +/// This event is generated when radio peripheral ends receiving of a complete frame. static inline void irq_end_state_rx_frame(void) { assert(nrf_radio_shorts_get() == SHORTS_RX_INITIAL); @@ -871,7 +949,7 @@ static inline void irq_end_state_rx_frame(void) } } -// This event is generated when the radio ends transmission of ACK frame. +/// This event is generated when the radio ends transmission of ACK frame. static inline void irq_end_state_tx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_TX_ACK); @@ -883,13 +961,15 @@ static inline void irq_end_state_tx_ack(void) // Receiver is enabled by shorts. } -// This could happen at the beginning of transmission procedure (the procedure already has disabled shorts). +/** This event may occur at the beginning of transmission procedure (the procedure already has + * disabled shorts). + */ static inline void irq_end_state_cca(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); } -// This event is generated when the radio ends transmission of a frame. +/// This event is generated when the radio ends transmission of a frame. static inline void irq_end_state_tx_frame(void) { shorts_disable(); @@ -911,7 +991,7 @@ static inline void irq_end_state_tx_frame(void) // Task DISABLE is triggered by shorts. } -// This event is generated when the radio ends receiving of ACK frame. +/// This event is generated when the radio ends receiving of ACK frame. static inline void irq_end_state_rx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -932,7 +1012,7 @@ static inline void irq_end_state_rx_ack(void) frame_rx_start_after_ack_rx(); } -// This event is generated when radio peripheral disables in order to enter sleep state. +/// This event is generated when radio peripheral disables in order to enter sleep state. static inline void irq_disabled_state_disabling(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -940,8 +1020,10 @@ static inline void irq_disabled_state_disabling(void) sleep_start(); } -// This event is generated when the driver enters receive state. The radio is now disabled and the -// driver starts enabling receiver. +/** This event is generated when the driver enters receive state. + * + * The radio is now disabled and the driver starts enabling receiver. + */ static inline void irq_disabled_state_waiting_rx_frame(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -964,8 +1046,25 @@ static inline void irq_disabled_state_waiting_rx_frame(void) nrf_radio_event_clear(NRF_RADIO_EVENT_DISABLED); } -// This event is generated during automatic ACK transmission: receiver is disabled and transmitter -// is being enabled by shorts. +/** This event is generated in case both END and DISABLED events are notified between + * checking if END event was notified and checking if DISABLED event was notified. + * + * In this invalid and rare case just drop received frame. + */ +static inline void irq_disabled_state_rx_frame(void) +{ + assert(nrf_radio_event_get(NRF_RADIO_EVENT_END)); + assert(nrf_radio_shorts_get() == SHORTS_RX_INITIAL); + + auto_ack_abort(RADIO_STATE_WAITING_RX_FRAME); + nrf_radio_event_clear(NRF_RADIO_EVENT_END); + nrf_radio_event_clear(NRF_RADIO_EVENT_READY); +} + +/** This event is generated during automatic ACK transmission. + * + * Receiver is disabled and transmitter is being enabled by shorts. + */ static inline void irq_disabled_state_tx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_RX_INITIAL); @@ -984,8 +1083,10 @@ static inline void irq_disabled_state_tx_ack(void) } } -// This event is generated before CCA procedure starts. The radio is disabled and the drivers -// enables receiver in order to start CCA procedure. +/** This event is generated before CCA procedure starts. + * + * The radio is disabled and the drivers enables receiver in order to start CCA procedure. + */ static inline void irq_disabled_state_cca(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -993,18 +1094,25 @@ static inline void irq_disabled_state_cca(void) nrf_radio_task_trigger(NRF_RADIO_TASK_RXEN); } -// This event is generated before transmission of a frame starts. The radio is disabled and -// enabling transmitter is requested by shorts or by the driver. +/** This event is generated before transmission of a frame starts. + * + * The radio is disabled and enabling transmitter is requested by shorts or by the driver. + */ static inline void irq_disabled_state_tx_frame(void) { + if (nrf_radio_state_get() == NRF_RADIO_STATE_DISABLED) + { + shorts_tx_frame_set(); + nrf_radio_task_trigger(NRF_RADIO_TASK_TXEN); + } + assert(nrf_radio_shorts_get() == SHORTS_TX_FRAME); -#if !RADIO_SHORT_CCAIDLE_TXEN - nrf_radio_task_trigger(NRF_RADIO_TASK_TXEN); -#endif } -// This event is generated when radio is disabled after transmission of a frame with ACK request. -// The driver enables receiver to receive ACK frame. +/** This event is generated when radio is disabled after transmission of a frame with ACK request. + * + * The driver enables receiver to receive ACK frame. + */ static inline void irq_disabled_state_rx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1017,8 +1125,11 @@ static inline void irq_disabled_state_rx_ack(void) } } -// This event is generated before energy detection procedure. The radio is disabled and the driver -// enables receiver in order to start energy detection procedure. +/** This event is generated before energy detection procedure. + * + * The radio is disabled and the driver enables receiver in order to start energy detection + * procedure. + */ static inline void irq_disabled_state_ed(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1026,8 +1137,10 @@ static inline void irq_disabled_state_ed(void) nrf_radio_task_trigger(NRF_RADIO_TASK_RXEN); } -// This event is generated when receiver is ready to start receiving a frame. Driver checks if -// buffer for a frame is available and starts receiver. +/** This event is generated when receiver is ready to start receiving a frame. + * + * Driver checks if buffer for a frame is available and starts receiver. + */ static inline void irq_ready_state_waiting_rx_frame(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1038,23 +1151,27 @@ static inline void irq_ready_state_waiting_rx_frame(void) if (mutex_lock()) { shorts_rx_initial_set(); - rx_start(); + rx_frame_start(); mutex_unlock(); } } } -// This event is generated when transmitter is ready to transmit ACK frame. Transmission is started -// by shorts. The driver sets shorts to gracefully end transmission of ACK. +/** This event is generated when transmitter is ready to transmit ACK frame. + * + * Transmission is started by shorts. The driver sets shorts to gracefully end transmission of ACK. + */ static inline void irq_ready_state_tx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_RX_FOLLOWING); shorts_tx_ack_set(); } -// This event is generated when receiver is ready to start CCA procedure. The driver prepares for -// transmission and starts CCA procedure. +/** This event is generated when receiver is ready to start CCA procedure. + * + * The driver prepares for transmission and starts CCA procedure. + */ static inline void irq_ready_state_cca(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1066,14 +1183,16 @@ static inline void irq_ready_state_cca(void) nrf_radio_task_trigger(NRF_RADIO_TASK_CCASTART); } -// This event is generated when transmitter is ready to transmit a frame. Transmission is started by -// shorts. +/** This event is generated when transmitter is ready to transmit a frame. + * + * Transmission is started by shorts. + */ static inline void irq_ready_state_tx_frame(void) { assert(nrf_radio_shorts_get() == SHORTS_TX_FRAME); } -// This event is generated when receiver is ready to receive an ACK frame. +/// This event is generated when receiver is ready to receive an ACK frame. static inline void irq_ready_state_rx_ack(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1090,7 +1209,7 @@ static inline void irq_ready_state_rx_ack(void) } } -// This event is generated when receiver is ready to start energy detection procedure. +/// This event is generated when receiver is ready to start energy detection procedure. static inline void irq_ready_state_ed(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1099,16 +1218,17 @@ static inline void irq_ready_state_ed(void) } #if !RADIO_SHORT_CCAIDLE_TXEN -// This event is generated when CCA reports that channel is idle. +/// This event is generated when CCA reports that channel is idle. static inline void irq_ccaidle(void) { - assert (m_state == RADIO_STATE_TX_FRAME); + assert(m_state == RADIO_STATE_TX_FRAME); + assert(nrf_radio_shorts_get() == SHORTS_TX_FRAME); nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); } #endif // RADIO_SHORT_CCAIDLE_TXEN -// This event is generated when CCA reports busy channel prior to transmission. +/// This event is generated when CCA reports busy channel prior to transmission. static inline void irq_ccabusy_state_tx_frame(void) { assert(nrf_radio_shorts_get() == SHORTS_TX_FRAME); @@ -1122,7 +1242,7 @@ static inline void irq_ccabusy_state_tx_frame(void) nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); } -// This event is generated when energy detection procedure ends. +/// This event is generated when energy detection procedure ends. static inline void irq_edend(void) { assert(m_state == RADIO_STATE_ED); @@ -1148,7 +1268,7 @@ static inline void irq_edend(void) } } -// Handler of radio interrupts. +/// Handler of radio interrupts. void RADIO_IRQHandler(void) { nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_IRQ_HANDLER); @@ -1168,8 +1288,11 @@ void RADIO_IRQHandler(void) irq_framestart_state_rx_ack(); break; - case RADIO_STATE_TX_ACK: case RADIO_STATE_TX_FRAME: + irq_framestart_state_tx_frame(); + break; + + case RADIO_STATE_TX_ACK: case RADIO_STATE_CCA: // This could happen at the beginning of transmission procedure. case RADIO_STATE_WAITING_TIMESLOT: break; @@ -1267,6 +1390,11 @@ void RADIO_IRQHandler(void) irq_disabled_state_waiting_rx_frame(); break; + case RADIO_STATE_RX_HEADER: + case RADIO_STATE_RX_FRAME: + irq_disabled_state_rx_frame(); + break; + case RADIO_STATE_TX_ACK: irq_disabled_state_tx_ack(); break; @@ -1392,8 +1520,10 @@ void RADIO_IRQHandler(void) * @section FSM transition request sub-procedures **************************************************************************************************/ -// Abort transmission procedure. -// This function is called when MAC layer requests transition from transmit to receive state. +/** Abort transmission procedure. + * + * This function is called when MAC layer requests transition from transmit to receive state. + */ static inline void tx_procedure_abort(void) { shorts_disable(); @@ -1563,7 +1693,7 @@ bool nrf_drv_radio802154_fsm_receive(uint8_t channel) return result; } -bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, uint8_t channel, int8_t power) +bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca) { bool result = false; mp_tx_data = p_data; @@ -1576,9 +1706,8 @@ bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, uint8_t channel, i assert(m_state == RADIO_STATE_WAITING_RX_FRAME); channel_set(channel); - auto_ack_abort(RADIO_STATE_CCA); - assert(nrf_radio_shorts_get() == SHORTS_IDLE); + auto_ack_abort(cca ? RADIO_STATE_CCA : RADIO_STATE_TX_FRAME); tx_power_set(power); nrf_radio_packet_ptr_set(p_data); @@ -1707,7 +1836,7 @@ void nrf_drv_radio802154_fsm_notify_buffer_free(rx_buffer_t * p_buffer) shorts_rx_initial_set(); rx_buffer_in_use_set(p_buffer); - rx_start(); + rx_frame_start(); // Clear events that could have happened in critical section due to RX // ramp up. diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h index 80173ccf0..2d4f216a9 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h @@ -130,11 +130,12 @@ bool nrf_drv_radio802154_fsm_receive(uint8_t channel); * @param[in] p_data Pointer to a frame to transmit. * @param[in] channel Channel number that the radio should use to transmit the frame. * @param[in] power Transmission power. + * @param[in] cca If the driver should perform CCA procedure before transmission. * * @retval true Entering TRANSMIT state succeeded. * @retval false Entering TRANSMIT state failed (driver is performing other procedure). */ -bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, uint8_t channel, int8_t power); +bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca); /** * @brief Request transition to ENERGY_DETECTION state. diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c index 9cbca1b7f..3f8ed4dda 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c @@ -42,20 +42,20 @@ #include "nrf_drv_radio802154_const.h" -#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 typedef struct { - int8_t tx_power; // Transmit power. - uint8_t pan_id[PAN_ID_SIZE]; // Pan Id of this node. - uint8_t short_addr[SHORT_ADDRESS_SIZE]; // Short Address of this node. - uint8_t extended_addr[EXTENDED_ADDRESS_SIZE]; // Extended Address of this node. - bool promiscuous :1; // Indicating if radio is in promiscuous mode. - bool auto_ack :1; // Indicating if auto ACK procedure is enabled. - uint8_t channel :5; // Channel on which the node receives messages. + int8_t tx_power; ///< Transmit power. + uint8_t pan_id[PAN_ID_SIZE]; ///< Pan Id of this node. + uint8_t short_addr[SHORT_ADDRESS_SIZE]; ///< Short Address of this node. + uint8_t extended_addr[EXTENDED_ADDRESS_SIZE]; ///< Extended Address of this node. + bool promiscuous :1; ///< Indicating if radio is in promiscuous mode. + bool auto_ack :1; ///< Indicating if auto ACK procedure is enabled. + uint8_t channel :5; ///< Channel on which the node receives messages. } nrf_drv_radio802154_pib_data_t; -static nrf_drv_radio802154_pib_data_t m_data; +static nrf_drv_radio802154_pib_data_t m_data; ///< Buffer containing PIB data. void nrf_drv_radio802154_pib_init(void) { diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h index dbd53c646..fca55153a 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h @@ -74,11 +74,12 @@ bool nrf_drv_radio802154_request_receive(uint8_t channel); * @param[in] p_data Pointer to the frame to transmit. * @param[in] channel Channel number used to transmit the frame. * @param[in] power Transmitter power used to transmit the frame. + * @param[in] cca If the driver should perform CCA procedure before transmission. * * @retval true The driver will enter transmit state. * @retval false The driver cannot enter transmit state due to ongoing operation. */ -bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power); +bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca); /** * @brief Request entering energy detection state. diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_direct.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_direct.c index 330a3d959..8639c97fe 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_direct.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_direct.c @@ -72,12 +72,12 @@ bool nrf_drv_radio802154_request_receive(uint8_t channel) return result; } -bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power) +bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca) { bool result; nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_transmit(p_data, channel, power); + result = nrf_drv_radio802154_fsm_transmit(p_data, channel, power, cca); nrf_drv_radio802154_critical_section_exit(); return result; diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_swi.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_swi.c index 057b3d896..963c18e93 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_swi.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_swi.c @@ -37,6 +37,7 @@ #include "nrf_drv_radio802154_request.h" +#include #include #include @@ -51,12 +52,31 @@ #include #include -static bool active_verctor_priority_is_high(void) -{ - uint32_t active_vector_id = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos; - uint32_t active_priority = NVIC_GetPriority((IRQn_Type)active_vector_id); +#define CMSIS_IRQ_NUM_VECTACTIVE_DIFF 16 - return active_priority >= RADIO_NOTIFICATION_SWI_PRIORITY; +/** Check if active vector priority is high enough to call requests directly. + * + * @retval true Active vector priority is greater or equal to SWI priority. + * @retval false Active vector priority is lower than SWI priority. + */ +static bool active_vector_priority_is_high(void) +{ + uint32_t active_vector_id = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos; + IRQn_Type irq_number; + uint32_t active_priority; + + // Check if this function is called from main thread. + if (active_vector_id == 0) + { + return false; + } + + assert(active_vector_id >= CMSIS_IRQ_NUM_VECTACTIVE_DIFF); + + irq_number = (IRQn_Type)(active_vector_id - CMSIS_IRQ_NUM_VECTACTIVE_DIFF); + active_priority = NVIC_GetPriority(irq_number); + + return active_priority <= RADIO_NOTIFICATION_SWI_PRIORITY; } void nrf_drv_radio802154_request_init(void) @@ -68,7 +88,7 @@ bool nrf_drv_radio802154_request_sleep(void) { bool result = false; - if (active_verctor_priority_is_high()) + if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); result = nrf_drv_radio802154_fsm_sleep(); @@ -86,7 +106,7 @@ bool nrf_drv_radio802154_request_receive(uint8_t channel) { bool result = false; - if (active_verctor_priority_is_high()) + if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); result = nrf_drv_radio802154_fsm_receive(channel); @@ -100,19 +120,19 @@ bool nrf_drv_radio802154_request_receive(uint8_t channel) return result; } -bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power) +bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca) { bool result = false; - if (active_verctor_priority_is_high()) + if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_transmit(p_data, channel, power); + result = nrf_drv_radio802154_fsm_transmit(p_data, channel, power, cca); nrf_drv_radio802154_critical_section_exit(); } else { - nrf_drv_radio802154_swi_transmit(p_data, channel, power, &result); + nrf_drv_radio802154_swi_transmit(p_data, channel, power, cca, &result); } return result; @@ -122,7 +142,7 @@ bool nrf_drv_radio802154_request_energy_detection(uint8_t channel, uint32_t time { bool result = false; - if (active_verctor_priority_is_high()) + if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); result = nrf_drv_radio802154_fsm_energy_detection(channel, time_us); @@ -138,5 +158,14 @@ bool nrf_drv_radio802154_request_energy_detection(uint8_t channel, uint32_t time void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data) { - nrf_drv_radio802154_swi_buffer_free(p_data); + if (active_vector_priority_is_high()) + { + nrf_drv_radio802154_critical_section_enter(); + nrf_drv_radio802154_fsm_notify_buffer_free((rx_buffer_t *)p_data); + nrf_drv_radio802154_critical_section_exit(); + } + else + { + nrf_drv_radio802154_swi_buffer_free(p_data); + } } diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_rx_buffer.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_rx_buffer.c index 693db5ad0..597a804a5 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_rx_buffer.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_rx_buffer.c @@ -46,7 +46,7 @@ #if defined ( __GNUC__ ) -// Receive buffer (EasyDMA cannot address whole RAM. Place buffer in the special section.) +/// Receive buffer (EasyDMA cannot address whole RAM. Place buffer in the special section.) rx_buffer_t nrf_drv_radio802154_rx_buffers[RADIO_RX_BUFFERS] __attribute__ ((section ("nrf_radio_buffer.nrf_drv_radio802154_rx_buffers"))); diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c index b32f48e27..fbecfc320 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c @@ -48,59 +48,71 @@ #include "hal/nrf_egu.h" #include "raal/nrf_raal_api.h" -#define NTF_QUEUE_SIZE (RADIO_RX_BUFFERS + 3) // for each rx buffer, 1 for tx, 1 for channel busy, 1 for energy detection -#define REQ_QUEUE_SIZE 2 // minimal queue size +/** Size of notification queue. + * + * One slot for each receive buffer, one for transmission, one for busy channel and one for energy + * detection. + */ +#define NTF_QUEUE_SIZE (RADIO_RX_BUFFERS + 3) +/** Size of requests queue. + * + * Two is minimal queue size. It is not expected in current implementation to queue a few requests. + */ +#define REQ_QUEUE_SIZE 2 -#define SWI_EGU NRF_EGU3 -#define SWI_IRQn SWI3_EGU3_IRQn -#define SWI_IRQHandler SWI3_EGU3_IRQHandler +#define SWI_EGU NRF_EGU3 ///< Label of SWI peripheral. +#define SWI_IRQn SWI3_EGU3_IRQn ///< Symbol of SWI IRQ number. +#define SWI_IRQHandler SWI3_EGU3_IRQHandler ///< Symbol of SWI IRQ handler. -#define NTF_INT NRF_EGU_INT_TRIGGERED0 -#define NTF_TASK NRF_EGU_TASK_TRIGGER0 -#define NTF_EVENT NRF_EGU_EVENT_TRIGGERED0 +#define NTF_INT NRF_EGU_INT_TRIGGERED0 ///< Label of notification interrupt. +#define NTF_TASK NRF_EGU_TASK_TRIGGER0 ///< Label of notification task. +#define NTF_EVENT NRF_EGU_EVENT_TRIGGERED0 ///< Label of notification event. -#define TIMESLOT_EXIT_INT NRF_EGU_INT_TRIGGERED1 -#define TIMESLOT_EXIT_TASK NRF_EGU_TASK_TRIGGER1 -#define TIMESLOT_EXIT_EVENT NRF_EGU_EVENT_TRIGGERED1 +#define TIMESLOT_EXIT_INT NRF_EGU_INT_TRIGGERED1 ///< Label of timeslot exit interrupt. +#define TIMESLOT_EXIT_TASK NRF_EGU_TASK_TRIGGER1 ///< Label of timeslot exit task. +#define TIMESLOT_EXIT_EVENT NRF_EGU_EVENT_TRIGGERED1 ///< Label of timeslot exit event. -#define REQ_INT NRF_EGU_INT_TRIGGERED2 -#define REQ_TASK NRF_EGU_TASK_TRIGGER2 -#define REQ_EVENT NRF_EGU_EVENT_TRIGGERED2 +#define REQ_INT NRF_EGU_INT_TRIGGERED2 ///< Label of request interrupt. +#define REQ_TASK NRF_EGU_TASK_TRIGGER2 ///< Label of request task. +#define REQ_EVENT NRF_EGU_EVENT_TRIGGERED2 ///< Label of request event. +/// Types of notifications in notification queue. typedef enum { - NTF_TYPE_RECEIVED, - NTF_TYPE_TRANSMITTED, - NTF_TYPE_CHANNEL_BUSY, - NTF_TYPE_ENERGY_DETECTED, + NTF_TYPE_RECEIVED, ///< Frame received + NTF_TYPE_TRANSMITTED, ///< Frame transmitted + NTF_TYPE_CHANNEL_BUSY, ///< Frame transmission failure + NTF_TYPE_ENERGY_DETECTED, ///< Energy detection procedure ended } nrf_drv_radio802154_ntf_type_t; +/// Notification data in the notification queue. typedef struct { - nrf_drv_radio802154_ntf_type_t type; + nrf_drv_radio802154_ntf_type_t type; ///< Notification type. union { struct { - uint8_t * p_psdu; - int8_t power; - int8_t lqi; - } received; + uint8_t * p_psdu; ///< Pointer to received frame PSDU. + int8_t power; ///< RSSI of received frame. + int8_t lqi; ///< LQI of received frame. + } received; ///< Received frame details. struct { - uint8_t * p_psdu; - int8_t power; - int8_t lqi; - } transmitted; + uint8_t * p_psdu; ///< Pointer to received ACK PSDU or NULL. + int8_t power; ///< RSSI of received ACK or 0. + int8_t lqi; ///< LQI of received ACK or 0. + } transmitted; ///< Transmitted frame details. struct { - int8_t result; - } energy_detected; - } data; + int8_t result; ///< Energy detection result. + } energy_detected; ///< Energy detection details. + } data; ///< Notification data depending on it's type. } nrf_drv_radio802154_ntf_data_t; +/// Type of requests in request queue. typedef enum { REQ_TYPE_SLEEP, @@ -110,52 +122,60 @@ typedef enum REQ_TYPE_BUFFER_FREE, } nrf_drv_radio802154_req_type_t; +/// Request data in request queue. typedef struct { - nrf_drv_radio802154_req_type_t type; + nrf_drv_radio802154_req_type_t type; ///< Type of the request. union { struct { - bool * p_result; - } sleep; + bool * p_result; ///< Sleep request result. + } sleep; ///< Sleep request details. struct { - bool * p_result; - uint8_t channel; - } receive; + bool * p_result; ///< Receive request result. + uint8_t channel; ///< Channel to receive on. + } receive; ///< Receive request details. struct { - bool * p_result; - const uint8_t * p_data; - uint8_t channel; - int8_t power; - } transmit; + bool * p_result; ///< Transmit request result. + const uint8_t * p_data; ///< Pointer to PSDU to transmit. + uint8_t channel; ///< Channel to transmit on. + int8_t power; ///< Requested transmission power. + bool cca; ///< If CCA was requested prior to transmission. + } transmit; ///< Transmit request details. struct { - bool * p_result; - uint8_t channel; - uint32_t time_us; - } energy_detection; + bool * p_result; ///< Energy detection request result. + uint8_t channel; ///< Channel to perform energy detection on. + uint32_t time_us; ///< Requested time of energy detection procedure. + } energy_detection; ///< Energy detection request details. struct { - rx_buffer_t * p_data; - } buffer_free; - } data; + rx_buffer_t * p_data; ///< Pointer to receive buffer to free. + } buffer_free; ///< Buffer free request details. + } data; ///< Request data depending on it's type. } nrf_drv_radio802154_req_data_t; -static nrf_drv_radio802154_ntf_data_t m_ntf_queue[NTF_QUEUE_SIZE]; -static uint8_t m_ntf_r_ptr; -static uint8_t m_ntf_w_ptr; +static nrf_drv_radio802154_ntf_data_t m_ntf_queue[NTF_QUEUE_SIZE]; ///< Notification queue. +static uint8_t m_ntf_r_ptr; ///< Notification queue read index. +static uint8_t m_ntf_w_ptr; ///< Notification queue write index. -static nrf_drv_radio802154_req_data_t m_req_queue[REQ_QUEUE_SIZE]; -static uint8_t m_req_r_ptr; -static uint8_t m_req_w_ptr; +static nrf_drv_radio802154_req_data_t m_req_queue[REQ_QUEUE_SIZE]; ///< Request queue. +static uint8_t m_req_r_ptr; // Request queue read index. +static uint8_t m_req_w_ptr; // Request queue write index. +/** + * Increment given index for any queue. + * + * @param[inout] p_ptr Index to increment. + * @param[in] queue_size Number of elements in the queue. + */ static void queue_ptr_increment(uint8_t * p_ptr, uint8_t queue_size) { if (++(*p_ptr) >= queue_size) @@ -164,6 +184,16 @@ static void queue_ptr_increment(uint8_t * p_ptr, uint8_t queue_size) } } +/** + * Check if given queue is full. + * + * @param[in] r_ptr Read index associated with given queue. + * @param[in] w_ptr Write index associated with given queue. + * @param[in] queue_size Number of elements in the queue. + * + * @retval true Given queue is full. + * @retval false Given queue is not full. + */ static bool queue_is_full(uint8_t r_ptr, uint8_t w_ptr, uint8_t queue_size) { if (w_ptr == (r_ptr - 1)) @@ -179,36 +209,79 @@ static bool queue_is_full(uint8_t r_ptr, uint8_t w_ptr, uint8_t queue_size) return false; } +/** + * Check if given queue is empty. + * + * @param[in] r_ptr Read index associated with given queue. + * @param[in] w_ptr Write index associated with given queue. + * + * @retval true Given queue is empty. + * @retval false Given queue is not empty. + */ static bool queue_is_empty(uint8_t r_ptr, uint8_t w_ptr) { return (r_ptr == w_ptr); } +/** + * Increment given index associated with notification queue. + * + * @param[inout] p_ptr Pointer to the index to increment. + */ static void ntf_queue_ptr_increment(uint8_t * p_ptr) { queue_ptr_increment(p_ptr, NTF_QUEUE_SIZE); } +/** + * Check if notification queue is full. + * + * @retval true Notification queue is full. + * @retval false Notification queue is not full. + */ static bool ntf_queue_is_full(void) { return queue_is_full(m_ntf_r_ptr, m_ntf_w_ptr, NTF_QUEUE_SIZE); } +/** + * Check if notification queue is empty. + * + * @retval true Notification queue is empty. + * @retval false Notification queue is not empty. + */ static bool ntf_queue_is_empty(void) { return queue_is_empty(m_ntf_r_ptr, m_ntf_w_ptr); } +/** + * Increment given index associated with request queue. + * + * @param[inout] p_ptr Pointer to the index to increment. + */ static void req_queue_ptr_increment(uint8_t * p_ptr) { queue_ptr_increment(p_ptr, REQ_QUEUE_SIZE); } +/** + * Check if request queue is full. + * + * @retval true Request queue is full. + * @retval false Request queue is not full. + */ static bool req_queue_is_full(void) { return queue_is_full(m_req_r_ptr, m_req_w_ptr, REQ_QUEUE_SIZE); } +/** + * Check if request queue is empty. + * + * @retval true Request queue is empty. + * @retval false Request queue is not empty. + */ static bool req_queue_is_empty(void) { return queue_is_empty(m_req_r_ptr, m_req_w_ptr); @@ -331,6 +404,7 @@ void nrf_drv_radio802154_swi_receive(uint8_t channel, bool * p_result) void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, + bool cca, bool * p_result) { nrf_drv_radio802154_critical_section_enter(); @@ -342,6 +416,7 @@ void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, p_slot->data.transmit.p_data = p_data; p_slot->data.transmit.channel = channel; p_slot->data.transmit.power = power; + p_slot->data.transmit.cca = cca; p_slot->data.transmit.p_result = p_result; req_queue_ptr_increment(&m_req_w_ptr); @@ -454,7 +529,8 @@ void SWI_IRQHandler(void) *(p_slot->data.transmit.p_result) = nrf_drv_radio802154_fsm_transmit( p_slot->data.transmit.p_data, p_slot->data.transmit.channel, - p_slot->data.transmit.power); + p_slot->data.transmit.power, + p_slot->data.transmit.cca); break; case REQ_TYPE_ENERGY_DETECTION: diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.h index 337ff5bc8..1828f3702 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.h @@ -108,11 +108,13 @@ void nrf_drv_radio802154_swi_receive(uint8_t channel, bool * p_result); * @param[in] p_data Pointer to PSDU of the frame to transmit. * @param[in] channel Channel number used for requested transmission. * @param[in] power Transmitter power for requested transmission. + * @param[in] cca If the driver should perform CCA procedure before transmission. * @param[out] p_result Result of entering transmit state. */ void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, + bool cca, bool * p_result); /** diff --git a/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.c b/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.c index fa33dca24..e3b5c17f5 100644 --- a/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.c +++ b/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.c @@ -128,6 +128,12 @@ static inline uint32_t timer_time_get(void) return NRF_TIMER0->CC[TIMER_CC_CAPTURE]; } +/**@brief Check if margin is already reached. */ +static inline bool timer_is_margin_reached(void) +{ + return NRF_TIMER0->EVENTS_COMPARE[TIMER_CC_MARGIN]; +} + /**@brief Enter timeslot critical section. */ static inline void timeslot_critical_section_enter(void) { @@ -438,28 +444,38 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO: /**< This signal indicates the NRF_RADIO interrupt. */ nrf_drv_radio802154_pin_set(PIN_DBG_TIMESLOT_RADIO_IRQ); + nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_RADIO); - if (m_in_timeslot && !NRF_TIMER0->EVENTS_COMPARE[TIMER_CC_MARGIN]) + if (m_in_timeslot) { - RADIO_IRQHandler(); - } - else - { - NVIC_ClearPendingIRQ(RADIO_IRQn); + if (!timer_is_margin_reached()) + { + RADIO_IRQHandler(); + } + else + { + // Handle margin exceeded event. + timer_irq_handle(); + } } + nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_RADIO); nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_RADIO_IRQ); break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED: /**< This signal indicates extend action failed. */ nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_EXTEND_REQ); nrf_drv_radio802154_pin_tgl(PIN_DBG_TIMESLOT_FAILED); + nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL); timeslot_extend(); + + nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL); break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED: /**< This signal indicates extend action succeeded. */ nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_EXTEND_REQ); + nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS); timer_extend(); @@ -467,7 +483,8 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t { timeslot_extend(); } - + + nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS); break; default: