[nRF52840] update 802.15.4 driver (#2089)

This commit is contained in:
Hubert Miś
2017-08-10 08:52:39 -07:00
committed by Jonathan Hui
parent 913892a800
commit 96f82b3858
27 changed files with 1370 additions and 401 deletions
@@ -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_
@@ -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
+2
View File
@@ -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();
+28 -14
View File
@@ -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);
}
Binary file not shown.
@@ -43,6 +43,8 @@
#include <string.h>
#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 <cmsis/core_cmFunc.h>
#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;
}
@@ -39,6 +39,9 @@
#include <stdbool.h>
#include <stdint.h>
#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
@@ -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
@@ -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
@@ -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
@@ -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();
}
@@ -39,6 +39,7 @@
#include <stdbool.h>
#include <stdint.h>
#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
@@ -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);
/**
*@}
@@ -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);
}
@@ -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);
}
@@ -36,23 +36,26 @@
#include "nrf_drv_radio802154_pib.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#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));
}
@@ -39,6 +39,8 @@
#include <stdbool.h>
#include <stdint.h>
#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
@@ -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_ */
@@ -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);
/**
*@}
**/
@@ -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();
}
@@ -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();
}
}
@@ -48,6 +48,8 @@
#include "hal/nrf_egu.h"
#include "raal/nrf_raal_api.h"
#include <cmsis/core_cmFunc.h>
/** 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);
}
}
@@ -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);
/**
*@}
**/
@@ -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
/**
@@ -43,6 +43,7 @@
#include <string.h>
#include <nrf_raal_api.h>
#include <nrf_drv_radio802154.h>
#include <nrf_drv_radio802154_debug.h>
#include <nrf_drv_clock.h>
#include <softdevice.h>
@@ -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
{
@@ -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
+33 -12
View File
@@ -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;
}
/**
*@}