From 96f82b385864d1234aca646e74177a6a299be6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Mi=C5=9B?= Date: Thu, 10 Aug 2017 17:52:39 +0200 Subject: [PATCH] [nRF52840] update 802.15.4 driver (#2089) --- examples/platforms/nrf52840/platform-config.h | 68 --- .../platforms/nrf52840/platform-softdevice.h | 2 +- examples/platforms/nrf52840/platform.c | 2 + examples/platforms/nrf52840/radio.c | 42 +- .../drivers/doc/fsm_description.doc | Bin 0 -> 34304 bytes .../drivers/radio/nrf_drv_radio802154.c | 149 +++++- .../drivers/radio/nrf_drv_radio802154.h | 316 +++++++++++-- .../radio/nrf_drv_radio802154_config.h | 23 +- .../drivers/radio/nrf_drv_radio802154_const.h | 1 + .../drivers/radio/nrf_drv_radio802154_debug.h | 2 + .../drivers/radio/nrf_drv_radio802154_fsm.c | 424 ++++++++++++++---- .../drivers/radio/nrf_drv_radio802154_fsm.h | 116 +++-- .../radio/nrf_drv_radio802154_notification.h | 9 +- .../nrf_drv_radio802154_notification_direct.c | 11 +- .../nrf_drv_radio802154_notification_swi.c | 7 +- .../drivers/radio/nrf_drv_radio802154_pib.c | 70 ++- .../drivers/radio/nrf_drv_radio802154_pib.h | 16 + .../nrf_drv_radio802154_procedures_duration.h | 10 + .../radio/nrf_drv_radio802154_request.h | 37 +- .../nrf_drv_radio802154_request_direct.c | 52 ++- .../radio/nrf_drv_radio802154_request_swi.c | 83 +++- .../drivers/radio/nrf_drv_radio802154_swi.c | 219 ++++++--- .../drivers/radio/nrf_drv_radio802154_swi.h | 47 +- .../drivers/radio/raal/nrf_raal_config.h | 2 +- .../raal/softdevice/nrf_raal_softdevice.c | 16 +- .../raal/softdevice/nrf_raal_softdevice.h | 2 +- .../NordicSemiconductor/hal/nrf_radio.h | 45 +- 27 files changed, 1370 insertions(+), 401 deletions(-) create mode 100644 third_party/NordicSemiconductor/drivers/doc/fsm_description.doc diff --git a/examples/platforms/nrf52840/platform-config.h b/examples/platforms/nrf52840/platform-config.h index 9b6824114..df9313142 100644 --- a/examples/platforms/nrf52840/platform-config.h +++ b/examples/platforms/nrf52840/platform-config.h @@ -269,72 +269,4 @@ */ #define LOG_TIMESTAMP_ENABLE 1 -/******************************************************************************* - * @section Radio Driver Configuration. - ******************************************************************************/ - -/** - * @def RADIO_CCA_MODE - * - * RADIO CCA Mode. - * - */ -#define RADIO_CCA_MODE NRF_RADIO_CCA_MODE_ED - -/** - * @def RADIO_CCA_ED_THRESHOLD - * - * RADIO Energy Detection Threshold. - * - */ -#define RADIO_CCA_ED_THRESHOLD 0x2D - -/** - * @def RADIO_CCA_CORR_THRESHOLD - * - * RADIO Correlator Threshold. - * - */ -#define RADIO_CCA_CORR_THRESHOLD 0x2D - -/** - * @def RADIO_CCA_CORR_LIMIT - * - * RADIO Correlator limit. - * - */ -#define RADIO_CCA_CORR_LIMIT 0x02 - -/** - * @def RADIO_IRQ_PRIORITY - * - * RADIO Interrupt priority. - * - */ -#define RADIO_IRQ_PRIORITY 0 - -/** - * @def RADIO_PENDING_SHORT_ADDRESSES - * - * RADIO Number of slots containing short addresses of nodes for which pending data is stored. - * - */ -#define RADIO_PENDING_SHORT_ADDRESSES OPENTHREAD_CONFIG_MAX_CHILDREN - -/** - * @def RADIO_PENDING_EXTENDED_ADDRESSES - * - * RADIO Number of slots containing extended addresses of nodes for which pending data is stored. - * - */ -#define RADIO_PENDING_EXTENDED_ADDRESSES OPENTHREAD_CONFIG_MAX_CHILDREN - -/** - * @def RADIO_RX_BUFFERS - * - * RADIO Number of buffers in receive queue. - * - */ -#define RADIO_RX_BUFFERS 16 - #endif // PLATFORM_CONFIG_H_ diff --git a/examples/platforms/nrf52840/platform-softdevice.h b/examples/platforms/nrf52840/platform-softdevice.h index 040176e36..e79236305 100644 --- a/examples/platforms/nrf52840/platform-softdevice.h +++ b/examples/platforms/nrf52840/platform-softdevice.h @@ -41,7 +41,7 @@ #define PLATFORM_SOFTDEVICE_RAAL_TIMESLOT_DEFAULT_LENGTH 6400 #define PLATFORM_SOFTDEVICE_RAAL_TIMESLOT_DEFAULT_ALLOC_ITERS 5 #define PLATFORM_SOFTDEVICE_RAAL_TIMESLOT_DEFAULT_SAFE_MARGIN 91 -#define PLATFORM_SOFTDEVICE_RAAL_TIMESLOT_DEFAULT_TIMEOUT 100000 +#define PLATFORM_SOFTDEVICE_RAAL_TIMESLOT_DEFAULT_TIMEOUT 6400 #define PLATFORM_SOFTDEVICE_RAAL_TIMESLOT_DEFAULT_MAX_LENGTH 120000000 #define PLATFORM_SOFTDEVICE_RAAL_DEFAULT_LF_CLK_ACCURACY_PPM 25 diff --git a/examples/platforms/nrf52840/platform.c b/examples/platforms/nrf52840/platform.c index f0146a0dd..5000eb54b 100644 --- a/examples/platforms/nrf52840/platform.c +++ b/examples/platforms/nrf52840/platform.c @@ -47,8 +47,10 @@ void PlatformInit(int argc, char *argv[]) (void)argc; (void)argv; +#if !SOFTDEVICE_PRESENT // Enable I-code cache NRF_NVMC->ICACHECNF = NVMC_ICACHECNF_CACHEEN_Enabled; +#endif nrf_drv_clock_init(); diff --git a/examples/platforms/nrf52840/radio.c b/examples/platforms/nrf52840/radio.c index 40a53b4cb..77c9ae662 100644 --- a/examples/platforms/nrf52840/radio.c +++ b/examples/platforms/nrf52840/radio.c @@ -88,6 +88,8 @@ static uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE + 1]; static otRadioFrame sAckFrame; +static int8_t sDefaultTxPower; + static uint32_t sEnergyDetectionTime; static uint8_t sEnergyDetectionChannel; static int8_t sEnergyDetected; @@ -316,7 +318,9 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) { (void) aInstance; - nrf_drv_radio802154_receive(aChannel); + nrf_drv_radio802154_channel_set(aChannel); + nrf_drv_radio802154_tx_power_set(sDefaultTxPower); + nrf_drv_radio802154_receive(); clearPendingEvents(); return OT_ERROR_NONE; @@ -328,7 +332,10 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) aFrame->mPsdu[-1] = aFrame->mLength; - if (nrf_drv_radio802154_transmit(&aFrame->mPsdu[-1], aFrame->mChannel, aFrame->mPower, true)) + nrf_drv_radio802154_channel_set(aFrame->mChannel); + nrf_drv_radio802154_tx_power_set(aFrame->mPower); + + if (nrf_drv_radio802154_transmit_raw(&aFrame->mPsdu[-1], true)) { clearPendingEvents(); otPlatRadioTxStarted(aInstance, aFrame); @@ -485,7 +492,9 @@ otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint1 clearPendingEvents(); - if (nrf_drv_radio802154_energy_detection(aScanChannel, sEnergyDetectionTime)) + nrf_drv_radio802154_channel_set(aScanChannel); + + if (nrf_drv_radio802154_energy_detection(sEnergyDetectionTime)) { resetPendingEvent(kPendingEventEnergyDetectionStart); } @@ -501,7 +510,8 @@ void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower) { (void)aInstance; - nrf_drv_radio802154_ack_tx_power_set(aPower); + sDefaultTxPower = aPower; + nrf_drv_radio802154_tx_power_set(aPower); } void nrf5RadioProcess(otInstance *aInstance) @@ -524,13 +534,16 @@ void nrf5RadioProcess(otInstance *aInstance) uint8_t *bufferAddress = &sReceivedFrames[i].mPsdu[-1]; sReceivedFrames[i].mPsdu = NULL; - nrf_drv_radio802154_buffer_free(bufferAddress); + nrf_drv_radio802154_buffer_free_raw(bufferAddress); } } if (isPendingEventSet(kPendingEventTransmit)) { - if (nrf_drv_radio802154_transmit(sTransmitPsdu, sTransmitFrame.mChannel, sTransmitFrame.mPower, true)) + nrf_drv_radio802154_channel_set(sTransmitFrame.mChannel); + nrf_drv_radio802154_tx_power_set(sTransmitFrame.mPower); + + if (nrf_drv_radio802154_transmit_raw(sTransmitPsdu, true)) { resetPendingEvent(kPendingEventTransmit); otPlatRadioTxStarted(aInstance, &sTransmitFrame); @@ -554,7 +567,7 @@ void nrf5RadioProcess(otInstance *aInstance) if (sAckFrame.mPsdu != NULL) { - nrf_drv_radio802154_buffer_free(sAckFrame.mPsdu - 1); + nrf_drv_radio802154_buffer_free_raw(sAckFrame.mPsdu - 1); sAckFrame.mPsdu = NULL; } @@ -595,20 +608,22 @@ void nrf5RadioProcess(otInstance *aInstance) if (isPendingEventSet(kPendingEventEnergyDetectionStart)) { - if (nrf_drv_radio802154_energy_detection(sEnergyDetectionChannel, sEnergyDetectionTime)) + nrf_drv_radio802154_channel_set(sEnergyDetectionChannel); + + if (nrf_drv_radio802154_energy_detection(sEnergyDetectionTime)) { resetPendingEvent(kPendingEventEnergyDetectionStart); } } } -void nrf_drv_radio802154_received(uint8_t *p_data, int8_t power, int8_t lqi) +void nrf_drv_radio802154_received_raw(uint8_t *p_data, int8_t power, int8_t lqi) { otRadioFrame *receivedFrame = NULL; if (isPendingEventSet(kPendingEventTransmit)) { - nrf_drv_radio802154_buffer_free(p_data); + nrf_drv_radio802154_buffer_free_raw(p_data); return; } @@ -638,7 +653,7 @@ void nrf_drv_radio802154_received(uint8_t *p_data, int8_t power, int8_t lqi) #endif } -void nrf_drv_radio802154_transmitted(uint8_t *aAckPsdu, int8_t aPower, int8_t aLqi) +void nrf_drv_radio802154_transmitted_raw(uint8_t *aAckPsdu, int8_t aPower, int8_t aLqi) { if (aAckPsdu == NULL) { @@ -661,10 +676,9 @@ void nrf_drv_radio802154_busy_channel(void) setPendingEvent(kPendingEventChannelAccessFailure); } -void nrf_drv_radio802154_energy_detected(int8_t result) +void nrf_drv_radio802154_energy_detected(uint8_t result) { - // TODO: Correct RSSI calculation after lab tests. - sEnergyDetected = 94 - result; + sEnergyDetected = nrf_drv_radio802154_dbm_from_energy_level_calculate(result); setPendingEvent(kPendingEventEnergyDetected); } diff --git a/third_party/NordicSemiconductor/drivers/doc/fsm_description.doc b/third_party/NordicSemiconductor/drivers/doc/fsm_description.doc new file mode 100644 index 0000000000000000000000000000000000000000..afb697fcafd50a2a1d5c1e532fe4a1ec75f37513 GIT binary patch literal 34304 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 l&Y-fSdZc=$x%cJAR;v(ADBAx5u{{xw^jza(d literal 0 HcmV?d00001 diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c index e9f9454a8..9b8b4b0d2 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c @@ -43,6 +43,8 @@ #include #include "nrf_drv_radio802154_ack_pending_bit.h" +#include "nrf_drv_radio802154_config.h" +#include "nrf_drv_radio802154_const.h" #include "nrf_drv_radio802154_debug.h" #include "nrf_drv_radio802154_fsm.h" #include "nrf_drv_radio802154_notification.h" @@ -55,17 +57,37 @@ #include +#define RAW_LENGTH_OFFSET 0 +#define RAW_PAYLOAD_OFFSET 1 + + +void nrf_drv_radio802154_channel_set(uint8_t channel) +{ + bool changed = nrf_drv_radio802154_pib_channel_get() != channel; + + nrf_drv_radio802154_pib_channel_set(channel); + + if (changed) + { + nrf_drv_radio802154_request_channel_update(); + } +} uint8_t nrf_drv_radio802154_channel_get(void) { return nrf_drv_radio802154_pib_channel_get(); } -void nrf_drv_radio802154_ack_tx_power_set(int8_t power) +void nrf_drv_radio802154_tx_power_set(int8_t power) { nrf_drv_radio802154_pib_tx_power_set(power); } +int8_t nrf_drv_radio802154_tx_power_get(void) +{ + return nrf_drv_radio802154_pib_tx_power_get(); +} + void nrf_drv_radio802154_pan_id_set(const uint8_t * p_pan_id) { nrf_drv_radio802154_pib_pan_id_set(p_pan_id); @@ -81,6 +103,12 @@ void nrf_drv_radio802154_short_address_set(const uint8_t * p_short_address) nrf_drv_radio802154_pib_short_address_set(p_short_address); } +int8_t nrf_drv_radio802154_dbm_from_energy_level_calculate(uint8_t energy_level) +{ + // TODO: Correct this calculation after lab tests. + return -94 + energy_level; +} + void nrf_drv_radio802154_init(void) { nrf_drv_radio802154_ack_pending_bit_init(); @@ -99,6 +127,13 @@ void nrf_drv_radio802154_deinit(void) nrf_drv_radio802154_fsm_deinit(); } +#if !RADIO_INTERNAL_IRQ_HANDLING +void nrf_drv_radio802154_irq_handler(void) +{ + nrf_drv_radio802154_fsm_irq_handler(); +} +#endif // !RADIO_INTERNAL_IRQ_HANDLING + nrf_drv_radio802154_state_t nrf_drv_radio802154_state_get(void) { switch (nrf_drv_radio802154_fsm_state_get()) @@ -114,13 +149,19 @@ nrf_drv_radio802154_state_t nrf_drv_radio802154_state_get(void) case RADIO_STATE_TX_ACK: return NRF_DRV_RADIO802154_STATE_RECEIVE; - case RADIO_STATE_CCA: + case RADIO_STATE_CCA_BEFORE_TX: case RADIO_STATE_TX_FRAME: case RADIO_STATE_RX_ACK: return NRF_DRV_RADIO802154_STATE_TRANSMIT; case RADIO_STATE_ED: return NRF_DRV_RADIO802154_STATE_ENERGY_DETECTION; + + case RADIO_STATE_CCA: + return NRF_DRV_RADIO802154_STATE_CCA; + + case RADIO_STATE_CONTINUOUS_CARRIER: + return NRF_DRV_RADIO802154_STATE_CONTINUOUS_CARRIER; } return NRF_DRV_RADIO802154_STATE_INVALID; @@ -154,40 +195,84 @@ bool nrf_drv_radio802154_sleep(void) return result; } -void nrf_drv_radio802154_receive(uint8_t channel) +void nrf_drv_radio802154_receive(void) { bool result; nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RECEIVE); - result = nrf_drv_radio802154_request_receive(channel); + result = nrf_drv_radio802154_request_receive(); assert(result == true); 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 cca) +bool nrf_drv_radio802154_transmit_raw(const uint8_t * p_data, bool cca) { bool result; nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_TRANSMIT); - result = nrf_drv_radio802154_request_transmit(p_data, channel, power, cca); + result = nrf_drv_radio802154_request_transmit(p_data, cca); nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_TRANSMIT); return result; } -bool nrf_drv_radio802154_energy_detection(uint8_t channel, uint32_t time_us) +bool nrf_drv_radio802154_transmit(const uint8_t * p_data, uint8_t length, bool cca) +{ +#if defined ( __GNUC__ ) + + static uint8_t tx_buffer[RAW_PAYLOAD_OFFSET + MAX_PACKET_SIZE] + __attribute__ ((section ("nrf_radio_buffer.tx_buffer"))); + +#elif defined ( __ICCARM__ ) + +#pragma location="NRF_RADIO_BUFFER" + static uint8_t tx_buffer[RAW_PAYLOAD_OFFSET + MAX_PACKET_SIZE]; + +#endif + + assert(length <= MAX_PACKET_SIZE - FCS_SIZE); + + tx_buffer[RAW_LENGTH_OFFSET] = length + FCS_SIZE; + memcpy(&tx_buffer[RAW_PAYLOAD_OFFSET], p_data, length); + + return nrf_drv_radio802154_transmit_raw(tx_buffer, cca); +} + +bool nrf_drv_radio802154_energy_detection(uint32_t time_us) { bool result; nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_ENERGY_DETECTION); - result = nrf_drv_radio802154_request_energy_detection(channel, time_us); + result = nrf_drv_radio802154_request_energy_detection(time_us); nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_ENERGY_DETECTION); return result; } -void nrf_drv_radio802154_buffer_free(uint8_t * p_data) +bool nrf_drv_radio802154_cca(void) +{ + bool result; + nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_CCA); + + result = nrf_drv_radio802154_request_cca(); + + nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_CCA); + return result; +} + +bool nrf_drv_radio802154_continuous_carrier(void) +{ + bool result; + nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_CONTINUOUS_CARRIER); + + result = nrf_drv_radio802154_request_continuous_carrier(); + + nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_CONTINUOUS_CARRIER); + return result; +} + +void nrf_drv_radio802154_buffer_free_raw(uint8_t * p_data) { rx_buffer_t * p_buffer = (rx_buffer_t *)p_data; @@ -200,6 +285,11 @@ void nrf_drv_radio802154_buffer_free(uint8_t * p_data) nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_BUFFER_FREE); } +void nrf_drv_radio802154_buffer_free(uint8_t * p_data) +{ + nrf_drv_radio802154_buffer_free_raw(p_data - RAW_PAYLOAD_OFFSET); +} + int8_t nrf_drv_radio802154_rssi_last_get(void) { uint8_t minus_dbm = nrf_radio_rssi_sample_get(); @@ -246,26 +336,48 @@ void nrf_drv_radio802154_pending_bit_for_addr_reset(bool extended) nrf_drv_radio802154_ack_pending_bit_for_addr_reset(extended); } +void nrf_drv_radio802154_cca_cfg_set(const nrf_drv_radio802154_cca_cfg_t * p_cca_cfg) +{ + nrf_drv_radio802154_pib_cca_cfg_set(p_cca_cfg); + + nrf_drv_radio802154_request_cca_cfg_update(); +} + +void nrf_drv_radio802154_cca_cfg_get(nrf_drv_radio802154_cca_cfg_t * p_cca_cfg) +{ + nrf_drv_radio802154_pib_cca_cfg_get(p_cca_cfg); +} + __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) +__WEAK void nrf_drv_radio802154_received(uint8_t * p_data, uint8_t length, int8_t power, int8_t lqi) { + (void) length; (void) power; (void) lqi; nrf_drv_radio802154_buffer_free(p_data); } +__WEAK void nrf_drv_radio802154_received_raw(uint8_t * p_data, int8_t power, int8_t lqi) +{ + nrf_drv_radio802154_received(p_data + RAW_PAYLOAD_OFFSET, + p_data[RAW_LENGTH_OFFSET], + power, + lqi); +} + __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) +__WEAK void nrf_drv_radio802154_transmitted(uint8_t * p_ack, uint8_t length, int8_t power, int8_t lqi) { + (void) length; (void) power; (void) lqi; @@ -275,12 +387,25 @@ __WEAK void nrf_drv_radio802154_transmitted(uint8_t * p_ack, int8_t power, int8_ } } +__WEAK void nrf_drv_radio802154_transmitted_raw(uint8_t * p_ack, int8_t power, int8_t lqi) +{ + nrf_drv_radio802154_transmitted(p_ack + RAW_PAYLOAD_OFFSET, + p_ack[RAW_LENGTH_OFFSET], + power, + lqi); +} + __WEAK void nrf_drv_radio802154_busy_channel(void) { // Intentionally empty } -__WEAK void nrf_drv_radio802154_energy_detected(int8_t result) +__WEAK void nrf_drv_radio802154_energy_detected(uint8_t result) { (void) result; } + +__WEAK void nrf_drv_radio802154_cca_done(bool channel_free) +{ + (void) channel_free; +} diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h index 78ce280d5..c8ccb13c9 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h @@ -39,6 +39,9 @@ #include #include +#include "nrf_drv_radio802154_config.h" +#include "hal/nrf_radio.h" + #ifdef __cplusplus extern "C" { #endif @@ -53,8 +56,21 @@ typedef enum NRF_DRV_RADIO802154_STATE_RECEIVE, NRF_DRV_RADIO802154_STATE_TRANSMIT, NRF_DRV_RADIO802154_STATE_ENERGY_DETECTION, + NRF_DRV_RADIO802154_STATE_CCA, + NRF_DRV_RADIO802154_STATE_CONTINUOUS_CARRIER, } nrf_drv_radio802154_state_t; +/** + * @brief Structure for configuring CCA. + */ +typedef struct +{ + nrf_radio_cca_mode_t mode; ///< CCA mode. + uint8_t ed_threshold; ///< CCA Energy Busy Threshold. Not used in NRF_RADIO_CCA_MODE_CARRIER. + uint8_t corr_threshold; ///< CCA Correlator Busy Threshold. Not used in NRF_RADIO_CCA_MODE_ED. + uint8_t corr_limit; ///< Limit of occurrences above CCA Correlator Busy Threshold. Not used in NRF_RADIO_CCA_MODE_ED. +} nrf_drv_radio802154_cca_cfg_t; + /** * @brief Initialize 802.15.4 driver. * @@ -71,17 +87,50 @@ void nrf_drv_radio802154_init(void); */ void nrf_drv_radio802154_deinit(void); +#if !RADIO_INTERNAL_IRQ_HANDLING +/** + * @brief Handle interrupt request from the RADIO peripheral. + * + * @note When RADIO_INTERNAL_IRQ_HANDLING is enabled the driver internally handles the RADIO IRQ + * and this function shall not be called. + * + * This function is intended to be used in Operating System environment when the OS handles IRQ + * and indirectly passes it to the driver or with RAAL implementation that indirectly passes radio + * IRQ handler to the driver (i.e. SoftDevice). + */ +void nrf_drv_radio802154_irq_handler(void); +#endif // !RADIO_INTERNAL_IRQ_HANDLING + +/** + * @brief Set channel on which the radio shall operate right now. + * + * @param[in] channel Channel number (11-26). + */ +void nrf_drv_radio802154_channel_set(uint8_t channel); + /** * @brief Get channel on which the radio operates right now. + * + * @returns Channel number (11-26). */ uint8_t nrf_drv_radio802154_channel_get(void); /** - * @brief Set transmit power used for ACK frames. + * @brief Set transmit power. + * + * @note The driver recalculates requested value to the nearest value accepted by the hardware. + * The calculation result is rounded up. * * @param[in] power Transmit power [dBm]. */ -void nrf_drv_radio802154_ack_tx_power_set(int8_t power); +void nrf_drv_radio802154_tx_power_set(int8_t power); + +/** + * @brief Get currently set transmit power. + * + * @return Currently used transmit power [dBm]. + */ +int8_t nrf_drv_radio802154_tx_power_get(void); /** * @section Setting addresses and Pan Id of this device. @@ -114,19 +163,18 @@ void nrf_drv_radio802154_extended_address_set(const uint8_t *p_extended_address) */ void nrf_drv_radio802154_short_address_set(const uint8_t *p_short_address); +/** + * @brief Calculate dBm from energy level received during energy detection procedure. + * + * @param[in] energy_level Energy level passed by @sa nrf_drv_radio802154_energy_detected + * + * @return Result of energy detection procedure in dBm. + */ +int8_t nrf_drv_radio802154_dbm_from_energy_level_calculate(uint8_t energy_level); + /** * @section Functions to request FSM transitions and check current state. - * - * receive() transmit() - * --------> --------> - * Sleep Receive Transmit - * <-------- | /|\<-------- - * sleep() | | receive() / transmitted() / busy_channel() - * | | - * energy_detection() | | energy_detected() - * \|/ | - * Energy detection */ /** @@ -153,35 +201,82 @@ bool nrf_drv_radio802154_sleep(void); * * In Receive state radio receives frames and automatically sends ACK frames when appropriate. * Received frame is reported to higher layer by nrf_radio802154_received() call. - * - * @param[in] channel Channel number on which radio will receive. */ -void nrf_drv_radio802154_receive(uint8_t channel); +void nrf_drv_radio802154_receive(void); /** * @brief Change radio state to Transmit. * - * @note This function should be called in Receive state. In other states transmission will be + * @note This function should be called in Receive state. In other states transmission will not be * scheduled. + * @note If the CPU was halted or interrupted during performing this function + * @sa nrf_drv_radio802154_transmitted() or @sa nrf_drv_radio802154_busy_channel() may be + * called before nrf_drv_radio802154_transmit_raw() returns result. + * @note This function is implemented in zero-copy fashion. It passes given buffer pointer to + * the RADIO peripheral. * * In Transmit state radio transmits given frame. If requested it waits for ACK frame. - * Radio driver wait infinitely for ACK frame. Higher layer is responsible to call - * nrf_radio802154_receive() after ACK timeout. - * Transmission result is reported to higher layer by nrf_radio802154_transmitted() or - * nrf_radio802154_busy_channel() calls. + * Radio driver waits infinitely for ACK frame. Higher layer is responsible to call + * @sa nrf_radio802154_receive() after ACK timeout. + * Transmission result is reported to higher layer by @sa nrf_radio802154_transmitted() or + * @sa nrf_radio802154_busy_channel() calls. + * + * p_data + * v + * +-----+-----------------------------------------------------------+------------+ + * | PHR | MAC Header and payload | FCS | + * +-----+-----------------------------------------------------------+------------+ + * | | + * | <---------------------------- PHR -----------------------------------> | * * @param[in] p_data Pointer to array containing data to transmit. First byte should contain - * frame length and following bytes should contain data. CRC is computed - * automatically by radio hardware and can contain any bytes. - * @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. + * frame length (including PHR and FCS). Following bytes should contain data. + * CRC is computed automatically by radio hardware and because of that FCS + * field can contain any bytes. * @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 cca); +bool nrf_drv_radio802154_transmit_raw(const uint8_t *p_data, bool cca); + +/** + * @brief Change radio state to Transmit. + * + * @note This function should be called in Receive state. In other states transmission will not be + * scheduled. + * @note If the CPU was halted or interrupted during performing this function + * @sa nrf_drv_radio802154_transmitted() or @sa nrf_drv_radio802154_busy_channel() may be + * called before nrf_drv_radio802154_transmit() returns result. + * @note This function makes copy of given buffer. There is an internal buffer maintained by this + * function. It is used to make a frame copy. To prevent unnecessary memory consumption and + * to perform zero-copy transmission @sa nrf_drv_radio802154_transmit_raw() function should + * be used instead of this. + * + * In Transmit state radio transmits given frame. If requested, it waits for ACK frame. + * Radio driver waits infinitely for ACK frame. Higher layer is responsible to call + * @sa nrf_radio802154_receive() after ACK timeout. + * Transmission result is reported to higher layer by @sa nrf_radio802154_transmitted() or + * @sa nrf_radio802154_busy_channel() calls. + * + * p_data + * v + * +-----+-----------------------------------------------------------+------------+ + * | PHR | MAC Header and payload | FCS | + * +-----+-----------------------------------------------------------+------------+ + * | | + * | <------------------ length -----------------------------> | + * + * @param[in] p_data Pointer to array containing payload of a data to transmit. The array + * should exclude PHR or FCS fields of 802.15.4 frame. + * @param[in] length Length of given frame. This value shall exclude PHR and FCS fields from + * the given frame (exact size of buffer pointed by @p p_data). + * @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 length, bool cca); /** * @brief Change radio state to Energy Detection. @@ -191,16 +286,43 @@ bool nrf_drv_radio802154_transmit(const uint8_t *p_data, uint8_t channel, int8_t * called before nrf_drv_radio802154_energy_detection() returns result. * * In Energy Detection state radio detects maximum energy for given time. Result of the detection - * is reported to the higher layer by nrf_drv_radio802154_energy_detected() call. + * is reported to the higher layer by @sa nrf_drv_radio802154_energy_detected() call. * - * @param[in] channel Channel number on which radio will detect energy. * @param[in] time_us Duration of energy detection procedure. Given value is rounded up to * multiplication of 8s (128 us). * * @return true If the energy detection procedure was scheduled. * @return false If the driver could not schedule the energy detection procedure. */ -bool nrf_drv_radio802154_energy_detection(uint8_t channel, uint32_t time_us); +bool nrf_drv_radio802154_energy_detection(uint32_t time_us); + +/** + * @brief Change radio state to CCA. + * @note This function should be called in Receive state or Sleep state. + * @note If this function is called in Sleep state nrf_drv_radio802154_cca_done() may be + * called before nrf_drv_radio802154_cca() returns result. + * + * In CCA state radio verifies if channel is clear. Result of verification is reported to the higher + * layer by @sa nrf_drv_radio802154_cca_done() call. + * + * @return true If the CCA procedure was scheduled. + * @return false If the driver could not schedule the CCA procedure. + */ +bool nrf_drv_radio802154_cca(void); + +/** + * @brief Change radio state to CONTINUOUS_CARRIER. + * @note This function should be called in Receive or Sleep state. + * @note When radio is emitting continuous carrier it blocks all transmissions on selected channel. + * This function should be called only during radio tests. It should not be used during + * normal device operation. + * @note This function works correctly only with a single-phy arbiter. It should not be used with + * any other arbiter. + * + * @return true If the continuous carrier procedure was scheduled. + * @return false If the driver could not schedule the continuous carrier procedure. + */ +bool nrf_drv_radio802154_continuous_carrier(void); /** @@ -220,16 +342,53 @@ extern void nrf_drv_radio802154_rx_started(void); * @brief Notify that frame was received. * * @note Buffer pointed by the p_data pointer is not modified by the radio driver (and can't - * be used to receive a frame) until nrf_drv_radio802154_buffer_free() function is called. + * be used to receive a frame) until nrf_drv_radio802154_buffer_free_raw() function is called. * @note Buffer pointed by the p_data pointer may be modified by the function handler (and other - * modules) until nrf_drv_radio802154_buffer_free() function is called. + * modules) until @sa nrf_drv_radio802154_buffer_free_raw() function is called. + * @note The next higher layer should handle @sa nrf_drv_radio802154_received_raw() or @sa + * nrf_drv_radio802154_received() function. It should not handle both. * - * @param[in] p_data Pointer to buffer containing received data. First byte in the buffer is - * length of the frame and following bytes is the frame itself (after PHR). + * p_data + * v + * +-----+-----------------------------------------------------------+------------+ + * | PHR | MAC Header and payload | FCS | + * +-----+-----------------------------------------------------------+------------+ + * | | + * | <---------------------------- PHR -----------------------------------> | + * + * @param[in] p_data Pointer to the buffer containing received data (PHR + PSDU). First byte in + * the buffer is length of the frame (PHR) and following bytes is the frame + * itself (PSDU). Length byte (PHR) includes FCS. FCS is already verified by + * the hardware and may be modified by the hardware. * @param[in] power RSSI of received frame. * @param[in] lqi LQI of received frame. */ -extern void nrf_drv_radio802154_received(uint8_t * p_data, int8_t power, int8_t lqi); +extern void nrf_drv_radio802154_received_raw(uint8_t * p_data, int8_t power, int8_t lqi); + +/** + * @brief Notify that frame was received. + * + * @note Buffer pointed by the p_data pointer is not modified by the radio driver (and can't + * be used to receive a frame) until nrf_drv_radio802154_buffer_free() function is called. + * @note Buffer pointed by the p_data pointer may be modified by the function handler (and other + * modules) until @sa nrf_drv_radio802154_buffer_free() function is called. + * @note The next higher layer should handle @sa nrf_drv_radio802154_received_raw() or @sa + * nrf_drv_radio802154_received() function. It should not handle both. + * + * p_data + * v + * +-----+-----------------------------------------------------------+------------+ + * | PHR | MAC Header and payload | FCS | + * +-----+-----------------------------------------------------------+------------+ + * | | + * | <------------------ length -----------------------------> | + * + * @param[in] p_data Pointer to the buffer containing payload of received frame (PSDU without FCS). + * @param[in] length Length of received payload. + * @param[in] power RSSI of received frame. + * @param[in] lqi LQI of received frame. + */ +extern void nrf_drv_radio802154_received(uint8_t * p_data, uint8_t length, int8_t power, int8_t lqi); /** * @brief Notify that transmitting frame has started. @@ -246,18 +405,46 @@ extern void nrf_drv_radio802154_tx_started(void); * @note If ACK was requested for transmitted frame this function is called after proper ACK is * received. If ACK was not requested this function is called just after transmission is * ended. - * @note Buffer pointed by the p_ack pointer is not modified by the radio driver (and can't - * be used to receive a frame) until nrf_drv_radio802154_buffer_free() function is called. - * @note Buffer pointed by the p_ack pointer may be modified by the function handler (and other - * modules) until nrf_drv_radio802154_buffer_free() function is called. + * @note Buffer pointed by the @p p_ack pointer is not modified by the radio driver (and can't + * be used to receive a frame) until @sa nrf_drv_radio802154_buffer_free_raw() function is + * called. + * @note Buffer pointed by the @p p_ack pointer may be modified by the function handler (and other + * modules) until @sa nrf_drv_radio802154_buffer_free_raw() function is called. + * @note The next higher layer should handle @sa nrf_drv_radio802154_transmitted_raw() or @sa + * nrf_drv_radio802154_transmitted() function. It should not handle both. * * @param[in] p_ack Pointer to received ACK buffer. Fist byte in the buffer is length of the - * frame and following bytes are the ACK frame itself (after PHR). + * frame (PHR) and following bytes are the ACK frame itself (PSDU). Length byte + * (PHR) includes FCS. FCS is already verified by the hardware and may be + * modified by the hardware. * If ACK was not requested @p p_ack is set to NULL. * @param[in] power RSSI of received frame or 0 if ACK was not requested. * @param[in] lqi LQI of received frame or 0 if ACK was not requested. */ -extern void nrf_drv_radio802154_transmitted(uint8_t * p_ack, int8_t power, int8_t lqi); +extern void nrf_drv_radio802154_transmitted_raw(uint8_t * p_ack, int8_t power, int8_t lqi); + +/** + * @brief Notify that frame was transmitted. + * + * @note If ACK was requested for transmitted frame this function is called after proper ACK is + * received. If ACK was not requested this function is called just after transmission is + * ended. + * @note Buffer pointed by the @p p_ack pointer is not modified by the radio driver (and can't + * be used to receive a frame) until @sa nrf_drv_radio802154_buffer_free() function is + * called. + * @note Buffer pointed by the @p p_ack pointer may be modified by the function handler (and other + * modules) until @sa nrf_drv_radio802154_buffer_free() function is called. + * @note The next higher layer should handle @sa nrf_drv_radio802154_transmitted() or @sa + * nrf_drv_radio802154_transmitted() function. It should not handle both. + * + * @param[in] p_ack Pointer to buffer containing received ACK payload (PHR excluding FCS). + * If ACK was not requested @p p_ack is set to NULL. + * @param[in] length Length of received ACK payload. + * @param[in] power RSSI of received frame or 0 if ACK was not requested. + * @param[in] lqi LQI of received frame or 0 if ACK was not requested. + */ +extern void nrf_drv_radio802154_transmitted(uint8_t * p_ack, uint8_t length, int8_t power, int8_t lqi); + /** * @brief Notify that frame was not transmitted due to busy channel. @@ -269,9 +456,20 @@ extern void nrf_drv_radio802154_busy_channel(void); /** * @brief Notify that Energy Detection procedure finished. * + * @note This function passes EnergyLevel defined in 802.15.4-2006 specification: + * 0x00 - 0xff proportional to detected energy level (dBm above receiver sensitivity). To + * calculate result in dBm use @sa nrf_drv_radio802154_dbm_from_energy_level_calculate(). + * * @param[in] result Maximum energy detected during Energy Detection procedure. */ -extern void nrf_drv_radio802154_energy_detected(int8_t result); +extern void nrf_drv_radio802154_energy_detected(uint8_t result); + +/** + * @brief Notify that CCA procedure has finished. + * + * @param[in] channel_free Indication if channel is free. + */ +extern void nrf_drv_radio802154_cca_done(bool channel_free); /** @@ -282,6 +480,24 @@ extern void nrf_drv_radio802154_energy_detected(int8_t result); * @brief Notify driver that buffer containing received frame is not used anymore. * * @note The buffer pointed by the @p p_data pointer may be modified by this function. + * @note Use this function with buffers provided by @sa nrf_drv_radio802154_received_raw() and + * @sa nrf_drv_radio802154_transmitted_raw(). To free buffers provided by @sa + * nrf_drv_radio802154_received() or @sa nrf_drv_radio802154_transmitted() use + * @sa nrf_drv_radio802154_buffer_free(). + * + * @param[in] p_data A pointer to the buffer containing received data that is no more needed by + * the higher layer. + */ +void nrf_drv_radio802154_buffer_free_raw(uint8_t * p_data); + +/** + * @brief Notify driver that buffer containing received frame is not used anymore. + * + * @note The buffer pointed by the @p p_data pointer may be modified by this function. + * @note Use this function with buffers provided by @sa nrf_drv_radio802154_received() and + * @sa nrf_drv_radio802154_transmitted(). To free buffers provided by @sa + * nrf_drv_radio802154_received_raw() or @sa nrf_drv_radio802154_transmitted_raw() use + * @sa nrf_drv_radio802154_buffer_free_raw(). * * @param[in] p_data A pointer to the buffer containing received data that is no more needed by * the higher layer. @@ -420,6 +636,24 @@ bool nrf_drv_radio802154_pending_bit_for_addr_clear(const uint8_t *p_addr, bool */ void nrf_drv_radio802154_pending_bit_for_addr_reset(bool extended); +/** + * @section CCA configuration management. + */ + +/** + * @brief Configure radio CCA mode and threshold. + * + * @param[in] p_cca_cfg A pointer to the CCA configuration structure. Only fields relevant to selected mode are updated. + */ +void nrf_drv_radio802154_cca_cfg_set(const nrf_drv_radio802154_cca_cfg_t * p_cca_cfg); + +/** + * @brief Get current radio CCA configuration + * + * @param[out] p_cca_cfg A pointer to the structure for current CCA configuration. + */ +void nrf_drv_radio802154_cca_cfg_get(nrf_drv_radio802154_cca_cfg_t * p_cca_cfg); + #ifdef __cplusplus } #endif diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_config.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_config.h index 94c0acd45..64c5168e5 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_config.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_config.h @@ -54,7 +54,7 @@ extern "C" { * RADIO CCA Mode. * */ -#define RADIO_CCA_MODE NRF_RADIO_CCA_MODE_ED +#define RADIO_CCA_MODE_DEFAULT NRF_RADIO_CCA_MODE_ED /** * @def RADIO_CCA_ED_THRESHOLD @@ -62,7 +62,7 @@ extern "C" { * RADIO Energy Detection Threshold. * */ -#define RADIO_CCA_ED_THRESHOLD 0x2D +#define RADIO_CCA_ED_THRESHOLD_DEFAULT 0x2D /** * @def RADIO_CCA_CORR_THRESHOLD @@ -70,7 +70,7 @@ extern "C" { * RADIO Correlator Threshold. * */ -#define RADIO_CCA_CORR_THRESHOLD 0x2D +#define RADIO_CCA_CORR_THRESHOLD_DEFAULT 0x2D /** * @def RADIO_CCA_CORR_LIMIT @@ -78,7 +78,22 @@ extern "C" { * RADIO Correlator limit. * */ -#define RADIO_CCA_CORR_LIMIT 0x02 +#define RADIO_CCA_CORR_LIMIT_DEFAULT 0x02 + +/** + * @def RADIO_INTERNAL_IRQ_HANDLING + * + * If the driver should internally handle the RADIO IRQ. + * In case the driver is used in an OS the RADIO IRQ may be handled by the OS and passed to + * the driver @sa nrf_drv_radio802154_irq_handler(). In this case internal handling should be + * disabled. + */ + +#if RAAL_SOFTDEVICE +#define RADIO_INTERNAL_IRQ_HANDLING 0 +#else // RAAL_SOFTDEVICE +#define RADIO_INTERNAL_IRQ_HANDLING 1 +#endif // RAAL_SOFTDEVICE /** * @def RADIO_IRQ_PRIORITY 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 ad0cfd998..e51426aaa 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h @@ -69,6 +69,7 @@ #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 FCS_SIZE 2 ///< Size of FCS field #define MAX_PACKET_SIZE 127 ///< Maximal size of radio packet 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 bf69b605d..ccd051fe1 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h @@ -56,6 +56,8 @@ extern "C" { #define FUNCTION_TRANSMIT 0x0003UL #define FUNCTION_ENERGY_DETECTION 0x0004UL #define FUNCTION_BUFFER_FREE 0x0005UL +#define FUNCTION_CCA 0x0006UL +#define FUNCTION_CONTINUOUS_CARRIER 0x0007UL #define FUNCTION_IRQ_HANDLER 0x0100UL #define FUNCTION_EVENT_FRAMESTART 0x0101UL 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 0455ba228..c5bce5d96 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c @@ -249,6 +249,16 @@ static inline void rx_buffer_in_use_set(rx_buffer_t * p_rx_buffer) #endif } +/** Update CCA configuration in RADIO registers. */ +static void cca_configuration_update(void) +{ + nrf_drv_radio802154_cca_cfg_t cca_cfg; + nrf_drv_radio802154_pib_cca_cfg_get(&cca_cfg); + nrf_radio_cca_mode_set(cca_cfg.mode); + nrf_radio_cca_ed_threshold_set(cca_cfg.ed_threshold); + nrf_radio_cca_corr_threshold_set(cca_cfg.corr_threshold); + nrf_radio_cca_corr_counter_set(cca_cfg.corr_limit); +} /*************************************************************************************************** * @section Radio parameters calculators @@ -265,42 +275,6 @@ static void channel_set(uint8_t channel) nrf_radio_frequency_set(5 + (5 * (channel - 11))); } -/** 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. - * - * @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}; - const int8_t highest_value = allowed_values[(sizeof(allowed_values) / sizeof(allowed_values[0])) - 1]; - if (dbm > highest_value) - { - dbm = highest_value; - } - else - { - for (uint32_t i = 0; i < sizeof(allowed_values) / sizeof(allowed_values[0]); i++) - { - if (dbm <= allowed_values[i]) - { - dbm = allowed_values[i]; - break; - } - } - } - - nrf_radio_tx_power_set(dbm); -} - /*************************************************************************************************** * @section Shorts management @@ -402,6 +376,7 @@ static void auto_ack_abort(radio_state_t state_to_set) case NRF_RADIO_STATE_RX_DISABLE: case NRF_RADIO_STATE_DISABLED: + case NRF_RADIO_STATE_TX_DISABLE: // Do not trigger DISABLE task in those states to prevent double DISABLED events. state_set(state_to_set); break; @@ -464,6 +439,7 @@ static void nrf_radio_init(void) nrf_radio_config_preamble_length_set(NRF_RADIO_PREAMBLE_LENGTH_32BIT_ZERO); nrf_radio_config_crc_included_set(true); nrf_radio_config_max_length_set(MAX_PACKET_SIZE); + nrf_radio_ramp_up_mode_set(NRF_RADIO_RAMP_UP_MODE_DEFAULT); // Configure CRC nrf_radio_crc_length_set(CRC_LENGTH); @@ -471,10 +447,7 @@ static void nrf_radio_init(void) nrf_radio_crc_polynominal_set(CRC_POLYNOMIAL); // Configure CCA - nrf_radio_cca_mode_set(RADIO_CCA_MODE); - nrf_radio_cca_ed_threshold_set(RADIO_CCA_ED_THRESHOLD); - nrf_radio_cca_corr_threshold_set(RADIO_CCA_CORR_THRESHOLD); - nrf_radio_cca_corr_counter_set(RADIO_CCA_CORR_LIMIT); + cca_configuration_update(); // Configure MAC Header Match Unit nrf_radio_mhmu_search_pattern_set(0); @@ -483,9 +456,7 @@ static void nrf_radio_init(void) nrf_radio_int_enable(NRF_RADIO_INT_FRAMESTART_MASK); nrf_radio_int_enable(NRF_RADIO_INT_END_MASK); nrf_radio_int_enable(NRF_RADIO_INT_DISABLED_MASK); -#if !RADIO_SHORT_CCAIDLE_TXEN nrf_radio_int_enable(NRF_RADIO_INT_CCAIDLE_MASK); -#endif nrf_radio_int_enable(NRF_RADIO_INT_CCABUSY_MASK); nrf_radio_int_enable(NRF_RADIO_INT_READY_MASK); nrf_radio_int_enable(NRF_RADIO_INT_BCMATCH_MASK); @@ -603,6 +574,19 @@ void nrf_raal_timeslot_started(void) break; + case RADIO_STATE_CCA: + case RADIO_STATE_CONTINUOUS_CARRIER: + nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); + break; + + case RADIO_STATE_SLEEP: + // This case may happen when sleep is requested by the next higher layer right before + // timeslot starts and the driver uses SWI for requests and notifications. In this case + // RAAL may report timeslot start event when exiting sleep request critical section. + // The driver is already in SLEEP state but did not request timeslot end yet - it will + // be requested in the next SWI handler. + break; + default: assert(false); } @@ -619,7 +603,7 @@ void nrf_raal_timeslot_ended(void) switch (m_state) { - case RADIO_STATE_CCA: + case RADIO_STATE_CCA_BEFORE_TX: case RADIO_STATE_TX_FRAME: case RADIO_STATE_RX_ACK: nrf_drv_radio802154_notify_busy_channel(); @@ -638,6 +622,8 @@ void nrf_raal_timeslot_ended(void) case RADIO_STATE_SLEEP: case RADIO_STATE_WAITING_TIMESLOT: case RADIO_STATE_ED: + case RADIO_STATE_CCA: + case RADIO_STATE_CONTINUOUS_CARRIER: // Intentionally empty. break; @@ -645,7 +631,7 @@ void nrf_raal_timeslot_ended(void) case RADIO_STATE_RX_HEADER: case RADIO_STATE_RX_FRAME: case RADIO_STATE_TX_ACK: - case RADIO_STATE_CCA: + case RADIO_STATE_CCA_BEFORE_TX: case RADIO_STATE_TX_FRAME: case RADIO_STATE_RX_ACK: mutex_lock(); @@ -952,11 +938,15 @@ static inline void irq_end_state_rx_frame(void) /// 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); + assert(nrf_radio_shorts_get() == SHORTS_TX_ACK || + nrf_radio_shorts_get() == SHORTS_RX_FOLLOWING); // In case END is handled before READY shorts_disable(); received_frame_notify(); + // Clear event READY in case CPU was halted and event END is handled before READY. + nrf_radio_event_clear(NRF_RADIO_EVENT_READY); + state_set(RADIO_STATE_WAITING_RX_FRAME); // Receiver is enabled by shorts. } @@ -964,7 +954,7 @@ static inline void irq_end_state_tx_ack(void) /** This event may occur at the beginning of transmission procedure (the procedure already has * disabled shorts). */ -static inline void irq_end_state_cca(void) +static inline void irq_end_state_cca_before_tx(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); } @@ -975,6 +965,9 @@ static inline void irq_end_state_tx_frame(void) shorts_disable(); assert(nrf_radio_shorts_get() == SHORTS_IDLE); + // Clear event READY in case CPU was halted and event END is handled before READY. + nrf_radio_event_clear(NRF_RADIO_EVENT_READY); + if (!ack_is_requested(mp_tx_data)) { nrf_drv_radio802154_notify_transmitted(NULL, 0, 0); @@ -1040,7 +1033,7 @@ static inline void irq_disabled_state_waiting_rx_frame(void) mutex_unlock(); rx_buffer_in_use_set(nrf_drv_radio802154_rx_buffer_free_find()); - tx_power_set(nrf_drv_radio802154_pib_tx_power_get()); + nrf_radio_tx_power_set(nrf_drv_radio802154_pib_tx_power_get()); // Clear this event after RXEN task in case event is triggered just before. nrf_radio_event_clear(NRF_RADIO_EVENT_DISABLED); @@ -1087,7 +1080,7 @@ static inline void irq_disabled_state_tx_ack(void) * * The radio is disabled and the drivers enables receiver in order to start CCA procedure. */ -static inline void irq_disabled_state_cca(void) +static inline void irq_disabled_state_cca_before_tx(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); assert(nrf_radio_state_get() == NRF_RADIO_STATE_DISABLED); @@ -1137,6 +1130,29 @@ static inline void irq_disabled_state_ed(void) nrf_radio_task_trigger(NRF_RADIO_TASK_RXEN); } +/** This event is generated before stand-alone CCA procedure. + * + * The radio is disabled and the driver enables receiver in order to start CCA procedure. + */ +static inline void irq_disabled_state_cca(void) +{ + assert(nrf_radio_shorts_get() == SHORTS_IDLE); + assert(nrf_radio_state_get() == NRF_RADIO_STATE_DISABLED); + nrf_radio_task_trigger(NRF_RADIO_TASK_RXEN); +} + +/** This event is generated before continuous-carrier procedure is started. + * + * The radio is disabled and the driver enables transmitter in order to start emitting carrier + * continuously. + */ +static inline void irq_disabled_state_continuous_carrier(void) +{ + assert(nrf_radio_shorts_get() == SHORTS_IDLE); + assert(nrf_radio_state_get() == NRF_RADIO_STATE_DISABLED); + nrf_radio_task_trigger(NRF_RADIO_TASK_TXEN); +} + /** 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. @@ -1172,7 +1188,7 @@ static inline void irq_ready_state_tx_ack(void) * * The driver prepares for transmission and starts CCA procedure. */ -static inline void irq_ready_state_cca(void) +static inline void irq_ready_state_cca_before_tx(void) { assert(nrf_radio_shorts_get() == SHORTS_IDLE); assert(nrf_radio_state_get() == NRF_RADIO_STATE_RX_IDLE); @@ -1217,17 +1233,43 @@ static inline void irq_ready_state_ed(void) nrf_radio_task_trigger(NRF_RADIO_TASK_EDSTART); } +/// This event is generated when receiver is ready to start CCA procedure. +static inline void irq_ready_state_cca(void) +{ + assert(nrf_radio_shorts_get() == SHORTS_IDLE); + assert(nrf_radio_state_get() == NRF_RADIO_STATE_RX_IDLE); + nrf_radio_task_trigger(NRF_RADIO_TASK_CCASTART); +} + +/// This event is generated when transmitter is emitting carrier continuously. +static inline void irq_ready_state_continuous_carrier(void) +{ + assert(nrf_radio_shorts_get() == SHORTS_IDLE); + assert(nrf_radio_state_get() == NRF_RADIO_STATE_TX_IDLE); +} + #if !RADIO_SHORT_CCAIDLE_TXEN /// This event is generated when CCA reports that channel is idle. -static inline void irq_ccaidle(void) +static inline void irq_ccaidle_state_tx_frame(void) { - 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 idle channel during stand-alone procedure. +static inline void irq_ccaidle_state_cca(void) +{ + assert(nrf_radio_shorts_get() == SHORTS_IDLE); + assert(nrf_radio_state_get() == NRF_RADIO_STATE_RX_IDLE); + + nrf_drv_radio802154_notify_cca(true); + + state_set(RADIO_STATE_WAITING_RX_FRAME); + nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); +} + /// This event is generated when CCA reports busy channel prior to transmission. static inline void irq_ccabusy_state_tx_frame(void) { @@ -1242,6 +1284,18 @@ static inline void irq_ccabusy_state_tx_frame(void) nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); } +/// This event is generated when CCA reports busy channel during stand-alone procedure. +static inline void irq_ccabusy_state_cca(void) +{ + assert(nrf_radio_shorts_get() == SHORTS_IDLE); + assert(nrf_radio_state_get() == NRF_RADIO_STATE_RX_IDLE); + + nrf_drv_radio802154_notify_cca(false); + + state_set(RADIO_STATE_WAITING_RX_FRAME); + nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); +} + /// This event is generated when energy detection procedure ends. static inline void irq_edend(void) { @@ -1263,13 +1317,16 @@ static inline void irq_edend(void) { nrf_drv_radio802154_notify_energy_detected(m_ed_result); + // In case channel change was requested during energy detection procedure. + channel_set(nrf_drv_radio802154_pib_channel_get()); + state_set(RADIO_STATE_WAITING_RX_FRAME); nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); } } /// Handler of radio interrupts. -void RADIO_IRQHandler(void) +static inline void irq_handler(void) { nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_IRQ_HANDLER); @@ -1293,7 +1350,7 @@ void RADIO_IRQHandler(void) break; case RADIO_STATE_TX_ACK: - case RADIO_STATE_CCA: // This could happen at the beginning of transmission procedure. + case RADIO_STATE_CCA_BEFORE_TX: // This could happen at the beginning of transmission procedure. case RADIO_STATE_WAITING_TIMESLOT: break; @@ -1351,9 +1408,9 @@ void RADIO_IRQHandler(void) irq_end_state_tx_ack(); break; - case RADIO_STATE_CCA: // This could happen at the beginning of transmission procedure - // (the procedure already has disabled shorts). - irq_end_state_cca(); + case RADIO_STATE_CCA_BEFORE_TX: // This could happen at the beginning of transmission + // procedure (the procedure already has disabled shorts) + irq_end_state_cca_before_tx(); break; case RADIO_STATE_TX_FRAME: @@ -1399,8 +1456,8 @@ void RADIO_IRQHandler(void) irq_disabled_state_tx_ack(); break; - case RADIO_STATE_CCA: - irq_disabled_state_cca(); + case RADIO_STATE_CCA_BEFORE_TX: + irq_disabled_state_cca_before_tx(); break; case RADIO_STATE_TX_FRAME: @@ -1415,6 +1472,14 @@ void RADIO_IRQHandler(void) irq_disabled_state_ed(); break; + case RADIO_STATE_CCA: + irq_disabled_state_cca(); + break; + + case RADIO_STATE_CONTINUOUS_CARRIER: + irq_disabled_state_continuous_carrier(); + break; + case RADIO_STATE_WAITING_TIMESLOT: // Exit as soon as possible when waiting for timeslot. break; @@ -1441,8 +1506,8 @@ void RADIO_IRQHandler(void) irq_ready_state_tx_ack(); break; - case RADIO_STATE_CCA: - irq_ready_state_cca(); + case RADIO_STATE_CCA_BEFORE_TX: + irq_ready_state_cca_before_tx(); break; case RADIO_STATE_TX_FRAME: @@ -1457,6 +1522,14 @@ void RADIO_IRQHandler(void) irq_ready_state_ed(); break; + case RADIO_STATE_CCA: + irq_ready_state_cca(); + break; + + case RADIO_STATE_CONTINUOUS_CARRIER: + irq_ready_state_continuous_carrier(); + break; + case RADIO_STATE_WAITING_TIMESLOT: // Exit as soon as possible when waiting for timeslot. break; @@ -1468,17 +1541,33 @@ void RADIO_IRQHandler(void) nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_EVENT_READY); } -#if !RADIO_SHORT_CCAIDLE_TXEN if (nrf_radio_event_get(NRF_RADIO_EVENT_CCAIDLE)) { nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_EVENT_CCAIDLE); nrf_radio_event_clear(NRF_RADIO_EVENT_CCAIDLE); - irq_ccaidle(); + switch (m_state) + { + case RADIO_STATE_TX_FRAME: +#if !RADIO_SHORT_CCAIDLE_TXEN + irq_ccaidle_state_tx_frame(); +#endif + break; + + case RADIO_STATE_CCA: + irq_ccaidle_state_cca(); + break; + + case RADIO_STATE_WAITING_TIMESLOT: + // Exit as soon as possible when waiting for timeslot. + break; + + default: + assert(false); + } nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_EVENT_CCAIDLE); } -#endif if (nrf_radio_event_get(NRF_RADIO_EVENT_CCABUSY)) { @@ -1491,6 +1580,10 @@ void RADIO_IRQHandler(void) irq_ccabusy_state_tx_frame(); break; + case RADIO_STATE_CCA: + irq_ccabusy_state_cca(); + break; + case RADIO_STATE_WAITING_TIMESLOT: // Exit as soon as possible when waiting for timeslot. break; @@ -1626,7 +1719,7 @@ bool nrf_drv_radio802154_fsm_sleep(void) return result; } -bool nrf_drv_radio802154_fsm_receive(uint8_t channel) +bool nrf_drv_radio802154_fsm_receive(void) { bool result = false; @@ -1637,22 +1730,9 @@ bool nrf_drv_radio802154_fsm_receive(uint8_t channel) case RADIO_STATE_RX_FRAME: case RADIO_STATE_TX_ACK: result = true; - - if (channel_get() != channel) - { - channel_set(channel); - nrf_drv_radio802154_pib_channel_set(channel); - if (mutex_lock()) - { - auto_ack_abort(RADIO_STATE_WAITING_RX_FRAME); - } - } - break; case RADIO_STATE_DISABLING: - channel_set(channel); - nrf_drv_radio802154_pib_channel_set(channel); state_set(RADIO_STATE_WAITING_RX_FRAME); result = true; // TASK DISABLE was already triggered. Wait for event DISABLED. @@ -1660,24 +1740,28 @@ bool nrf_drv_radio802154_fsm_receive(uint8_t channel) case RADIO_STATE_SLEEP: assert(mutex_lock()); - state_set(RADIO_STATE_WAITING_TIMESLOT); - nrf_drv_radio802154_pib_channel_set(channel); - nrf_raal_continuous_mode_enter(); result = true; break; - case RADIO_STATE_CCA: + case RADIO_STATE_CCA_BEFORE_TX: case RADIO_STATE_TX_FRAME: case RADIO_STATE_RX_ACK: tx_procedure_abort(); result = true; break; + case RADIO_STATE_CONTINUOUS_CARRIER: + state_set(RADIO_STATE_WAITING_RX_FRAME); + nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); + result = true; + break; + case RADIO_STATE_ED: - // Ignore receive function during energy detection procedure. + case RADIO_STATE_CCA: + // Ignore receive function during energy detection or CCA procedure. break; case RADIO_STATE_WAITING_TIMESLOT: @@ -1693,7 +1777,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 cca) +bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, bool cca) { bool result = false; mp_tx_data = p_data; @@ -1705,11 +1789,9 @@ 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(cca ? RADIO_STATE_CCA_BEFORE_TX : RADIO_STATE_TX_FRAME); - auto_ack_abort(cca ? RADIO_STATE_CCA : RADIO_STATE_TX_FRAME); - - tx_power_set(power); + nrf_radio_tx_power_set(nrf_drv_radio802154_pib_tx_power_get()); nrf_radio_packet_ptr_set(p_data); // Clear events that could have happened in critical section due to receiving frame or RX ramp up. @@ -1741,9 +1823,9 @@ bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, uint8_t channel, i return result; } -bool nrf_drv_radio802154_fsm_energy_detection(uint8_t tx_channel, uint32_t time_us) +bool nrf_drv_radio802154_fsm_energy_detection(uint32_t time_us) { - bool result = false; + bool result = false; switch (m_state) { @@ -1751,7 +1833,6 @@ bool nrf_drv_radio802154_fsm_energy_detection(uint8_t tx_channel, uint32_t time_ if (mutex_lock()) { state_set(RADIO_STATE_ED); - nrf_drv_radio802154_pib_channel_set(tx_channel); m_ed_time_left = time_us; m_ed_result = 0; @@ -1769,9 +1850,6 @@ bool nrf_drv_radio802154_fsm_energy_detection(uint8_t tx_channel, uint32_t time_ if (ed_iter_setup(time_us)) { - nrf_drv_radio802154_pib_channel_set(tx_channel); - channel_set(tx_channel); - auto_ack_abort(RADIO_STATE_ED); assert(nrf_radio_shorts_get() == SHORTS_IDLE); @@ -1807,6 +1885,85 @@ bool nrf_drv_radio802154_fsm_energy_detection(uint8_t tx_channel, uint32_t time_ return result; } +bool nrf_drv_radio802154_fsm_cca(void) +{ + bool result = false; + + switch (m_state) + { + case RADIO_STATE_SLEEP: + if (mutex_lock()) + { + state_set(RADIO_STATE_CCA); + + nrf_raal_continuous_mode_enter(); + + result = true; + } + + break; + + case RADIO_STATE_WAITING_RX_FRAME: + if (mutex_lock()) + { + if (nrf_raal_timeslot_request(nrf_drv_radio802154_cca_duration_get())) + { + auto_ack_abort(RADIO_STATE_CCA); + + // Clear events that could have happened in critical section due to receiving + // frame or RX ramp up. + nrf_radio_event_clear(NRF_RADIO_EVENT_FRAMESTART); + nrf_radio_event_clear(NRF_RADIO_EVENT_BCMATCH); + nrf_radio_event_clear(NRF_RADIO_EVENT_END); + nrf_radio_event_clear(NRF_RADIO_EVENT_READY); + } + else + { + state_set(RADIO_STATE_CCA); + } + + result = true; + } + + break; + + case RADIO_STATE_DISABLING: + case RADIO_STATE_RX_HEADER: + case RADIO_STATE_RX_FRAME: + case RADIO_STATE_TX_ACK: + case RADIO_STATE_WAITING_TIMESLOT: + break; + + default: + assert(false); // This should not happen. + } + + return result; +} + +bool nrf_drv_radio802154_fsm_continuous_carrier(void) +{ + bool result = false; + + if (mutex_lock()) + { + assert(m_state == RADIO_STATE_WAITING_RX_FRAME || + m_state == RADIO_STATE_SLEEP); + + auto_ack_abort(RADIO_STATE_CONTINUOUS_CARRIER); + + // Clear events that could have happened in critical section due to receiving frame or RX ramp up. + nrf_radio_event_clear(NRF_RADIO_EVENT_FRAMESTART); + nrf_radio_event_clear(NRF_RADIO_EVENT_BCMATCH); + nrf_radio_event_clear(NRF_RADIO_EVENT_END); + nrf_radio_event_clear(NRF_RADIO_EVENT_READY); + + result = true; + } + + return result; +} + void nrf_drv_radio802154_fsm_notify_buffer_free(rx_buffer_t * p_buffer) { p_buffer->free = true; @@ -1857,3 +2014,84 @@ void nrf_drv_radio802154_fsm_notify_buffer_free(rx_buffer_t * p_buffer) break; } } + +void nrf_drv_radio802154_fsm_channel_update(void) +{ + switch (m_state) + { + case RADIO_STATE_WAITING_RX_FRAME: + assert(mutex_lock()); + + channel_set(nrf_drv_radio802154_pib_channel_get()); + auto_ack_abort(RADIO_STATE_WAITING_RX_FRAME); + + // Clear events that could have happened in critical section due to receiving + // frame or RX ramp up. + nrf_radio_event_clear(NRF_RADIO_EVENT_FRAMESTART); + nrf_radio_event_clear(NRF_RADIO_EVENT_BCMATCH); + nrf_radio_event_clear(NRF_RADIO_EVENT_END); + nrf_radio_event_clear(NRF_RADIO_EVENT_READY); + + break; + + case RADIO_STATE_CONTINUOUS_CARRIER: + channel_set(nrf_drv_radio802154_pib_channel_get()); + nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE); + break; + + case RADIO_STATE_RX_HEADER: + case RADIO_STATE_RX_FRAME: + case RADIO_STATE_TX_ACK: + case RADIO_STATE_CCA: + case RADIO_STATE_TX_FRAME: + case RADIO_STATE_RX_ACK: + channel_set(nrf_drv_radio802154_pib_channel_get()); + break; + + case RADIO_STATE_DISABLING: + case RADIO_STATE_SLEEP: + case RADIO_STATE_WAITING_TIMESLOT: + case RADIO_STATE_CCA_BEFORE_TX: + case RADIO_STATE_ED: + // Don't perform any action in these states (channel will be updated when receiver is + // enabled). + break; + + } +} + +void nrf_drv_radio802154_fsm_cca_cfg_update(void) +{ + switch (m_state) + { + case RADIO_STATE_WAITING_RX_FRAME: + case RADIO_STATE_RX_HEADER: + case RADIO_STATE_RX_FRAME: + case RADIO_STATE_TX_ACK: + case RADIO_STATE_CCA: + case RADIO_STATE_CCA_BEFORE_TX: + case RADIO_STATE_TX_FRAME: + case RADIO_STATE_RX_ACK: + cca_configuration_update(); + break; + + case RADIO_STATE_DISABLING: + case RADIO_STATE_SLEEP: + case RADIO_STATE_WAITING_TIMESLOT: + case RADIO_STATE_ED: + case RADIO_STATE_CONTINUOUS_CARRIER: + // Don't perform any action in these states (CCA configuration will be updated when + // receiver is enabled). + break; + + } +} + +#if RADIO_INTERNAL_IRQ_HANDLING +void RADIO_IRQHandler(void) +#else // RADIO_INTERNAL_IRQ_HADLING +void nrf_drv_radio802154_fsm_irq_handler(void) +#endif // RADIO_INTERNAL_IRQ_HANDLING +{ + irq_handler(); +} 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 2d4f216a9..d890e8066 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h @@ -39,6 +39,7 @@ #include #include +#include "nrf_drv_radio802154_config.h" #include "nrf_drv_radio802154_rx_buffer.h" #ifdef __cplusplus @@ -51,23 +52,29 @@ extern "C" { typedef enum { // Sleep - RADIO_STATE_DISABLING, // Entering low power (DISABLED) mode - RADIO_STATE_SLEEP, // Low power (DISABLED) mode + RADIO_STATE_DISABLING, // Entering low power (DISABLED) mode + RADIO_STATE_SLEEP, // Low power (DISABLED) mode // Receive - RADIO_STATE_WAITING_TIMESLOT, // Radio is inactive due to denied time slot - RADIO_STATE_WAITING_RX_FRAME, // Waiting for frame in receiver mode - RADIO_STATE_RX_HEADER, // Received SFD, receiving MAC header - RADIO_STATE_RX_FRAME, // Received MAC destination address, receiving rest of the frame - RADIO_STATE_TX_ACK, // Received frame and transmitting ACK + RADIO_STATE_WAITING_TIMESLOT, // Radio is inactive due to denied time slot + RADIO_STATE_WAITING_RX_FRAME, // Waiting for frame in receiver mode + RADIO_STATE_RX_HEADER, // Received SFD, receiving MAC header + RADIO_STATE_RX_FRAME, // Received MAC destination address, receiving rest of the frame + RADIO_STATE_TX_ACK, // Received frame and transmitting ACK // Transmit - RADIO_STATE_CCA, // Performing CCA - RADIO_STATE_TX_FRAME, // Transmitting data frame (or beacon) - RADIO_STATE_RX_ACK, // Receiving ACK after transmitted frame + RADIO_STATE_CCA_BEFORE_TX, // Performing CCA prior to transmission + RADIO_STATE_TX_FRAME, // Transmitting data frame (or beacon) + RADIO_STATE_RX_ACK, // Receiving ACK after transmitted frame // Energy Detection - RADIO_STATE_ED, // Performing Energy Detection procedure + RADIO_STATE_ED, // Performing Energy Detection procedure + + // CCA + RADIO_STATE_CCA, // Performing CCA procedure + + // Continuous carrier + RADIO_STATE_CONTINUOUS_CARRIER, // Emitting continuous carrier wave. } radio_state_t; /** @@ -94,10 +101,10 @@ radio_state_t nrf_drv_radio802154_fsm_state_get(void); /** * @brief Request transition to SLEEP state. * - * @note This function shall be called from critical section context. It shall not be interrupted - * by RADIO event handler or RAAL notification. + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. * - * @note This function should be called when the driver is in RECEIVE state. + * @note This function shall be called when the driver is in RECEIVE state. * * @retval true Entering SLEEP state succeeded. * @retval false Entering SLEEP state failed (driver is performing other procedure). @@ -107,52 +114,75 @@ bool nrf_drv_radio802154_fsm_sleep(void); /** * @brief Request transition to RECEIVE state. * - * @note This function shall be called from critical section context. It shall not be interrupted - * by RADIO event handler or RAAL notification. + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. * - * @note This function should be called when the driver is in SLEEP or TRANSMIT state. - * - * @param[in] channel Channel number that the radio should use to receive frames. + * @note This function shall be called when the driver is in SLEEP or TRANSMIT state. * * @retval true Entering RECEIVE state succeeded. * @retval false Entering RECEIVE state failed (driver is performing other procedure). */ -bool nrf_drv_radio802154_fsm_receive(uint8_t channel); +bool nrf_drv_radio802154_fsm_receive(void); /** * @brief Request transition to TRANSMIT state. * - * @note This function shall be called from critical section context. It shall not be interrupted - * by RADIO event handler or RAAL notification. + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. * - * @note This function should be called when the driver is in RECEIVE state. + * @note This function shall be called when the driver is in RECEIVE state. * * @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 cca); +bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, bool cca); /** * @brief Request transition to ENERGY_DETECTION state. * - * @note This function shall be called from critical section context. It shall not be interrupted - * by RADIO event handler or RAAL notification. + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. * - * @note This function should be called when the driver is in SLEEP or RECEIVE state. When Energy + * @note This function shall be called when the driver is in SLEEP or RECEIVE state. When Energy * detection procedure is finished the driver will transit to RECEIVE state. * - * @param[in] channel Channel number that the radio should use to perform energy detection. * @param[in] time_us Minimal time of energy detection procedure. * * @retval true Entering ENERGY_DETECTION state succeeded. * @retval false Entering ENERGY_DETECTION state failed (driver is performing other procedure). */ -bool nrf_drv_radio802154_fsm_energy_detection(uint8_t channel, uint32_t time_us); +bool nrf_drv_radio802154_fsm_energy_detection(uint32_t time_us); + +/** + * @brief Request transition to CCA state. + * + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. + * + * @note This function shall be called when the driver is in SLEEP or RECEIVE state. When CCA + * procedure is finished the driver will transit to RECEIVE state. + * + * @retval true Entering CCA state succeeded. + * @retval false Entering CCA state failed (driver is performing other procedure). + */ +bool nrf_drv_radio802154_fsm_cca(void); + +/** + * @brief Request transition to CONTINUOUS_CARRIER state. + * + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. + * + * @note This function shall be called when the driver is in RECEIVE or SLEEP state. When + * CONTINUOUS_CARRIER procedure is finished the driver will transit to RECEIVE state. + * + * @retval true Entering CONTINUOUS_CARRIER state succeeded. + * @retval false Entering CONTINUOUS_CARRIER state failed (driver is performing other procedure). + */ +bool nrf_drv_radio802154_fsm_continuous_carrier(void); /*************************************************************************************************** * @section State machine notifications @@ -164,13 +194,33 @@ bool nrf_drv_radio802154_fsm_energy_detection(uint8_t channel, uint32_t time_us) * When there were no free buffers available the FSM does not start receiver. If FSM receives this * notification in changes internal state to make sure receiver is started if requested. * - * @note This function shall be called from critical section context. It shall not be interrupted - * by RADIO event handler or RAAL notification. + * @note This function shall be called from a critical section context. It shall not be interrupted + * by the RADIO event handler or RAAL notification. * * @param[in] p_buffer Pointer to buffer that has been freed. */ void nrf_drv_radio802154_fsm_notify_buffer_free(rx_buffer_t * p_buffer); +/** + * @brief Notify the FSM that next higher layer requested change of the channel. + * + * FSM should update frequency register of the peripheral and in case it is in RECEIVE state the + * receiver should be disabled and enabled again to use new channel. + */ +void nrf_drv_radio802154_fsm_channel_update(void); + +/** + * @brief Notify the FSM that next higher layer requested change of the CCA configuration. + */ +void nrf_drv_radio802154_fsm_cca_cfg_update(void); + +#if !RADIO_INTERNAL_IRQ_HANDLING +/** + * @brief Notify the FSM that there is a pending IRQ that should be handled. + */ +void nrf_drv_radio802154_fsm_irq_handler(void); +#endif // !RADIO_INTERNAL_IRQ_HANDLING + #ifdef __cplusplus } #endif diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification.h index 2f7fcc5bf..137902743 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification.h @@ -78,7 +78,14 @@ void nrf_drv_radio802154_notify_busy_channel(void); * * @param[in] result Detected energy level. */ -void nrf_drv_radio802154_notify_energy_detected(int8_t result); +void nrf_drv_radio802154_notify_energy_detected(uint8_t result); + +/** + * @brief Notify next higher layer that CCA procedure ended. + * + * @param[in] is_free If detected that channel is free. + */ +void nrf_drv_radio802154_notify_cca(bool is_free); /** *@} diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_direct.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_direct.c index b3bbfa5f9..e4eee1f42 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_direct.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_direct.c @@ -48,12 +48,12 @@ void nrf_drv_radio802154_notification_init(void) void nrf_drv_radio802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi) { - nrf_drv_radio802154_received(p_data, power, lqi); + nrf_drv_radio802154_received_raw(p_data, power, lqi); } void nrf_drv_radio802154_notify_transmitted(uint8_t * p_ack, int8_t power, int8_t lqi) { - nrf_drv_radio802154_transmitted(p_ack, power, lqi); + nrf_drv_radio802154_transmitted_raw(p_ack, power, lqi); } void nrf_drv_radio802154_notify_busy_channel(void) @@ -61,8 +61,13 @@ void nrf_drv_radio802154_notify_busy_channel(void) nrf_drv_radio802154_busy_channel(); } -void nrf_drv_radio802154_notify_energy_detected(int8_t result) +void nrf_drv_radio802154_notify_energy_detected(uint8_t result) { nrf_drv_radio802154_energy_detected(result); } +void nrf_drv_radio802154_notify_cca(bool is_free) +{ + nrf_drv_radio802154_cca_done(is_free); +} + diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_swi.c b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_swi.c index 999c3774b..d01dd7ab2 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_swi.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_swi.c @@ -62,8 +62,13 @@ void nrf_drv_radio802154_notify_busy_channel(void) nrf_drv_radio802154_swi_notify_busy_channel(); } -void nrf_drv_radio802154_notify_energy_detected(int8_t result) +void nrf_drv_radio802154_notify_energy_detected(uint8_t result) { nrf_drv_radio802154_swi_notify_energy_detected(result); } +void nrf_drv_radio802154_notify_cca(bool is_free) +{ + nrf_drv_radio802154_swi_notify_cca(is_free); +} + 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 3f8ed4dda..614a50ba6 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c @@ -36,23 +36,26 @@ #include "nrf_drv_radio802154_pib.h" +#include #include #include #include +#include "nrf_drv_radio802154_config.h" #include "nrf_drv_radio802154_const.h" #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. + nrf_drv_radio802154_cca_cfg_t cca; ///< CCA mode and thresholds. + 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; ///< Buffer containing PIB data. @@ -67,6 +70,11 @@ void nrf_drv_radio802154_pib_init(void) m_data.short_addr[0] = 0xfe; m_data.short_addr[1] = 0xff; memset(m_data.extended_addr, 0, sizeof(m_data.extended_addr)); + + m_data.cca.mode = RADIO_CCA_MODE_DEFAULT; + m_data.cca.ed_threshold = RADIO_CCA_ED_THRESHOLD_DEFAULT; + m_data.cca.corr_threshold = RADIO_CCA_CORR_THRESHOLD_DEFAULT; + m_data.cca.corr_limit = RADIO_CCA_CORR_LIMIT_DEFAULT; } bool nrf_drv_radio802154_pib_promiscuous_get(void) @@ -106,6 +114,24 @@ int8_t nrf_drv_radio802154_pib_tx_power_get(void) void nrf_drv_radio802154_pib_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}; + const int8_t highest_value = allowed_values[(sizeof(allowed_values) / sizeof(allowed_values[0])) - 1]; + if (dbm > highest_value) + { + dbm = highest_value; + } + else + { + for (uint32_t i = 0; i < sizeof(allowed_values) / sizeof(allowed_values[0]); i++) + { + if (dbm <= allowed_values[i]) + { + dbm = allowed_values[i]; + break; + } + } + } + m_data.tx_power = dbm; } @@ -172,3 +198,33 @@ bool nrf_drv_radio802154_pib_dest_addr_matches(const uint8_t * p_psdu) return true; } + +void nrf_drv_radio802154_pib_cca_cfg_set(const nrf_drv_radio802154_cca_cfg_t * p_cca_cfg) +{ + switch (p_cca_cfg->mode) + { + case NRF_RADIO_CCA_MODE_ED: + m_data.cca.mode = p_cca_cfg->mode; + m_data.cca.ed_threshold = p_cca_cfg->ed_threshold; + break; + + case NRF_RADIO_CCA_MODE_CARRIER: + m_data.cca.mode = p_cca_cfg->mode; + m_data.cca.corr_threshold = p_cca_cfg->corr_threshold; + m_data.cca.corr_limit = p_cca_cfg->corr_limit; + break; + + case NRF_RADIO_CCA_MODE_CARRIER_AND_ED: + case NRF_RADIO_CCA_MODE_CARRIER_OR_ED: + memcpy(&m_data.cca, p_cca_cfg, sizeof(m_data.cca)); + break; + + default: + assert(false); + } +} + +void nrf_drv_radio802154_pib_cca_cfg_get(nrf_drv_radio802154_cca_cfg_t * p_cca_cfg) +{ + memcpy(p_cca_cfg, &m_data.cca, sizeof(m_data.cca)); +} diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.h index 519758c9b..f92266b43 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.h @@ -39,6 +39,8 @@ #include #include +#include "nrf_drv_radio802154.h" + #ifdef __cplusplus extern "C" { #endif @@ -147,6 +149,20 @@ void nrf_drv_radio802154_pib_short_address_set(const uint8_t * p_short_address); */ bool nrf_drv_radio802154_pib_dest_addr_matches(const uint8_t * p_psdu); +/** + * @brief Set radio CCA mode and threshold. + * + * @param[in] p_cca_cfg A pointer to the CCA configuration structure. Only fields relevant to selected mode are updated. + */ +void nrf_drv_radio802154_pib_cca_cfg_set(const nrf_drv_radio802154_cca_cfg_t * p_cca_cfg); + +/** + * @brief Get current radio CCA configuration. + * + * @param[out] p_cca_cfg A pointer to the structure for current CCA configuration. + */ +void nrf_drv_radio802154_pib_cca_cfg_get(nrf_drv_radio802154_cca_cfg_t * p_cca_cfg); + #ifdef __cplusplus } #endif diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_procedures_duration.h b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_procedures_duration.h index 172ab775e..a378da9f5 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_procedures_duration.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_procedures_duration.h @@ -90,4 +90,14 @@ static inline uint16_t nrf_drv_radio802154_rx_duration_get(uint8_t psdu_length, return result; } +static inline uint16_t nrf_drv_radio802154_cca_duration_get(void) +{ + // aTurnaroundTime + CCA + uint16_t result = A_TURNAROUND_TIME + A_CCA_DURATION; + + result *= PHY_US_PER_SYMBOL; + + return result; +} + #endif /* NRF_DRV_RADIO802154_PROCEDURES_DURATION_H_ */ 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 fca55153a..7e3091dd7 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h @@ -61,36 +61,47 @@ bool nrf_drv_radio802154_request_sleep(void); /** * @brief Request entering receive state. * - * @param[in] channel Channel number used to receive data. - * * @retval true The driver will enter receive state. * @retval false The driver cannot enter receive state due to ongoing operation. */ -bool nrf_drv_radio802154_request_receive(uint8_t channel); +bool nrf_drv_radio802154_request_receive(void); /** * @brief Request entering transmit state. * * @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 cca); +bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, bool cca); /** * @brief Request entering energy detection state. * - * @param[in] channel Channel number used to perform energy detection procedure. * @param[in] time_us Requested duration of energy detection procedure. * * @retval true The driver will enter energy detection state. * @retval false The driver cannot enter energy detection state due to ongoing operation. */ -bool nrf_drv_radio802154_request_energy_detection(uint8_t channel, uint32_t time_us); +bool nrf_drv_radio802154_request_energy_detection(uint32_t time_us); + +/** + * @brief Request entering CCA state. + * + * @retval true The driver will enter CCA state. + * @retval false The driver cannot enter CCA state due to ongoing operation. + */ +bool nrf_drv_radio802154_request_cca(void); + +/** + * @brief Request entering continuous carrier state. + * + * @retval true The driver will enter continuous carrier state. + * @retval false The driver cannot enter continuous carrier state due to ongoing operation. + */ +bool nrf_drv_radio802154_request_continuous_carrier(void); /** * @brief Request the driver to free given buffer. @@ -99,6 +110,16 @@ bool nrf_drv_radio802154_request_energy_detection(uint8_t channel, uint32_t time */ void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data); +/** + * @brief Request the driver to update channel number used by the RADIO peripheral. + */ +void nrf_drv_radio802154_request_channel_update(void); + +/** + * @brief Request the driver to update CCA configuration used by the RADIO peripheral. + */ +void nrf_drv_radio802154_request_cca_cfg_update(void); + /** *@} **/ 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 8639c97fe..9484a70d8 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 @@ -61,34 +61,56 @@ bool nrf_drv_radio802154_request_sleep(void) return result; } -bool nrf_drv_radio802154_request_receive(uint8_t channel) +bool nrf_drv_radio802154_request_receive(void) { bool result; nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_receive(channel); + result = nrf_drv_radio802154_fsm_receive(); nrf_drv_radio802154_critical_section_exit(); return result; } -bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca) +bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, bool cca) { bool result; nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_transmit(p_data, channel, power, cca); + result = nrf_drv_radio802154_fsm_transmit(p_data, cca); nrf_drv_radio802154_critical_section_exit(); return result; } -bool nrf_drv_radio802154_request_energy_detection(uint8_t channel, uint32_t time_us) +bool nrf_drv_radio802154_request_energy_detection(uint32_t time_us) { bool result; nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_energy_detection(channel, time_us); + result = nrf_drv_radio802154_fsm_energy_detection(time_us); + + nrf_drv_radio802154_critical_section_exit(); + return result; +} + +bool nrf_drv_radio802154_request_cca(void) +{ + bool result; + nrf_drv_radio802154_critical_section_enter(); + + result = nrf_drv_radio802154_fsm_cca(); + + nrf_drv_radio802154_critical_section_exit(); + return result; +} + +bool nrf_drv_radio802154_request_continuous_carrier(void) +{ + bool result; + nrf_drv_radio802154_critical_section_enter(); + + result = nrf_drv_radio802154_fsm_continuous_carrier(); nrf_drv_radio802154_critical_section_exit(); return result; @@ -102,3 +124,21 @@ void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data) nrf_drv_radio802154_critical_section_exit(); } + +void nrf_drv_radio802154_request_channel_update(void) +{ + nrf_drv_radio802154_critical_section_enter(); + + nrf_drv_radio802154_fsm_channel_update(); + + nrf_drv_radio802154_critical_section_exit(); +} + +void nrf_drv_radio802154_request_cca_cfg_update(void) +{ + nrf_drv_radio802154_critical_section_enter(); + + nrf_drv_radio802154_fsm_cca_cfg_update(); + + nrf_drv_radio802154_critical_section_exit(); +} 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 963c18e93..e7275785c 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 @@ -102,55 +102,91 @@ bool nrf_drv_radio802154_request_sleep(void) return result; } -bool nrf_drv_radio802154_request_receive(uint8_t channel) +bool nrf_drv_radio802154_request_receive(void) { bool result = false; if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_receive(channel); + result = nrf_drv_radio802154_fsm_receive(); nrf_drv_radio802154_critical_section_exit(); } else { - nrf_drv_radio802154_swi_receive(channel, &result); + nrf_drv_radio802154_swi_receive(&result); } return result; } -bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, uint8_t channel, int8_t power, bool cca) +bool nrf_drv_radio802154_request_transmit(const uint8_t * p_data, bool cca) { bool result = false; if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_transmit(p_data, channel, power, cca); + result = nrf_drv_radio802154_fsm_transmit(p_data, cca); nrf_drv_radio802154_critical_section_exit(); } else { - nrf_drv_radio802154_swi_transmit(p_data, channel, power, cca, &result); + nrf_drv_radio802154_swi_transmit(p_data, cca, &result); } return result; } -bool nrf_drv_radio802154_request_energy_detection(uint8_t channel, uint32_t time_us) +bool nrf_drv_radio802154_request_energy_detection(uint32_t time_us) { bool result = false; if (active_vector_priority_is_high()) { nrf_drv_radio802154_critical_section_enter(); - result = nrf_drv_radio802154_fsm_energy_detection(channel, time_us); + result = nrf_drv_radio802154_fsm_energy_detection(time_us); nrf_drv_radio802154_critical_section_exit(); } else { - nrf_drv_radio802154_swi_energy_detection(channel, time_us, &result); + nrf_drv_radio802154_swi_energy_detection(time_us, &result); + } + + return result; +} + +bool nrf_drv_radio802154_request_cca(void) +{ + bool result = false; + + if (active_vector_priority_is_high()) + { + nrf_drv_radio802154_critical_section_enter(); + result = nrf_drv_radio802154_fsm_cca(); + nrf_drv_radio802154_critical_section_exit(); + } + else + { + nrf_drv_radio802154_swi_cca(&result); + } + + return result; +} + +bool nrf_drv_radio802154_request_continuous_carrier(void) +{ + bool result = false; + + if (active_vector_priority_is_high()) + { + nrf_drv_radio802154_critical_section_enter(); + result = nrf_drv_radio802154_fsm_continuous_carrier(); + nrf_drv_radio802154_critical_section_exit(); + } + else + { + nrf_drv_radio802154_swi_continuous_carrier(&result); } return result; @@ -169,3 +205,32 @@ void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data) nrf_drv_radio802154_swi_buffer_free(p_data); } } + +void nrf_drv_radio802154_request_channel_update(void) +{ + if (active_vector_priority_is_high()) + { + nrf_drv_radio802154_critical_section_enter(); + nrf_drv_radio802154_fsm_channel_update(); + nrf_drv_radio802154_critical_section_exit(); + } + else + { + nrf_drv_radio802154_swi_channel_update(); + } +} + +void nrf_drv_radio802154_request_cca_cfg_update(void) +{ + if (active_vector_priority_is_high()) + { + nrf_drv_radio802154_critical_section_enter(); + nrf_drv_radio802154_fsm_cca_cfg_update(); + nrf_drv_radio802154_critical_section_exit(); + } + else + { + nrf_drv_radio802154_swi_cca_cfg_update(); + } +} + 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 fbecfc320..75484e4d0 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c @@ -48,6 +48,8 @@ #include "hal/nrf_egu.h" #include "raal/nrf_raal_api.h" +#include + /** Size of notification queue. * * One slot for each receive buffer, one for transmission, one for busy channel and one for energy @@ -83,6 +85,7 @@ typedef enum NTF_TYPE_TRANSMITTED, ///< Frame transmitted NTF_TYPE_CHANNEL_BUSY, ///< Frame transmission failure NTF_TYPE_ENERGY_DETECTED, ///< Energy detection procedure ended + NTF_TYPE_CCA, ///< CCA procedure ended } nrf_drv_radio802154_ntf_type_t; /// Notification data in the notification queue. @@ -109,6 +112,11 @@ typedef struct { int8_t result; ///< Energy detection result. } energy_detected; ///< Energy detection details. + + struct + { + bool result; ///< CCA result. + } cca; ///< CCA details. } data; ///< Notification data depending on it's type. } nrf_drv_radio802154_ntf_data_t; @@ -119,7 +127,11 @@ typedef enum REQ_TYPE_RECEIVE, REQ_TYPE_TRANSMIT, REQ_TYPE_ENERGY_DETECTION, + REQ_TYPE_CCA, + REQ_TYPE_CONTINUOUS_CARRIER, REQ_TYPE_BUFFER_FREE, + REQ_TYPE_CHANNEL_UPDATE, + REQ_TYPE_CCA_CFG_UPDATE } nrf_drv_radio802154_req_type_t; /// Request data in request queue. @@ -136,25 +148,31 @@ typedef struct struct { bool * p_result; ///< Receive request result. - uint8_t channel; ///< Channel to receive on. } receive; ///< Receive request details. struct { 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; ///< 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 + { + bool * p_result; ///< CCA request result. + } cca; ///< CCA request details. + + struct + { + bool * p_result; ///< Continuous carrier request result. + } continuous_carrier; ///< Continuous carrier request details. + struct { rx_buffer_t * p_data; ///< Pointer to receive buffer to free. @@ -287,6 +305,42 @@ static bool req_queue_is_empty(void) return queue_is_empty(m_req_r_ptr, m_req_w_ptr); } +/** + * Enter request block. + * + * This is a helper function used in all request functions to atomically + * find an empty slot in request queue and allow atomic slot update. + * + * @return Pointer to an empty slot in the request queue. + */ +static nrf_drv_radio802154_req_data_t * req_enter(void) +{ + __disable_irq(); + __DSB(); + __ISB(); + + assert(!req_queue_is_full()); + + return &m_req_queue[m_req_w_ptr]; +} + +/** + * Exit request block. + * + * This is a helper function used in all request functions to end atomic slot update + * and trigger SWI to process the request from the slot. + */ +static void req_exit(void) +{ + req_queue_ptr_increment(&m_req_w_ptr); + + nrf_egu_task_trigger(SWI_EGU, REQ_TASK); + + __enable_irq(); + __DSB(); + __ISB(); +} + void nrf_drv_radio802154_swi_init(void) { m_ntf_r_ptr = 0; @@ -347,7 +401,7 @@ void nrf_drv_radio802154_swi_notify_busy_channel(void) nrf_egu_task_trigger(SWI_EGU, NTF_TASK); } -void nrf_drv_radio802154_swi_notify_energy_detected(int8_t result) +void nrf_drv_radio802154_swi_notify_energy_detected(uint8_t result) { assert(!ntf_queue_is_full()); @@ -361,6 +415,20 @@ void nrf_drv_radio802154_swi_notify_energy_detected(int8_t result) nrf_egu_task_trigger(SWI_EGU, NTF_TASK); } +void nrf_drv_radio802154_swi_notify_cca(bool channel_free) +{ + assert(!ntf_queue_is_full()); + + nrf_drv_radio802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr]; + + p_slot->type = NTF_TYPE_CCA; + p_slot->data.cca.result = channel_free; + + ntf_queue_ptr_increment(&m_ntf_w_ptr); + + nrf_egu_task_trigger(SWI_EGU, NTF_TASK); +} + void nrf_drv_radio802154_swi_timeslot_exit(void) { assert(!nrf_egu_event_check(SWI_EGU, TIMESLOT_EXIT_EVENT)); @@ -370,93 +438,93 @@ void nrf_drv_radio802154_swi_timeslot_exit(void) void nrf_drv_radio802154_swi_sleep(bool * p_result) { - nrf_drv_radio802154_critical_section_enter(); - assert(!req_queue_is_full()); - - nrf_drv_radio802154_req_data_t * p_slot = &m_req_queue[m_req_w_ptr]; + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); p_slot->type = REQ_TYPE_SLEEP; p_slot->data.sleep.p_result = p_result; - req_queue_ptr_increment(&m_req_w_ptr); - - nrf_egu_task_trigger(SWI_EGU, REQ_TASK); - nrf_drv_radio802154_critical_section_exit(); + req_exit(); } -void nrf_drv_radio802154_swi_receive(uint8_t channel, bool * p_result) +void nrf_drv_radio802154_swi_receive(bool * p_result) { - nrf_drv_radio802154_critical_section_enter(); - assert(!req_queue_is_full()); - - nrf_drv_radio802154_req_data_t * p_slot = &m_req_queue[m_req_w_ptr]; + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); p_slot->type = REQ_TYPE_RECEIVE; - p_slot->data.receive.channel = channel; p_slot->data.receive.p_result = p_result; - req_queue_ptr_increment(&m_req_w_ptr); - - nrf_egu_task_trigger(SWI_EGU, REQ_TASK); - nrf_drv_radio802154_critical_section_exit(); + req_exit(); } -void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, - uint8_t channel, - int8_t power, - bool cca, - bool * p_result) +void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, bool cca, bool * p_result) { - nrf_drv_radio802154_critical_section_enter(); - assert(!req_queue_is_full()); - - nrf_drv_radio802154_req_data_t * p_slot = &m_req_queue[m_req_w_ptr]; + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); p_slot->type = REQ_TYPE_TRANSMIT; 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); - - nrf_egu_task_trigger(SWI_EGU, REQ_TASK); - nrf_drv_radio802154_critical_section_exit(); + req_exit(); } -void nrf_drv_radio802154_swi_energy_detection(uint8_t channel, uint32_t time_us, bool * p_result) +void nrf_drv_radio802154_swi_energy_detection(uint32_t time_us, bool * p_result) { - nrf_drv_radio802154_critical_section_enter(); - assert(!req_queue_is_full()); - - nrf_drv_radio802154_req_data_t * p_slot = &m_req_queue[m_req_w_ptr]; + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); p_slot->type = REQ_TYPE_ENERGY_DETECTION; - p_slot->data.energy_detection.channel = channel; p_slot->data.energy_detection.time_us = time_us; p_slot->data.energy_detection.p_result = p_result; - req_queue_ptr_increment(&m_req_w_ptr); + req_exit(); +} - nrf_egu_task_trigger(SWI_EGU, REQ_TASK); - nrf_drv_radio802154_critical_section_exit(); +void nrf_drv_radio802154_swi_cca(bool * p_result) +{ + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); + + p_slot->type = REQ_TYPE_CCA; + p_slot->data.cca.p_result = p_result; + + req_exit(); +} + +void nrf_drv_radio802154_swi_continuous_carrier(bool * p_result) +{ + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); + + p_slot->type = REQ_TYPE_CONTINUOUS_CARRIER; + p_slot->data.continuous_carrier.p_result = p_result; + + req_exit(); } void nrf_drv_radio802154_swi_buffer_free(uint8_t * p_data) { - nrf_drv_radio802154_critical_section_enter(); - assert(!req_queue_is_full()); - - nrf_drv_radio802154_req_data_t * p_slot = &m_req_queue[m_req_w_ptr]; + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); p_slot->type = REQ_TYPE_BUFFER_FREE; p_slot->data.buffer_free.p_data = (rx_buffer_t *)p_data; - req_queue_ptr_increment(&m_req_w_ptr); + req_exit(); +} - nrf_egu_task_trigger(SWI_EGU, REQ_TASK); - nrf_drv_radio802154_critical_section_exit(); +void nrf_drv_radio802154_swi_channel_update(void) +{ + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); + + p_slot->type = REQ_TYPE_CHANNEL_UPDATE; + + req_exit(); +} + +void nrf_drv_radio802154_swi_cca_cfg_update(void) +{ + nrf_drv_radio802154_req_data_t * p_slot = req_enter(); + + p_slot->type = REQ_TYPE_CCA_CFG_UPDATE; + + req_exit(); } void SWI_IRQHandler(void) @@ -472,15 +540,15 @@ void SWI_IRQHandler(void) switch (p_slot->type) { case NTF_TYPE_RECEIVED: - nrf_drv_radio802154_received(p_slot->data.received.p_psdu, - p_slot->data.received.power, - p_slot->data.received.lqi); + nrf_drv_radio802154_received_raw(p_slot->data.received.p_psdu, + p_slot->data.received.power, + p_slot->data.received.lqi); break; case NTF_TYPE_TRANSMITTED: - nrf_drv_radio802154_transmitted(p_slot->data.transmitted.p_psdu, - p_slot->data.transmitted.power, - p_slot->data.transmitted.lqi); + nrf_drv_radio802154_transmitted_raw(p_slot->data.transmitted.p_psdu, + p_slot->data.transmitted.power, + p_slot->data.transmitted.lqi); break; case NTF_TYPE_CHANNEL_BUSY: @@ -491,6 +559,10 @@ void SWI_IRQHandler(void) nrf_drv_radio802154_energy_detected(p_slot->data.energy_detected.result); break; + case NTF_TYPE_CCA: + nrf_drv_radio802154_cca_done(p_slot->data.cca.result); + break; + default: assert(false); } @@ -514,6 +586,8 @@ void SWI_IRQHandler(void) { nrf_drv_radio802154_req_data_t * p_slot = &m_req_queue[m_req_r_ptr]; + nrf_drv_radio802154_critical_section_enter(); + switch (p_slot->type) { case REQ_TYPE_SLEEP: @@ -521,33 +595,48 @@ void SWI_IRQHandler(void) break; case REQ_TYPE_RECEIVE: - *(p_slot->data.receive.p_result) = nrf_drv_radio802154_fsm_receive( - p_slot->data.receive.channel); + *(p_slot->data.receive.p_result) = nrf_drv_radio802154_fsm_receive(); break; case REQ_TYPE_TRANSMIT: *(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.cca); break; case REQ_TYPE_ENERGY_DETECTION: *(p_slot->data.energy_detection.p_result) = nrf_drv_radio802154_fsm_energy_detection( - p_slot->data.energy_detection.channel, p_slot->data.energy_detection.time_us); break; + case REQ_TYPE_CCA: + *(p_slot->data.cca.p_result) = nrf_drv_radio802154_fsm_cca(); + break; + + case REQ_TYPE_CONTINUOUS_CARRIER: + *(p_slot->data.continuous_carrier.p_result) = + nrf_drv_radio802154_fsm_continuous_carrier(); + break; + case REQ_TYPE_BUFFER_FREE: nrf_drv_radio802154_fsm_notify_buffer_free(p_slot->data.buffer_free.p_data); break; + case REQ_TYPE_CHANNEL_UPDATE: + nrf_drv_radio802154_fsm_channel_update(); + break; + + case REQ_TYPE_CCA_CFG_UPDATE: + nrf_drv_radio802154_fsm_cca_cfg_update(); + break; + default: assert(false); } + nrf_drv_radio802154_critical_section_exit(); + req_queue_ptr_increment(&m_req_r_ptr); } } 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 1828f3702..e6124deee 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.h @@ -78,7 +78,14 @@ void nrf_drv_radio802154_swi_notify_busy_channel(void); * * @param[in] result Detected energy level. */ -void nrf_drv_radio802154_swi_notify_energy_detected(int8_t result); +void nrf_drv_radio802154_swi_notify_energy_detected(uint8_t result); + +/** + * @brief Notify next higher layer that CCA procedure ended from SWI priority level. + * + * @param[in] channel_free If detected free channel. + */ +void nrf_drv_radio802154_swi_notify_cca(bool channel_free); /** * @brief Request discarding of the timeslot from SWI priority level. @@ -97,34 +104,40 @@ void nrf_drv_radio802154_swi_sleep(bool * p_result); /** * @brief Request entering receive state from SWI priority. * - * @param[in] channel Channel number used for receive procedure. * @param[out] p_result Result of entering receive state. */ -void nrf_drv_radio802154_swi_receive(uint8_t channel, bool * p_result); +void nrf_drv_radio802154_swi_receive(bool * p_result); /** * @biref Request entering transmit state from SWI priority. * * @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); +void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, bool cca, bool * p_result); /** * @brief Request entering energy detection state from SWI priority. * - * @param[in] channel Channel number used for the energy detection procedure. * @param[in] time_us Requested duration of energy detection procedure. * @param[out] p_result Result of entering energy detection state. */ -void nrf_drv_radio802154_swi_energy_detection(uint8_t channel, uint32_t time_us, bool * p_result); +void nrf_drv_radio802154_swi_energy_detection(uint32_t time_us, bool * p_result); + +/** + * @brief Request entering CCA state from SWI priority. + * + * @param[out] p_result Result of entering CCA state. + */ +void nrf_drv_radio802154_swi_cca(bool * p_result); + +/** + * @brief Request entering continuous carrier state from SWI priority. + * + * @param[out] p_result Result of entering continuous carrier state. + */ +void nrf_drv_radio802154_swi_continuous_carrier(bool * p_result); /** * @brief Notify FSM that given buffer is not used anymore and can be freed. @@ -133,6 +146,16 @@ void nrf_drv_radio802154_swi_energy_detection(uint8_t channel, uint32_t time_us, */ void nrf_drv_radio802154_swi_buffer_free(uint8_t * p_data); +/** + * @brief Notify FSM that the next higher layer requested channel change. + */ +void nrf_drv_radio802154_swi_channel_update(void); + +/** + * @brief Notify FSM that the next higher layer requested CCA configuration change. + */ +void nrf_drv_radio802154_swi_cca_cfg_update(void); + /** *@} **/ diff --git a/third_party/NordicSemiconductor/drivers/radio/raal/nrf_raal_config.h b/third_party/NordicSemiconductor/drivers/radio/raal/nrf_raal_config.h index c465a66f5..8cb4471e9 100644 --- a/third_party/NordicSemiconductor/drivers/radio/raal/nrf_raal_config.h +++ b/third_party/NordicSemiconductor/drivers/radio/raal/nrf_raal_config.h @@ -52,7 +52,7 @@ extern "C" { * */ #ifndef NRF_RAAL_MAX_CLEAN_UP_TIME_US -#define NRF_RAAL_MAX_CLEAN_UP_TIME_US 100 +#define NRF_RAAL_MAX_CLEAN_UP_TIME_US 91 #endif /** 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 e3b5c17f5..caf0b74ac 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 @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -111,9 +112,6 @@ static volatile pending_events_t m_pending_event = PENDING_EVENT_NONE; /**@brief Defines RTC0 counter value on timeslot begin. */ static uint32_t m_start_rtc_ticks = 0; -/**@brief External Interrupt from RADIO. */ -extern void RADIO_IRQHandler(void); - /**@brief Initialize timeslot internal variables. */ static inline void timeslot_data_init(void) { @@ -382,8 +380,8 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE); nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_ENDED); - m_pending_event = PENDING_EVENT_NONE; - m_in_timeslot = false; + m_pending_event = PENDING_EVENT_NONE; + m_in_timeslot = false; // TODO: Change to NRF_RADIO_SIGNAL_CALLBACK_ACTION_END (KRKNWK-937) m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; @@ -404,12 +402,12 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t // Ensure HFCLK is running before start is issued. assert(NRF_CLOCK->HFCLKSTAT == (CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk)); + timer_start(); + m_start_rtc_ticks = NRF_RTC0->COUNTER; m_in_timeslot = true; - m_alloc_iters = 0; - m_timeslot_length = m_timeslot_length; - timer_start(); + timeslot_data_init(); if (m_in_critical_section) { @@ -450,7 +448,7 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t { if (!timer_is_margin_reached()) { - RADIO_IRQHandler(); + nrf_drv_radio802154_irq_handler(); } else { diff --git a/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.h b/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.h index 2e53ca1d3..68865419f 100644 --- a/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.h +++ b/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.h @@ -47,7 +47,7 @@ extern "C" { #define NRF_RAAL_TIMESLOT_DEFAULT_LENGTH 6400 #define NRF_RAAL_TIMESLOT_DEFAULT_ALLOC_ITERS 5 #define NRF_RAAL_TIMESLOT_DEFAULT_SAFE_MARGIN 91 -#define NRF_RAAL_TIMESLOT_DEFAULT_TIMEOUT 100000 +#define NRF_RAAL_TIMESLOT_DEFAULT_TIMEOUT 6400 #define NRF_RAAL_TIMESLOT_DEFAULT_MAX_LENGTH 120000000 #define NRF_RAAL_DEFAULT_LF_CLK_ACCURACY_PPM 25 diff --git a/third_party/NordicSemiconductor/hal/nrf_radio.h b/third_party/NordicSemiconductor/hal/nrf_radio.h index 9a0245eaf..3150f0ed1 100644 --- a/third_party/NordicSemiconductor/hal/nrf_radio.h +++ b/third_party/NordicSemiconductor/hal/nrf_radio.h @@ -67,7 +67,7 @@ typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */ NRF_RADIO_TASK_CCASTART = offsetof(NRF_RADIO_Type, TASKS_CCASTART), /**< Start Clear Channel Assessment procedure. */ NRF_RADIO_TASK_CCASTOP = offsetof(NRF_RADIO_Type, TASKS_CCASTOP), /**< Stop Clear Channel Assessment procedure. */ NRF_RADIO_TASK_EDSTART = offsetof(NRF_RADIO_Type, TASKS_EDSTART), /**< Start Energy Detection procedure. */ - NRF_RADIO_TASK_RSSISTART = offsetof(NRF_RADIO_Type, TASKS_RSSISTART), /**< Start the RSSI and take one single sample of received signal strength. */ + NRF_RADIO_TASK_RSSISTART = offsetof(NRF_RADIO_Type, TASKS_RSSISTART), /**< Start the RSSI and take one single sample of received signal strength. */ } nrf_radio_task_t; /*lint -restore */ /** @@ -201,6 +201,16 @@ typedef enum NRF_RADIO_CRC_INCLUDES_ADDR_IEEE802154 = RADIO_CRCCNF_SKIPADDR_Ieee802154, /**< CRC calculation as per 802.15.4 standard. */ } nrf_radio_crc_includes_addr_t; +/** + * @enum nrf_radio_ramp_up_mode_t + * @brief Types of radio ramp-up mode. + */ +typedef enum +{ + NRF_RADIO_RAMP_UP_MODE_DEFAULT = RADIO_MODECNF0_RU_Default, /**< Default ramp-up mode. */ + NRF_RADIO_RAMP_UP_MODE_FAST = RADIO_MODECNF0_RU_Fast /**< Fast ramp-up mode. */ +} nrf_radio_ramp_up_mode_t; + /** * @brief Function for enabling interrupts. * @@ -532,6 +542,17 @@ __STATIC_INLINE void nrf_radio_mhmu_pattern_mask_set(uint32_t radio_mhmu_pattern NRF_RADIO->MHRMATCHMAS = radio_mhmu_pattern_mask; } +/** + * @brief Function for setting radio ramp-up mode. + * + * @param[in] ramp_up_mode Radio ramp-up mode. + */ +__STATIC_INLINE void nrf_radio_ramp_up_mode_set(nrf_radio_ramp_up_mode_t ramp_up_mode) +{ + NRF_RADIO->MODECNF0 &= (~RADIO_MODECNF0_RU_Msk); + NRF_RADIO->MODECNF0 |= ((uint32_t) ramp_up_mode << RADIO_MODECNF0_RU_Pos); +} + /** * @brief Function for setting radio frequency. * @@ -606,18 +627,18 @@ __STATIC_INLINE uint8_t nrf_radio_ed_sample_get(void) __STATIC_INLINE void nrf_radio_ed_loop_count_set(uint32_t radio_ed_loop_count) { NRF_RADIO->EDCNT = (radio_ed_loop_count & 0x001FFFFF); -} +} + +/** + * @brief Function for setting power mode of the radio peripheral. + * + * @param[in] radio_power If radio should powered on. + */ +__STATIC_INLINE void nrf_radio_power_set(bool radio_power) +{ + NRF_RADIO->POWER = (uint32_t) radio_power; +} -/** - * @brief Function for setting power mode of the radio peripheral. - * - * @param[in] radio_power If radio should powered on. - */ -__STATIC_INLINE void nrf_radio_power_set(bool radio_power) -{ - NRF_RADIO->POWER = (uint32_t) radio_power; -} - /** *@}