[nrf52840] update radio driver to 178ecb3514e5f46282bf2108b56aecf5b8db6728 (#2601)

This commit is contained in:
Hubert Miś
2018-03-07 17:32:25 +00:00
committed by Jonathan Hui
parent afa7f34b26
commit f758cc1cc9
78 changed files with 11249 additions and 6885 deletions
+43 -38
View File
@@ -38,7 +38,7 @@ COMMONCPPFLAGS
-DCONFIG_GPIO_AS_PINRESET \
-DNRF52840_XXAA \
-DENABLE_FEM=1 \
-DNRF_DRV_RADIO802154_PROJECT_CONFIG=\"platform-config.h\" \
-DNRF_802154_PROJECT_CONFIG=\"platform-config.h\" \
-I$(top_srcdir)/include \
-I$(top_srcdir)/examples/platforms \
-I$(top_srcdir)/src/core \
@@ -83,10 +83,9 @@ PLATFORM_COMMON_SOURCES
SINGLEPHY_SOURCES = \
flash_nosd.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_priority_drop_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_notification_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_priority_drop_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_request_direct.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/raal/single_phy/single_phy.c \
$(NULL)
@@ -98,11 +97,10 @@ SOFTDEVICE_SOURCES
flash_sd.c \
softdevice.c \
softdevice.h \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_priority_drop_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control_softdevice.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_notification_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_priority_drop_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_request_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_swi.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.c \
$(NULL)
@@ -129,17 +127,19 @@ PLATFORM_SOURCES
endif
RADIO_DRIVER_SOURCES = \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_ack_pending_bit.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_critical_section.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_revision.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_rx_buffer.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control_common.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/platform/clock/nrf_drv_radio802154_clock_sdk.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/platform/timer/nrf_drv_radio802154_timer_none.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_ack_pending_bit.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core_hooks.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_critical_section.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_debug.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_pib.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_revision.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/nrf_802154_rx_buffer.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/mac_features/nrf_802154_filter.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/platform/clock/nrf_802154_clock_sdk.c \
@top_builddir@/third_party/NordicSemiconductor/drivers/radio/platform/timer/nrf_802154_timer_none.c \
$(NULL)
NORDICSEMI_SOURCES = \
@@ -212,29 +212,34 @@ noinst_HEADERS
$(top_srcdir)/third_party/NordicSemiconductor/device/nrf52840_peripherals.h \
$(top_srcdir)/third_party/NordicSemiconductor/device/system_nrf52840.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/clock/nrf_drv_clock.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_ack_pending_bit.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_config.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_const.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_critical_section.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_debug.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_fsm.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_notification.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_pib.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_priority_drop.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_procedures_duration.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_request.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_revision.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_drv_radio802154_rx_buffer.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_ack_pending_bit.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core_hooks.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_config.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_const.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_critical_section.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_debug.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_notification.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_pib.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_priority_drop.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_procedures_duration.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_request.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_revision.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_rx_buffer.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/nrf_802154_swi.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control_api.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control_config.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/fem/nrf_fem_control_internal.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/hal/nrf_radio.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/platform/clock/nrf_drv_radio802154_clock.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/platform/timer/nrf_drv_radio802154_timer.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/mac_features/nrf_802154_ack_timeout.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/mac_features/nrf_802154_csma_ca.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/mac_features/nrf_802154_filter.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/platform/clock/nrf_802154_clock.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/platform/timer/nrf_802154_timer.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/raal/nrf_raal_api.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/raal/nrf_raal_config.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/raal/softdevice/nrf_raal_softdevice.h \
$(top_srcdir)/third_party/NordicSemiconductor/drivers/radio/timer_scheduler/nrf_802154_timer_sched.h \
$(top_srcdir)/third_party/NordicSemiconductor/hal/nrf_assert.h \
$(top_srcdir)/third_party/NordicSemiconductor/hal/nrf_clock.h \
$(top_srcdir)/third_party/NordicSemiconductor/hal/nrf_gpio.h \
+8 -8
View File
@@ -46,7 +46,7 @@
#include <openthread/platform/toolchain.h>
#include <common/logging.hpp>
#include <drivers/radio/nrf_drv_radio802154.h>
#include <drivers/radio/nrf_802154.h>
#include <utils/code_utils.h>
typedef enum { kDiagTransmitModeIdle, kDiagTransmitModePackets, kDiagTransmitModeCarrier } DiagTrasmitMode;
@@ -100,10 +100,10 @@ static void appendErrorResult(otError aError, char *aOutput, size_t aOutputMaxLe
static bool startCarrierTransmision(void)
{
nrf_drv_radio802154_channel_set(sChannel);
nrf_drv_radio802154_tx_power_set(sTxPower);
nrf_802154_channel_set(sChannel);
nrf_802154_tx_power_set(sTxPower);
return nrf_drv_radio802154_continuous_carrier();
return nrf_802154_continuous_carrier();
}
static void processListen(otInstance *aInstance, int argc, char *argv[], char *aOutput, size_t aOutputMaxLen)
@@ -333,14 +333,14 @@ static void processCcaThreshold(otInstance *aInstance, int argc, char *argv[], c
{
(void)aInstance;
otError error = OT_ERROR_NONE;
nrf_drv_radio802154_cca_cfg_t ccaConfig;
otError error = OT_ERROR_NONE;
nrf_802154_cca_cfg_t ccaConfig;
otEXPECT_ACTION(otPlatDiagModeGet(), error = OT_ERROR_INVALID_STATE);
if (argc == 0)
{
nrf_drv_radio802154_cca_cfg_get(&ccaConfig);
nrf_802154_cca_cfg_get(&ccaConfig);
snprintf(aOutput, aOutputMaxLen, "cca threshold: %u\r\n", ccaConfig.ed_threshold);
}
@@ -355,7 +355,7 @@ static void processCcaThreshold(otInstance *aInstance, int argc, char *argv[], c
ccaConfig.mode = NRF_RADIO_CCA_MODE_ED;
ccaConfig.ed_threshold = (uint8_t)value;
nrf_drv_radio802154_cca_cfg_set(&ccaConfig);
nrf_802154_cca_cfg_set(&ccaConfig);
snprintf(aOutput, aOutputMaxLen, "set cca threshold to %u\r\nstatus 0x%02x\r\n", ccaConfig.ed_threshold, error);
}
+5 -6
View File
@@ -41,11 +41,11 @@
#include "platform-fem.h"
#define ENABLE_FEM 1
#include <nrf_drv_radio802154.h>
#include <nrf_802154.h>
void PlatformFemSetConfigParams(const PlatformFemConfigParams *aConfig)
{
nrf_drv_radio802154_fem_control_cfg_t cfg;
nrf_802154_fem_control_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
@@ -57,9 +57,8 @@ void PlatformFemSetConfigParams(const PlatformFemConfigParams *aConfig)
cfg.lna_cfg.gpio_pin = aConfig->mLnaCfg.mGpioPin;
cfg.ppi_ch_id_clr = aConfig->mPpiChIdClr;
cfg.ppi_ch_id_set = aConfig->mPpiChIdSet;
cfg.radio_ppi_grp = aConfig->mRadioPpiGrp;
cfg.timer_ppi_grp = aConfig->mTimerPpiGrp;
cfg.gpiote_ch_id = aConfig->mGpioteChId;
cfg.pa_gpiote_ch_id = aConfig->mGpiotePaChId;
cfg.lna_gpiote_ch_id = aConfig->mGpioteLnaChId;
nrf_drv_radio802154_fem_control_cfg_set(&cfg);
nrf_802154_fem_control_cfg_set(&cfg);
}
+27 -6
View File
@@ -352,23 +352,44 @@
******************************************************************************/
/**
* @def NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES
* @def NRF_802154_PENDING_SHORT_ADDRESSES
*
* Number of slots containing short addresses of nodes for which pending data is stored.
*
*/
#ifndef NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES
#define NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES OPENTHREAD_CONFIG_MAX_CHILDREN
#ifndef NRF_802154_PENDING_SHORT_ADDRESSES
#define NRF_802154_PENDING_SHORT_ADDRESSES OPENTHREAD_CONFIG_MAX_CHILDREN
#endif
/**
* @def NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES
* @def NRF_802154_PENDING_EXTENDED_ADDRESSES
*
* Number of slots containing extended addresses of nodes for which pending data is stored.
*
*/
#ifndef NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES
#define NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES OPENTHREAD_CONFIG_MAX_CHILDREN
#ifndef NRF_802154_PENDING_EXTENDED_ADDRESSES
#define NRF_802154_PENDING_EXTENDED_ADDRESSES OPENTHREAD_CONFIG_MAX_CHILDREN
#endif
/**
* @def NRF_802154_CSMA_CA_ENABLED
*
* If CSMA-CA procedure should be enabled by the driver. Disabling CSMA-CA procedure improves
* driver performance.
*
*/
#ifndef NRF_802154_CSMA_CA_ENABLED
#define NRF_802154_CSMA_CA_ENABLED 0
#endif
/**
* @def NRF_802154_ACK_TIMEOUT_ENABLED
*
* If ACK timeout feature should be enabled in the driver.
*
*/
#ifndef NRF_802154_ACK_TIMEOUT_ENABLED
#define NRF_802154_ACK_TIMEOUT_ENABLED 0
#endif
#endif // PLATFORM_CONFIG_H_
+6 -7
View File
@@ -94,13 +94,12 @@ typedef struct
*/
typedef struct
{
PlatformFemConfigPaLna mPaCfg; /**< Power Amplifier configuration */
PlatformFemConfigPaLna mLnaCfg; /**< Low Noise Amplifier configuration */
uint8_t mPpiChIdSet; /**< PPI channel used for radio pin setting */
uint8_t mPpiChIdClr; /**< PPI channel used for radio pin clearing */
uint8_t mTimerPpiGrp; /**< PPI group used for disabling timer match PPI. */
uint8_t mRadioPpiGrp; /**< PPI group used for disabling radio disabled PPI. */
uint8_t mGpioteChId; /**< GPIOTE channel used for radio pin toggling */
PlatformFemConfigPaLna mPaCfg; /**< Power Amplifier configuration */
PlatformFemConfigPaLna mLnaCfg; /**< Low Noise Amplifier configuration */
uint8_t mPpiChIdSet; /**< PPI channel used for radio pin setting */
uint8_t mPpiChIdClr; /**< PPI channel used for radio pin clearing */
uint8_t mGpiotePaChId; /**< GPIOTE channel used for radio PA pin toggling */
uint8_t mGpioteLnaChId; /**< GPIOTE channel used for radio LNA pin toggling */
} PlatformFemConfigParams;
/**
+65 -59
View File
@@ -51,7 +51,7 @@
#include "platform.h"
#include <device/nrf.h>
#include <nrf_drv_radio802154.h>
#include <nrf_802154.h>
#include <openthread-core-config.h>
#include <openthread/config.h>
@@ -74,7 +74,7 @@ enum
static bool sDisabled;
static otError sReceiveError = OT_ERROR_NONE;
static otRadioFrame sReceivedFrames[NRF_DRV_RADIO802154_RX_BUFFERS];
static otRadioFrame sReceivedFrames[NRF_802154_RX_BUFFERS];
static otRadioFrame sTransmitFrame;
static uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE + 1];
@@ -107,7 +107,7 @@ static void dataInit(void)
sReceiveError = OT_ERROR_NONE;
for (uint32_t i = 0; i < NRF_DRV_RADIO802154_RX_BUFFERS; i++)
for (uint32_t i = 0; i < NRF_802154_RX_BUFFERS; i++)
{
sReceivedFrames[i].mPsdu = NULL;
}
@@ -188,14 +188,14 @@ void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
uint8_t address[SHORT_ADDRESS_SIZE];
convertShortAddress(address, aPanId);
nrf_drv_radio802154_pan_id_set(address);
nrf_802154_pan_id_set(address);
}
void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
{
(void)aInstance;
nrf_drv_radio802154_extended_address_set(aExtAddress->m8);
nrf_802154_extended_address_set(aExtAddress->m8);
}
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
@@ -205,18 +205,18 @@ void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
uint8_t address[SHORT_ADDRESS_SIZE];
convertShortAddress(address, aShortAddress);
nrf_drv_radio802154_short_address_set(address);
nrf_802154_short_address_set(address);
}
void nrf5RadioInit(void)
{
dataInit();
nrf_drv_radio802154_init();
nrf_802154_init();
}
void nrf5RadioDeinit(void)
{
nrf_drv_radio802154_deinit();
nrf_802154_deinit();
}
otRadioState otPlatRadioGetState(otInstance *aInstance)
@@ -228,16 +228,16 @@ otRadioState otPlatRadioGetState(otInstance *aInstance)
return OT_RADIO_STATE_DISABLED;
}
switch (nrf_drv_radio802154_state_get())
switch (nrf_802154_state_get())
{
case NRF_DRV_RADIO802154_STATE_SLEEP:
case NRF_802154_STATE_SLEEP:
return OT_RADIO_STATE_SLEEP;
case NRF_DRV_RADIO802154_STATE_RECEIVE:
case NRF_DRV_RADIO802154_STATE_ENERGY_DETECTION:
case NRF_802154_STATE_RECEIVE:
case NRF_802154_STATE_ENERGY_DETECTION:
return OT_RADIO_STATE_RECEIVE;
case NRF_DRV_RADIO802154_STATE_TRANSMIT:
case NRF_802154_STATE_TRANSMIT:
return OT_RADIO_STATE_TRANSMIT;
default:
@@ -296,7 +296,7 @@ otError otPlatRadioSleep(otInstance *aInstance)
{
(void)aInstance;
if (nrf_drv_radio802154_sleep())
if (nrf_802154_sleep())
{
clearPendingEvents();
}
@@ -313,12 +313,14 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
(void)aInstance;
nrf_drv_radio802154_channel_set(aChannel);
nrf_drv_radio802154_tx_power_set(sDefaultTxPower);
nrf_drv_radio802154_receive();
bool result;
nrf_802154_channel_set(aChannel);
nrf_802154_tx_power_set(sDefaultTxPower);
result = nrf_802154_receive();
clearPendingEvents();
return OT_ERROR_NONE;
return result ? OT_ERROR_NONE : OT_ERROR_INVALID_STATE;
}
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
@@ -327,9 +329,9 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
aFrame->mPsdu[-1] = aFrame->mLength;
nrf_drv_radio802154_channel_set(aFrame->mChannel);
nrf_802154_channel_set(aFrame->mChannel);
if (nrf_drv_radio802154_transmit_raw(&aFrame->mPsdu[-1], true))
if (nrf_802154_transmit_raw(&aFrame->mPsdu[-1], true))
{
clearPendingEvents();
otPlatRadioTxStarted(aInstance, aFrame);
@@ -354,7 +356,7 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance)
{
(void)aInstance;
return nrf_drv_radio802154_rssi_last_get();
return nrf_802154_rssi_last_get();
}
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
@@ -368,21 +370,21 @@ bool otPlatRadioGetPromiscuous(otInstance *aInstance)
{
(void)aInstance;
return nrf_drv_radio802154_promiscuous_get();
return nrf_802154_promiscuous_get();
}
void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
{
(void)aInstance;
nrf_drv_radio802154_promiscuous_set(aEnable);
nrf_802154_promiscuous_set(aEnable);
}
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
{
(void)aInstance;
nrf_drv_radio802154_auto_pending_bit_set(aEnable);
nrf_802154_auto_pending_bit_set(aEnable);
}
otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
@@ -394,7 +396,7 @@ otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t a
uint8_t shortAddress[SHORT_ADDRESS_SIZE];
convertShortAddress(shortAddress, aShortAddress);
if (nrf_drv_radio802154_pending_bit_for_addr_set(shortAddress, false))
if (nrf_802154_pending_bit_for_addr_set(shortAddress, false))
{
error = OT_ERROR_NONE;
}
@@ -412,7 +414,7 @@ otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress
otError error;
if (nrf_drv_radio802154_pending_bit_for_addr_set(aExtAddress->m8, true))
if (nrf_802154_pending_bit_for_addr_set(aExtAddress->m8, true))
{
error = OT_ERROR_NONE;
}
@@ -433,7 +435,7 @@ otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t
uint8_t shortAddress[SHORT_ADDRESS_SIZE];
convertShortAddress(shortAddress, aShortAddress);
if (nrf_drv_radio802154_pending_bit_for_addr_clear(shortAddress, false))
if (nrf_802154_pending_bit_for_addr_clear(shortAddress, false))
{
error = OT_ERROR_NONE;
}
@@ -451,7 +453,7 @@ otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddre
otError error;
if (nrf_drv_radio802154_pending_bit_for_addr_clear(aExtAddress->m8, true))
if (nrf_802154_pending_bit_for_addr_clear(aExtAddress->m8, true))
{
error = OT_ERROR_NONE;
}
@@ -467,14 +469,14 @@ void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
{
(void)aInstance;
nrf_drv_radio802154_pending_bit_for_addr_reset(false);
nrf_802154_pending_bit_for_addr_reset(false);
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
{
(void)aInstance;
nrf_drv_radio802154_pending_bit_for_addr_reset(true);
nrf_802154_pending_bit_for_addr_reset(true);
}
otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
@@ -486,9 +488,9 @@ otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint1
clearPendingEvents();
nrf_drv_radio802154_channel_set(aScanChannel);
nrf_802154_channel_set(aScanChannel);
if (nrf_drv_radio802154_energy_detection(sEnergyDetectionTime))
if (nrf_802154_energy_detection(sEnergyDetectionTime))
{
resetPendingEvent(kPendingEventEnergyDetectionStart);
}
@@ -522,14 +524,14 @@ otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
(void)aInstance;
sDefaultTxPower = aPower;
nrf_drv_radio802154_tx_power_set(aPower);
nrf_802154_tx_power_set(aPower);
return OT_ERROR_NONE;
}
void nrf5RadioProcess(otInstance *aInstance)
{
for (uint32_t i = 0; i < NRF_DRV_RADIO802154_RX_BUFFERS; i++)
for (uint32_t i = 0; i < NRF_802154_RX_BUFFERS; i++)
{
if (sReceivedFrames[i].mPsdu != NULL)
{
@@ -547,15 +549,15 @@ void nrf5RadioProcess(otInstance *aInstance)
uint8_t *bufferAddress = &sReceivedFrames[i].mPsdu[-1];
sReceivedFrames[i].mPsdu = NULL;
nrf_drv_radio802154_buffer_free_raw(bufferAddress);
nrf_802154_buffer_free_raw(bufferAddress);
}
}
if (isPendingEventSet(kPendingEventTransmit))
{
nrf_drv_radio802154_channel_set(sTransmitFrame.mChannel);
nrf_802154_channel_set(sTransmitFrame.mChannel);
if (nrf_drv_radio802154_transmit_raw(sTransmitPsdu, true))
if (nrf_802154_transmit_raw(sTransmitPsdu, true))
{
resetPendingEvent(kPendingEventTransmit);
otPlatRadioTxStarted(aInstance, &sTransmitFrame);
@@ -579,7 +581,7 @@ void nrf5RadioProcess(otInstance *aInstance)
if (sAckFrame.mPsdu != NULL)
{
nrf_drv_radio802154_buffer_free_raw(sAckFrame.mPsdu - 1);
nrf_802154_buffer_free_raw(sAckFrame.mPsdu - 1);
sAckFrame.mPsdu = NULL;
}
@@ -646,7 +648,7 @@ void nrf5RadioProcess(otInstance *aInstance)
if (isPendingEventSet(kPendingEventSleep))
{
if (nrf_drv_radio802154_sleep())
if (nrf_802154_sleep())
{
resetPendingEvent(kPendingEventSleep);
}
@@ -654,20 +656,20 @@ void nrf5RadioProcess(otInstance *aInstance)
if (isPendingEventSet(kPendingEventEnergyDetectionStart))
{
nrf_drv_radio802154_channel_set(sEnergyDetectionChannel);
nrf_802154_channel_set(sEnergyDetectionChannel);
if (nrf_drv_radio802154_energy_detection(sEnergyDetectionTime))
if (nrf_802154_energy_detection(sEnergyDetectionTime))
{
resetPendingEvent(kPendingEventEnergyDetectionStart);
}
}
}
void nrf_drv_radio802154_received_raw(uint8_t *p_data, int8_t power, int8_t lqi)
void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
{
otRadioFrame *receivedFrame = NULL;
for (uint32_t i = 0; i < NRF_DRV_RADIO802154_RX_BUFFERS; i++)
for (uint32_t i = 0; i < NRF_802154_RX_BUFFERS; i++)
{
if (sReceivedFrames[i].mPsdu == NULL)
{
@@ -684,7 +686,7 @@ void nrf_drv_radio802154_received_raw(uint8_t *p_data, int8_t power, int8_t lqi)
receivedFrame->mLength = p_data[0];
receivedFrame->mRssi = power;
receivedFrame->mLqi = lqi;
receivedFrame->mChannel = nrf_drv_radio802154_channel_get();
receivedFrame->mChannel = nrf_802154_channel_get();
#if OPENTHREAD_ENABLE_RAW_LINK_API
uint64_t timestamp = nrf5AlarmGetCurrentTime();
receivedFrame->mMsec = timestamp / US_PER_MS;
@@ -694,24 +696,24 @@ void nrf_drv_radio802154_received_raw(uint8_t *p_data, int8_t power, int8_t lqi)
PlatformEventSignalPending();
}
void nrf_drv_radio802154_receive_failed(nrf_drv_radio802154_rx_error_t error)
void nrf_802154_receive_failed(nrf_802154_rx_error_t error)
{
switch (error)
{
case NRF_DRV_RADIO802154_RX_ERROR_INVALID_FRAME:
case NRF_802154_RX_ERROR_INVALID_FRAME:
sReceiveError = OT_ERROR_NO_FRAME_RECEIVED;
break;
case NRF_DRV_RADIO802154_RX_ERROR_INVALID_FCS:
case NRF_802154_RX_ERROR_INVALID_FCS:
sReceiveError = OT_ERROR_FCS;
break;
case NRF_DRV_RADIO802154_RX_ERROR_INVALID_DEST_ADDR:
case NRF_802154_RX_ERROR_INVALID_DEST_ADDR:
sReceiveError = OT_ERROR_DESTINATION_ADDRESS_FILTERED;
break;
case NRF_DRV_RADIO802154_RX_ERROR_RUNTIME:
case NRF_DRV_RADIO802154_RX_ERROR_TIMESLOT_ENDED:
case NRF_802154_RX_ERROR_RUNTIME:
case NRF_802154_RX_ERROR_TIMESLOT_ENDED:
sReceiveError = OT_ERROR_FAILED;
break;
@@ -722,8 +724,10 @@ void nrf_drv_radio802154_receive_failed(nrf_drv_radio802154_rx_error_t error)
setPendingEvent(kPendingEventReceiveFailed);
}
void nrf_drv_radio802154_transmitted_raw(uint8_t *aAckPsdu, int8_t aPower, int8_t aLqi)
void nrf_802154_transmitted_raw(const uint8_t *aFrame, uint8_t *aAckPsdu, int8_t aPower, uint8_t aLqi)
{
assert(aFrame == sTransmitPsdu);
if (aAckPsdu == NULL)
{
sAckFrame.mPsdu = NULL;
@@ -734,31 +738,33 @@ void nrf_drv_radio802154_transmitted_raw(uint8_t *aAckPsdu, int8_t aPower, int8_
sAckFrame.mLength = aAckPsdu[0];
sAckFrame.mRssi = aPower;
sAckFrame.mLqi = aLqi;
sAckFrame.mChannel = nrf_drv_radio802154_channel_get();
sAckFrame.mChannel = nrf_802154_channel_get();
}
setPendingEvent(kPendingEventFrameTransmitted);
}
void nrf_drv_radio802154_transmit_failed(nrf_drv_radio802154_tx_error_t error)
void nrf_802154_transmit_failed(const uint8_t *aFrame, nrf_802154_tx_error_t error)
{
assert(aFrame == sTransmitPsdu);
switch (error)
{
case NRF_DRV_RADIO802154_TX_ERROR_BUSY_CHANNEL:
case NRF_DRV_RADIO802154_TX_ERROR_TIMESLOT_ENDED:
case NRF_802154_TX_ERROR_BUSY_CHANNEL:
case NRF_802154_TX_ERROR_TIMESLOT_ENDED:
setPendingEvent(kPendingEventChannelAccessFailure);
break;
case NRF_DRV_RADIO802154_TX_ERROR_INVALID_ACK:
case NRF_DRV_RADIO802154_TX_ERROR_NO_MEM:
case NRF_802154_TX_ERROR_INVALID_ACK:
case NRF_802154_TX_ERROR_NO_MEM:
setPendingEvent(kPendingEventInvalidAck);
break;
}
}
void nrf_drv_radio802154_energy_detected(uint8_t result)
void nrf_802154_energy_detected(uint8_t result)
{
sEnergyDetected = nrf_drv_radio802154_dbm_from_energy_level_calculate(result);
sEnergyDetected = nrf_802154_dbm_from_energy_level_calculate(result);
setPendingEvent(kPendingEventEnergyDetected);
}
@@ -0,0 +1,364 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements common function for Front End Module control of the nRF 802.15.4 radio driver.
*
*/
#include "nrf_fem_control_api.h"
#include <assert.h>
#include "compiler_abstraction.h"
#include "nrf_fem_control_config.h"
#include "nrf_802154_config.h"
#include "nrf.h"
#include "hal/nrf_gpio.h"
#include "hal/nrf_gpiote.h"
#include "hal/nrf_ppi.h"
#include "hal/nrf_radio.h"
#include "hal/nrf_timer.h"
#define NRF_FEM_TIMER_INSTANCE NRF_802154_TIMER_INSTANCE
#if ENABLE_FEM
static nrf_fem_control_cfg_t m_nrf_fem_control_cfg; /**< FEM controller configuration. */
/** Check whether pin is valid and enabled. */
static bool pin_is_enabled(nrf_fem_control_pin_t pin)
{
switch (pin)
{
case NRF_FEM_CONTROL_LNA_PIN:
return m_nrf_fem_control_cfg.lna_cfg.enable;
case NRF_FEM_CONTROL_PA_PIN:
return m_nrf_fem_control_cfg.pa_cfg.enable;
case NRF_FEM_CONTROL_ANY_PIN:
return m_nrf_fem_control_cfg.lna_cfg.enable || m_nrf_fem_control_cfg.pa_cfg.enable;
default:
assert(false);
return false;
}
}
/**
* @section GPIO control.
*/
/** Initialize GPIO according to configuration provided. */
static void gpio_init(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable)
{
nrf_gpio_cfg_output(m_nrf_fem_control_cfg.pa_cfg.gpio_pin);
nrf_gpio_pin_write(m_nrf_fem_control_cfg.pa_cfg.gpio_pin,
!m_nrf_fem_control_cfg.pa_cfg.active_high);
}
if (m_nrf_fem_control_cfg.lna_cfg.enable)
{
nrf_gpio_cfg_output(m_nrf_fem_control_cfg.lna_cfg.gpio_pin);
nrf_gpio_pin_write(m_nrf_fem_control_cfg.lna_cfg.gpio_pin,
!m_nrf_fem_control_cfg.lna_cfg.active_high);
}
}
/** Configure GPIOTE module. */
static void gpiote_configure(void)
{
nrf_gpiote_task_configure(m_nrf_fem_control_cfg.lna_gpiote_ch_id,
m_nrf_fem_control_cfg.lna_cfg.gpio_pin,
(nrf_gpiote_polarity_t)GPIOTE_CONFIG_POLARITY_None,
(nrf_gpiote_outinit_t)!m_nrf_fem_control_cfg.lna_cfg.active_high);
nrf_gpiote_task_enable(m_nrf_fem_control_cfg.lna_gpiote_ch_id);
nrf_gpiote_task_configure(m_nrf_fem_control_cfg.pa_gpiote_ch_id,
m_nrf_fem_control_cfg.pa_cfg.gpio_pin,
(nrf_gpiote_polarity_t)GPIOTE_CONFIG_POLARITY_None,
(nrf_gpiote_outinit_t)!m_nrf_fem_control_cfg.pa_cfg.active_high);
nrf_gpiote_task_enable(m_nrf_fem_control_cfg.pa_gpiote_ch_id);
}
/**
* @section PPI control.
*/
/** Initialize PPI according to configuration provided. */
static void ppi_init(void)
{
/* RADIO DISABLED --> clr LNA & clr PA PPI */
nrf_ppi_channel_and_fork_endpoint_setup(
(nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_clr,
(uint32_t)(&NRF_RADIO->EVENTS_DISABLED),
(m_nrf_fem_control_cfg.lna_cfg.active_high ?
(uint32_t)(&NRF_GPIOTE->TASKS_CLR[m_nrf_fem_control_cfg.lna_gpiote_ch_id]) :
(uint32_t)(&NRF_GPIOTE->TASKS_SET[m_nrf_fem_control_cfg.lna_gpiote_ch_id])),
(m_nrf_fem_control_cfg.pa_cfg.active_high ?
(uint32_t)(&NRF_GPIOTE->TASKS_CLR[m_nrf_fem_control_cfg.pa_gpiote_ch_id]) :
(uint32_t)(&NRF_GPIOTE->TASKS_SET[m_nrf_fem_control_cfg.pa_gpiote_ch_id])));
}
/** Setup PPI to set LNA pin on a timer event. */
static void ppi_lna_enable_setup(nrf_timer_cc_channel_t timer_cc_channel)
{
/* TIMER0->COMPARE --> set LNA PPI */
nrf_ppi_channel_endpoint_setup(
(nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set,
(uint32_t)(&NRF_FEM_TIMER_INSTANCE->EVENTS_COMPARE[timer_cc_channel]),
(m_nrf_fem_control_cfg.lna_cfg.active_high ?
(uint32_t)(&NRF_GPIOTE->TASKS_SET[m_nrf_fem_control_cfg.lna_gpiote_ch_id]) :
(uint32_t)(&NRF_GPIOTE->TASKS_CLR[m_nrf_fem_control_cfg.lna_gpiote_ch_id])));
}
/** Setup PPI to set PA pin on a timer event. */
static void ppi_pa_enable_setup(nrf_timer_cc_channel_t timer_cc_channel)
{
/* TIMER2->COMPARE --> set PA PPI */
nrf_ppi_channel_endpoint_setup(
(nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set,
(uint32_t)(&NRF_FEM_TIMER_INSTANCE->EVENTS_COMPARE[timer_cc_channel]),
(m_nrf_fem_control_cfg.pa_cfg.active_high ?
(uint32_t)(&NRF_GPIOTE->TASKS_SET[m_nrf_fem_control_cfg.pa_gpiote_ch_id]) :
(uint32_t)(&NRF_GPIOTE->TASKS_CLR[m_nrf_fem_control_cfg.pa_gpiote_ch_id])));
}
/**
* @section FEM API functions.
*/
void nrf_fem_control_cfg_set(const nrf_fem_control_cfg_t * p_cfg)
{
m_nrf_fem_control_cfg = *p_cfg;
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
gpio_init();
gpiote_configure();
ppi_init();
nrf_ppi_channel_enable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_clr);
}
}
void nrf_fem_control_cfg_get(nrf_fem_control_cfg_t * p_cfg)
{
*p_cfg = m_nrf_fem_control_cfg;
}
void nrf_fem_control_activate(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
nrf_ppi_channel_enable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_clr);
}
}
void nrf_fem_control_deactivate(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
nrf_ppi_channel_disable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_clr);
nrf_ppi_channel_disable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set);
}
}
void nrf_fem_control_ppi_enable(nrf_fem_control_pin_t pin, nrf_timer_cc_channel_t timer_cc_channel)
{
if (pin_is_enabled(pin))
{
switch (pin)
{
case NRF_FEM_CONTROL_LNA_PIN:
ppi_lna_enable_setup(timer_cc_channel);
nrf_ppi_channel_enable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set);
break;
case NRF_FEM_CONTROL_PA_PIN:
ppi_pa_enable_setup(timer_cc_channel);
nrf_ppi_channel_enable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set);
break;
default:
assert(false);
break;
}
}
}
void nrf_fem_control_ppi_disable(nrf_fem_control_pin_t pin)
{
if (pin_is_enabled(pin))
{
nrf_ppi_channel_disable((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set);
}
}
uint32_t nrf_fem_control_delay_get(nrf_fem_control_pin_t pin)
{
uint32_t target_time = 1;
if (pin_is_enabled(pin))
{
switch (pin)
{
case NRF_FEM_CONTROL_LNA_PIN:
target_time = NRF_FEM_RADIO_RX_STARTUP_LATENCY_US - NRF_FEM_LNA_TIME_IN_ADVANCE;
break;
case NRF_FEM_CONTROL_PA_PIN:
target_time = NRF_FEM_RADIO_TX_STARTUP_LATENCY_US - NRF_FEM_PA_TIME_IN_ADVANCE;
break;
default:
assert(false);
break;
}
}
return target_time;
}
void nrf_fem_control_pin_clear(void)
{
if (pin_is_enabled(NRF_FEM_CONTROL_PA_PIN))
{
nrf_gpio_pin_write(m_nrf_fem_control_cfg.pa_cfg.gpio_pin,
!m_nrf_fem_control_cfg.pa_cfg.active_high);
}
if (pin_is_enabled(NRF_FEM_CONTROL_LNA_PIN))
{
nrf_gpio_pin_write(m_nrf_fem_control_cfg.lna_cfg.gpio_pin,
!m_nrf_fem_control_cfg.lna_cfg.active_high);
}
}
void nrf_fem_control_timer_set(nrf_fem_control_pin_t pin,
nrf_timer_cc_channel_t timer_cc_channel,
nrf_timer_short_mask_t short_mask)
{
if (pin_is_enabled(pin))
{
uint32_t target_time = nrf_fem_control_delay_get(pin);
nrf_timer_shorts_enable(NRF_FEM_TIMER_INSTANCE, short_mask);
nrf_timer_cc_write(NRF_FEM_TIMER_INSTANCE, timer_cc_channel, target_time);
}
}
void nrf_fem_control_timer_reset(nrf_fem_control_pin_t pin, nrf_timer_short_mask_t short_mask)
{
if (pin_is_enabled(pin))
{
nrf_timer_task_trigger(NRF_FEM_TIMER_INSTANCE, NRF_TIMER_TASK_STOP);
nrf_timer_task_trigger(NRF_FEM_TIMER_INSTANCE, NRF_TIMER_TASK_CLEAR);
nrf_timer_shorts_disable(NRF_FEM_TIMER_INSTANCE, short_mask);
}
}
void nrf_fem_control_ppi_fork_setup(nrf_fem_control_pin_t pin,
nrf_ppi_channel_t ppi_channel,
uint32_t task_addr)
{
if (pin_is_enabled(pin))
{
nrf_ppi_fork_endpoint_setup(ppi_channel, task_addr);
}
}
void nrf_fem_control_ppi_task_setup(nrf_fem_control_pin_t pin,
nrf_ppi_channel_t ppi_channel,
uint32_t event_addr,
uint32_t task_addr)
{
if (pin_is_enabled(pin))
{
nrf_ppi_channel_endpoint_setup(ppi_channel, event_addr, task_addr);
nrf_ppi_channel_enable(ppi_channel);
}
}
void nrf_fem_control_ppi_fork_clear(nrf_fem_control_pin_t pin, nrf_ppi_channel_t ppi_channel)
{
if (pin_is_enabled(pin))
{
nrf_ppi_fork_endpoint_setup(ppi_channel, 0);
}
}
void nrf_fem_control_ppi_pin_task_setup(nrf_ppi_channel_t ppi_channel,
uint32_t event_addr,
bool lna_pin_set,
bool pa_pin_set)
{
uint32_t lna_task_addr = 0;
uint32_t pa_task_addr = 0;
if (m_nrf_fem_control_cfg.lna_cfg.enable)
{
if ((lna_pin_set && m_nrf_fem_control_cfg.lna_cfg.active_high) ||
(!lna_pin_set && !m_nrf_fem_control_cfg.lna_cfg.active_high))
{
lna_task_addr = (uint32_t)(&NRF_GPIOTE->TASKS_SET[m_nrf_fem_control_cfg.lna_gpiote_ch_id]);
}
else
{
lna_task_addr = (uint32_t)(&NRF_GPIOTE->TASKS_CLR[m_nrf_fem_control_cfg.lna_gpiote_ch_id]);
}
}
if (m_nrf_fem_control_cfg.pa_cfg.enable)
{
if ((pa_pin_set && m_nrf_fem_control_cfg.pa_cfg.active_high) ||
(!pa_pin_set && !m_nrf_fem_control_cfg.pa_cfg.active_high))
{
pa_task_addr = (uint32_t)(&NRF_GPIOTE->TASKS_SET[m_nrf_fem_control_cfg.pa_gpiote_ch_id]);
}
else
{
pa_task_addr = (uint32_t)(&NRF_GPIOTE->TASKS_CLR[m_nrf_fem_control_cfg.pa_gpiote_ch_id]);
}
}
if (lna_task_addr != 0 || pa_task_addr != 0)
{
nrf_ppi_channel_and_fork_endpoint_setup(ppi_channel, event_addr, lna_task_addr, pa_task_addr);
nrf_ppi_channel_enable(ppi_channel);
}
}
#endif // ENABLE_FEM
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,9 @@
#include <stdint.h>
#include <stdbool.h>
#include "hal/nrf_ppi.h"
#include "hal/nrf_timer.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -59,14 +62,11 @@ extern "C" {
/** Default PPI channel for pin clearing. */
#define NRF_FEM_CONTROL_DEFAULT_CLR_PPI_CHANNEL 19
/** Default PPI channel group used to disable timer match PPI. */
#define NRF_FEM_CONTROL_DEFAULT_TIMER_MATCH_PPI_GROUP 4
/** Default PPI channel group used to disable radio disabled PPI. */
#define NRF_FEM_CONTROL_DEFAULT_RADIO_DISABLED_PPI_GROUP 5
/** Default GPIOTE channel for FEM control. */
#define NRF_FEM_CONTROL_DEFAULT_LNA_GPIOTE_CHANNEL 6
/** Default GPIOTE channel for FEM control. */
#define NRF_FEM_CONTROL_DEFAULT_GPIOTE_CHANNEL 7
#define NRF_FEM_CONTROL_DEFAULT_PA_GPIOTE_CHANNEL 7
#if ENABLE_FEM
@@ -94,15 +94,24 @@ typedef struct
*/
typedef struct
{
nrf_fem_control_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */
nrf_fem_control_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */
uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */
uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */
uint8_t timer_ppi_grp; /**< PPI group used for disabling timer match PPI. */
uint8_t radio_ppi_grp; /**< PPI group used for disabling radio disabled PPI. */
uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */
nrf_fem_control_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */
nrf_fem_control_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */
uint8_t pa_gpiote_ch_id; /**< GPIOTE channel used for Power Amplifier pin toggling */
uint8_t lna_gpiote_ch_id; /**< GPIOTE channel used for Low Noise Amplifier pin toggling */
uint8_t ppi_ch_id_set; /**< PPI channel used for radio Power Amplifier and Low Noise Amplifier pins setting */
uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */
} nrf_fem_control_cfg_t;
/**
* @brief Hardware pins controlled by the Front End Module.
*/
typedef enum
{
NRF_FEM_CONTROL_PA_PIN,
NRF_FEM_CONTROL_LNA_PIN,
NRF_FEM_CONTROL_ANY_PIN,
} nrf_fem_control_pin_t;
/**@brief Set PA & LNA GPIO toggle configuration.
*
* @note This function shall not be called when radio is in use.
@@ -125,44 +134,105 @@ void nrf_fem_control_cfg_get(nrf_fem_control_cfg_t * p_cfg);
*/
void nrf_fem_control_activate(void);
/**@brief De-activate FEM controller.
/**@brief Deactivate FEM controller.
*
* This function should be called when radio goes to sleep.
*/
void nrf_fem_control_deactivate(void);
/**@brief Latch current time in FEM controller.
/**@brief Configure PPI to activate one of the Front End Module pins on an appropriate timer event.
*
* @param[in] pin The Front End Module controlled pin to be connected to the PPI.
* @param[in] timer_cc_channel Timer CC channel that triggers the @p pin activation through the PPI.
*
* This function stores current time to enable precise time measurement and mitigate impact of code
* execution time. It should be called before triggering RXEN or TXEN task, and calling
* @ref nrf_fem_control_pa_set or @ref nrf_fem_control_lna_set funcitons.
*/
void nrf_fem_control_time_latch(void);
void nrf_fem_control_ppi_enable(nrf_fem_control_pin_t pin, nrf_timer_cc_channel_t timer_cc_channel);
/**@brief Activate Power Amplifier (TX) pin of the Front End Module.
/**@brief Clear PPI configuration used to activate one of Front End Module pins.
*
* @param[in] shorts_used Information if this operation is related to a task triggered by a short.
* @param[in] turnaround Information if TX mode is entered from RX mode (turnaround) or DISABLED (ramp up).
* @param[in] pin The Front End Module controlled pin to be disconnected from the PPI.
*
* This function will set up a timer to activate the pin 5 +/- 2.5 us before radio READY event is generated.
* It will also set up a PPI to deactivate the pin on radio DISABLED event.
*
* @note This function shall always be called after @ref nrf_fem_control_time_latch function was called,
* to enable precise time measurement.
* */
void nrf_fem_control_pa_set(bool shorts_used, bool turnaround);
*/
void nrf_fem_control_ppi_disable(nrf_fem_control_pin_t pin);
/**@brief Activate Low Noise Amplifier (RX) pin of the Front End Module.
/**@brief Calculate target time for a timer, which activates one of the Front End Module pins.
*
* @param[in] pin The Front End Module controlled pin to be activated.
*
* @return @p pin activation delay in microseconds.
*
* @param[in] shorts_used Information if this operation is related to a task triggered by a short.
*/
uint32_t nrf_fem_control_delay_get(nrf_fem_control_pin_t pin);
/**@brief Clear the Power Amplifier and the Low Noise Amplifier pins immediately.
*
* This function will set up a timer to activate the pin 5 +/- 2.5 us before radio READY event is generated.
* It will also set up a PPI to deactivate the pin on radio DISABLED event.
*/
void nrf_fem_control_pin_clear(void);
/**@brief Configure and set a timer for one of the Front End Module pins activation.
*
* @param[in] pin The Front End Module controlled pin to be activated.
* @param[in] timer_cc_channel Timer CC channel to set.
* @param[in] short_mask Mask of timer shortcuts to be enabled.
*
* @note This function shall always be called after @ref nrf_fem_control_time_latch function was called,
* to enable precise time measurement.
* */
void nrf_fem_control_lna_set(bool shorts_used);
*/
void nrf_fem_control_timer_set(nrf_fem_control_pin_t pin,
nrf_timer_cc_channel_t timer_cc_channel,
nrf_timer_short_mask_t short_mask);
/**@brief Clear timer configuration after one of the Front End Module pins deactivation.
*
* @param[in] pin The Front End Module controlled pin that was deactivated.
* @param[in] short_mask Mask of timer shortcuts to be disabled.
*
*/
void nrf_fem_control_timer_reset(nrf_fem_control_pin_t pin, nrf_timer_short_mask_t short_mask);
/**@brief Setup a PPI fork task necessary for one of the Front End Module pins.
*
* @param[in] pin The Front End Module controlled pin that was deactivated.
* @param[in] ppi_channel PPI channel to connect the fork task to.
*
*/
void nrf_fem_control_ppi_fork_setup(nrf_fem_control_pin_t pin,
nrf_ppi_channel_t ppi_channel,
uint32_t task_addr);
/**@brief Setup a PPI task necessary for one of the Front End Module pins.
*
* @param[in] pin The Front End Module controlled pin that was deactivated.
* @param[in] ppi_channel PPI channel to connect the task to.
* @param[in] event_addr Address of the event to be connected to the PPI.
* @param[in] task_addr Address of the task to be connected to the PPI.
*
*/
void nrf_fem_control_ppi_task_setup(nrf_fem_control_pin_t pin,
nrf_ppi_channel_t ppi_channel,
uint32_t event_addr,
uint32_t task_addr);
/**@brief Clear a PPI fork task configuration for one of the Front End Module pins.
*
* @param[in] pin The Front End Module controlled pin that was deactivated.
* @param[in] ppi_channel PPI channel to disconnect the fork task from.
*
*/
void nrf_fem_control_ppi_fork_clear(nrf_fem_control_pin_t pin, nrf_ppi_channel_t ppi_channel);
/**@brief Setup PPI task and fork that set or clear Front End Module pins on a given event.
*
* @param[in] ppi_channel PPI channel to connect the task and fork to.
* @param[in] event_addr Address of the event to be connected to the PPI.
* @param[in] lna_pin_set If true, the Low Noise Amplifier pin will be set on the event @p event_addr.
* Otherwise, it will be cleared.
* @param[in] pa_pin_set If true, the Power Amplifier pin will be set on the event @p event_addr.
* Otherwise, it will be cleared.
*
*/
void nrf_fem_control_ppi_pin_task_setup(nrf_ppi_channel_t ppi_channel,
uint32_t event_addr,
bool lna_pin_set,
bool pa_pin_set);
#else // ENABLE_FEM
@@ -170,9 +240,17 @@ void nrf_fem_control_lna_set(bool shorts_used);
#define nrf_fem_control_cfg_get(...)
#define nrf_fem_control_activate(...)
#define nrf_fem_control_deactivate(...)
#define nrf_fem_control_time_latch(...)
#define nrf_fem_control_pa_set(...)
#define nrf_fem_control_lna_set(...)
#define nrf_fem_control_ppi_enable(...)
#define nrf_fem_control_ppi_disable(...)
#define nrf_fem_control_delay_get(...) 1
#define nrf_fem_control_pin_clear(...)
#define nrf_fem_control_timer_set(...)
#define nrf_fem_control_timer_reset(...)
#define nrf_fem_control_ppi_fork_setup(...)
#define nrf_fem_control_ppi_task_setup(...)
#define nrf_fem_control_ppi_task_and_fork_setup(...)
#define nrf_fem_control_ppi_fork_clear(...)
#define nrf_fem_control_ppi_pin_task_setup(...)
#endif // ENABLE_FEM
@@ -1,224 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements common function for Front End Module control of the nRF 802.15.4 radio driver.
*
*/
#include "nrf_fem_control_api.h"
#include "compiler_abstraction.h"
#include "nrf_fem_control_config.h"
#include "nrf_fem_control_internal.h"
#include "nrf.h"
#include "hal/nrf_gpio.h"
#include "hal/nrf_gpiote.h"
#include "hal/nrf_ppi.h"
#include "hal/nrf_radio.h"
static nrf_fem_control_cfg_t m_nrf_fem_control_cfg; /**< FEM controller configuration. */
static volatile uint32_t m_time_latch; /**< Recently latched timer value. */
/**
* @section GPIO control.
*/
/** Initialize GPIO according to configuration provided. */
static void gpio_init(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable)
{
nrf_gpio_cfg_output(m_nrf_fem_control_cfg.pa_cfg.gpio_pin);
nrf_gpio_pin_write(m_nrf_fem_control_cfg.pa_cfg.gpio_pin,
!m_nrf_fem_control_cfg.pa_cfg.active_high);
}
if (m_nrf_fem_control_cfg.lna_cfg.enable)
{
nrf_gpio_cfg_output(m_nrf_fem_control_cfg.lna_cfg.gpio_pin);
nrf_gpio_pin_write(m_nrf_fem_control_cfg.lna_cfg.gpio_pin,
!m_nrf_fem_control_cfg.lna_cfg.active_high);
}
}
/** Configure GPIOTE task. */
__STATIC_INLINE void gpiote_configure(uint8_t pin, nrf_gpiote_outinit_t init_val)
{
nrf_gpiote_task_configure(m_nrf_fem_control_cfg.gpiote_ch_id,
pin,
NRF_GPIOTE_POLARITY_TOGGLE,
init_val);
nrf_gpiote_task_enable(m_nrf_fem_control_cfg.gpiote_ch_id);
}
/**
* @section PPI control.
*/
/** Initialize PPI according to configuration provided. */
static void ppi_init(void)
{
nrf_ppi_channel_include_in_group((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set,
(nrf_ppi_channel_group_t)m_nrf_fem_control_cfg.timer_ppi_grp);
nrf_ppi_channel_include_in_group((nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_clr,
(nrf_ppi_channel_group_t)m_nrf_fem_control_cfg.radio_ppi_grp);
nrf_ppi_channel_and_fork_endpoint_setup(
(nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_set,
(uint32_t)(&NRF_TIMER0->EVENTS_COMPARE[TIMER_CC_FEM]),
(uint32_t)(&NRF_GPIOTE->TASKS_OUT[m_nrf_fem_control_cfg.gpiote_ch_id]),
(uint32_t)(&NRF_PPI->TASKS_CHG[m_nrf_fem_control_cfg.timer_ppi_grp].DIS));
// Workaround for FTPAN-114, disable PPI to prevent second radio DISABLED event trigger.
nrf_ppi_channel_and_fork_endpoint_setup(
(nrf_ppi_channel_t)m_nrf_fem_control_cfg.ppi_ch_id_clr,
(uint32_t)(&NRF_RADIO->EVENTS_DISABLED),
(uint32_t)(&NRF_GPIOTE->TASKS_OUT[m_nrf_fem_control_cfg.gpiote_ch_id]),
(uint32_t)(&NRF_PPI->TASKS_CHG[m_nrf_fem_control_cfg.radio_ppi_grp].DIS));
}
/** Enable PPI. */
__STATIC_INLINE void ppi_enable(void)
{
NRF_PPI->CHENSET = (1 << m_nrf_fem_control_cfg.ppi_ch_id_set) |
(1 << m_nrf_fem_control_cfg.ppi_ch_id_clr);
}
/** Disable PPI. */
__STATIC_INLINE void ppi_disable(void)
{
NRF_PPI->CHENCLR = (1 << m_nrf_fem_control_cfg.ppi_ch_id_set) |
(1 << m_nrf_fem_control_cfg.ppi_ch_id_clr);
}
/**
* @section FEM API functions.
*/
void nrf_fem_control_cfg_set(const nrf_fem_control_cfg_t * p_cfg)
{
m_nrf_fem_control_cfg = *p_cfg;
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
gpio_init();
ppi_init();
nrf_fem_control_timer_init();
}
else
{
nrf_fem_control_timer_deinit();
}
}
void nrf_fem_control_cfg_get(nrf_fem_control_cfg_t * p_cfg)
{
*p_cfg = m_nrf_fem_control_cfg;
}
void nrf_fem_control_activate(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
nrf_fem_control_timer_start();
}
}
void nrf_fem_control_deactivate(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
nrf_fem_control_timer_stop();
nrf_gpiote_task_disable(m_nrf_fem_control_cfg.gpiote_ch_id);
ppi_disable();
}
}
void nrf_fem_control_time_latch(void)
{
if (m_nrf_fem_control_cfg.pa_cfg.enable || m_nrf_fem_control_cfg.lna_cfg.enable)
{
m_time_latch = nrf_fem_control_timer_time_get();
}
}
void nrf_fem_control_pa_set(bool shorts_used, bool turnaround)
{
uint32_t target_time;
uint32_t latency;
latency = turnaround ? NRF_FEM_RADIO_TX_TURNAROUND_LATENCY_US :
NRF_FEM_RADIO_TX_STARTUP_LATENCY_US;
if (m_nrf_fem_control_cfg.pa_cfg.enable)
{
gpiote_configure(m_nrf_fem_control_cfg.pa_cfg.gpio_pin,
(nrf_gpiote_outinit_t)!m_nrf_fem_control_cfg.pa_cfg.active_high);
ppi_enable();
uint32_t tifs = nrf_radio_ifs_get();
target_time = tifs <= latency ?
m_time_latch + latency - NRF_FEM_PA_TIME_IN_ADVANCE :
m_time_latch + tifs - NRF_FEM_RADIO_TIFS_DRIFT_US - NRF_FEM_PA_TIME_IN_ADVANCE;
if (shorts_used)
{
target_time -= nrf_fem_control_irq_delay_get();
}
nrf_fem_control_timer_set(target_time);
}
}
void nrf_fem_control_lna_set(bool shorts_used)
{
uint32_t target_time;
if (m_nrf_fem_control_cfg.lna_cfg.enable)
{
gpiote_configure(m_nrf_fem_control_cfg.lna_cfg.gpio_pin,
(nrf_gpiote_outinit_t)!m_nrf_fem_control_cfg.lna_cfg.active_high);
ppi_enable();
target_time = m_time_latch + NRF_FEM_RADIO_RX_STARTUP_LATENCY_US -
NRF_FEM_LNA_TIME_IN_ADVANCE;
if (shorts_used)
{
target_time -= nrf_fem_control_irq_delay_get();
}
nrf_fem_control_timer_set(target_time);
}
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ extern "C" {
*/
/** Time in us when PA GPIO is activated before radio is ready for transmission. */
#define NRF_FEM_PA_TIME_IN_ADVANCE 5
#define NRF_FEM_PA_TIME_IN_ADVANCE 23
/** Time in us when LNA GPIO is activated before radio is ready for reception. */
#define NRF_FEM_LNA_TIME_IN_ADVANCE 5
@@ -53,15 +53,6 @@ extern "C" {
/** Radio ramp-up time in RX mode, in us. */
#define NRF_FEM_RADIO_RX_STARTUP_LATENCY_US 40
/** Radio turnaround from RX to TX mode, in us. */
#define NRF_FEM_RADIO_TX_TURNAROUND_LATENCY_US 20
/** Radio turnaround from TX to RX mode, in us. */
#define NRF_FEM_RADIO_RX_TURNAROUND_LATENCY_US 20
/** Tifs drift measured, in us. */
#define NRF_FEM_RADIO_TIFS_DRIFT_US 20
#else
#error "Device not supported."
@@ -1,91 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements internal functions of Front End Module control for standalone version of
* the nRF 802.15.4 radio driver.
*
*/
#include "nrf_fem_control_internal.h"
#include "hal/nrf_timer.h"
static bool m_timer_started = false; /**< Information if timer is running. */
void nrf_fem_control_timer_start(void)
{
if (!m_timer_started)
{
nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_START);
m_timer_started = true;
}
}
void nrf_fem_control_timer_stop(void)
{
nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
m_timer_started = false;
}
void nrf_fem_control_timer_set(uint32_t target)
{
nrf_timer_cc_write(NRF_TIMER0, (nrf_timer_cc_channel_t)TIMER_CC_FEM, target);
}
uint32_t nrf_fem_control_timer_time_get(void)
{
NRF_TIMER0->TASKS_CAPTURE[TIMER_CC_CAPTURE] = 1;
return NRF_TIMER0->CC[TIMER_CC_CAPTURE];
}
void nrf_fem_control_timer_init(void)
{
nrf_fem_control_timer_stop();
nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
nrf_timer_mode_set(NRF_TIMER0, NRF_TIMER_MODE_TIMER);
nrf_timer_bit_width_set(NRF_TIMER0, NRF_TIMER_BIT_WIDTH_32);
nrf_timer_frequency_set(NRF_TIMER0, NRF_TIMER_FREQ_1MHz);
}
void nrf_fem_control_timer_deinit(void)
{
nrf_fem_control_timer_stop();
nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
}
uint32_t nrf_fem_control_irq_delay_get(void)
{
return 0;
}
@@ -1,82 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @brief Front End Module control internal functions.
*
*/
#ifndef NRF_FEM_CONTROL_INTERNAL_H_
#define NRF_FEM_CONTROL_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "nrf_fem_control_api.h"
#define TIMER_CC_FEM 3 /**< Compare channel used by the module. */
#define TIMER_CC_CAPTURE 2 /**< Compare channel used for time capture. */
/**@brief Start timer used by the module. */
void nrf_fem_control_timer_start(void);
/**@brief Stop timer used by the module. */
void nrf_fem_control_timer_stop(void);
/**@brief Set timer CC target value.
*
* @param[in] target Traget time.
*/
void nrf_fem_control_timer_set(uint32_t target);
/**@brief Get current time from the timer.
*
* @retval Current timer time.
*/
uint32_t nrf_fem_control_timer_time_get(void);
/**@brief Initialize timer. */
void nrf_fem_control_timer_init(void);
/**@brief De-initialize timer. */
void nrf_fem_control_timer_deinit(void);
/**@brief Get configuration specific irq entry delay.
*
* @retval Delay value.
*/
uint32_t nrf_fem_control_irq_delay_get(void);
#ifdef __cplusplus
}
#endif
#endif /* NRF_FEM_CONTROL_INTERNAL_H_ */
@@ -1,78 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements internal functions of Front End Module control for
* nRF 802.15.4 radio driver working with SoftDevice RAAL.
*
*/
#include "nrf_fem_control_internal.h"
#include "hal/nrf_timer.h"
#define SOFTDEVICE_IRQ_ENTRY_DELAY 4UL /**< An IRQ entry delay when using SoftDevice. */
void nrf_fem_control_timer_start(void)
{
// Intentionally empty. In this configuration timer is controlled by RAAL.
}
void nrf_fem_control_timer_stop(void)
{
// Intentionally empty. In this configuration timer is controlled by RAAL.
}
void nrf_fem_control_timer_set(uint32_t target)
{
nrf_timer_cc_write(NRF_TIMER0, (nrf_timer_cc_channel_t)TIMER_CC_FEM, target);
}
uint32_t nrf_fem_control_timer_time_get(void)
{
NRF_TIMER0->TASKS_CAPTURE[TIMER_CC_CAPTURE] = 1;
return NRF_TIMER0->CC[TIMER_CC_CAPTURE];
}
void nrf_fem_control_timer_init(void)
{
// Intentionally empty. In this configuration timer is controlled by RAAL.
}
void nrf_fem_control_timer_deinit(void)
{
// Intentionally empty. In this configuration timer is controlled by RAAL.
}
uint32_t nrf_fem_control_irq_delay_get(void)
{
return SOFTDEVICE_IRQ_ENTRY_DELAY;
}
+304 -193
View File
@@ -1,4 +1,4 @@
/* Copyright (c) 2016, Nordic Semiconductor ASA
/* Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -80,15 +80,17 @@ typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */
NRF_RADIO_EVENT_ADDRESS = offsetof(NRF_RADIO_Type, EVENTS_ADDRESS), /**< Address sent or received. */
NRF_RADIO_EVENT_END = offsetof(NRF_RADIO_Type, EVENTS_END), /**< Packet transmitted or received. */
NRF_RADIO_EVENT_DISABLED = offsetof(NRF_RADIO_Type, EVENTS_DISABLED), /**< Radio has been disabled. */
NRF_RADIO_EVENT_RSSIEND = offsetof(NRF_RADIO_Type, EVENTS_RSSIEND), /**< Sampling of receive signal strength complete. */
NRF_RADIO_EVENT_BCMATCH = offsetof(NRF_RADIO_Type, EVENTS_BCMATCH), /**< Bit counter reached bit count value. */
NRF_RADIO_EVENT_CRCOK = offsetof(NRF_RADIO_Type, EVENTS_CRCOK), /**< Packet received with correct CRC. */
NRF_RADIO_EVENT_CRCERROR = offsetof(NRF_RADIO_Type, EVENTS_CRCERROR), /**< Packet received with incorrect CRC. */
NRF_RADIO_EVENT_CCAIDLE = offsetof(NRF_RADIO_Type, EVENTS_CCAIDLE), /**< Wireless medium is idle. */
NRF_RADIO_EVENT_CCABUSY = offsetof(NRF_RADIO_Type, EVENTS_CCABUSY), /**< Wireless medium is busy. */
NRF_RADIO_EVENT_RSSIEND = offsetof(NRF_RADIO_Type, EVENTS_RSSIEND), /**< Sampling of receive signal strength complete. */
NRF_RADIO_EVENT_MHRMATCH = offsetof(NRF_RADIO_Type, EVENTS_MHRMATCH), /**< MAC Header match found. */
NRF_RADIO_EVENT_FRAMESTART = offsetof(NRF_RADIO_Type, EVENTS_FRAMESTART), /**< IEEE 802.15.4 length field received. */
NRF_RADIO_EVENT_EDEND = offsetof(NRF_RADIO_Type, EVENTS_EDEND), /**< Energy Detection procedure ended. */
NRF_RADIO_EVENT_BCMATCH = offsetof(NRF_RADIO_Type, EVENTS_BCMATCH), /**< Bit counter reached bit count value. */
NRF_RADIO_EVENT_CCAIDLE = offsetof(NRF_RADIO_Type, EVENTS_CCAIDLE), /**< Wireless medium is idle. */
NRF_RADIO_EVENT_CCABUSY = offsetof(NRF_RADIO_Type, EVENTS_CCABUSY), /**< Wireless medium is busy. */
NRF_RADIO_EVENT_TXREADY = offsetof(NRF_RADIO_Type, EVENTS_TXREADY), /**< Radio has ramped up and is ready to be started TX path. */
NRF_RADIO_EVENT_RXREADY = offsetof(NRF_RADIO_Type, EVENTS_RXREADY), /**< Radio has ramped up and is ready to be started RX path. */
NRF_RADIO_EVENT_MHRMATCH = offsetof(NRF_RADIO_Type, EVENTS_MHRMATCH), /**< MAC Header match found. */
NRF_RADIO_EVENT_PHYEND = offsetof(NRF_RADIO_Type, EVENTS_PHYEND), /**< Generated in Ble_LR125Kbit, Ble_LR500Kbit and Ieee802154_250Kbit modes when last bit is sent on air. */
} nrf_radio_event_t; /*lint -restore */
@@ -102,14 +104,14 @@ typedef enum
NRF_RADIO_INT_ADDRESS_MASK = RADIO_INTENSET_ADDRESS_Msk, /**< Mask for enabling or disabling an interrupt on ADDRESS event. */
NRF_RADIO_INT_END_MASK = RADIO_INTENSET_END_Msk, /**< Mask for enabling or disabling an interrupt on END event. */
NRF_RADIO_INT_DISABLED_MASK = RADIO_INTENSET_DISABLED_Msk, /**< Mask for enabling or disabling an interrupt on DISABLED event. */
NRF_RADIO_INT_RSSIEND_MASK = RADIO_INTENSET_RSSIEND_Msk, /**< Mask for enabling or disabling an interrupt on RSSIEND event. */
NRF_RADIO_INT_BCMATCH_MASK = RADIO_INTENSET_BCMATCH_Msk, /**< Mask for enabling or disabling an interrupt on BCMATCH event. */
NRF_RADIO_INT_CRCOK_MASK = RADIO_INTENSET_CRCOK_Msk, /**< Mask for enabling or disabling an interrupt on CRCOK event. */
NRF_RADIO_INT_CRCERROR_MASK = RADIO_INTENSET_CRCERROR_Msk, /**< Mask for enabling or disabling an interrupt on CRCERROR event. */
NRF_RADIO_INT_CCAIDLE_MASK = RADIO_INTENSET_CCAIDLE_Msk, /**< Mask for enabling or disabling an interrupt on CCAIDLE event. */
NRF_RADIO_INT_CCABUSY_MASK = RADIO_INTENSET_CCABUSY_Msk, /**< Mask for enabling or disabling an interrupt on CCABUSY event. */
NRF_RADIO_INT_RSSIEND_MASK = RADIO_INTENSET_RSSIEND_Msk, /**< Mask for enabling or disabling an interrupt on RSSIEND event. */
NRF_RADIO_INT_FRAMESTART_MASK = RADIO_INTENSET_FRAMESTART_Msk, /**< Mask for enabling or disabling an interrupt on FRAMESTART event. */
NRF_RADIO_INT_EDEND_MASK = RADIO_INTENSET_EDEND_Msk, /**< Mask for enabling or disabling an interrupt on EDEND event. */
NRF_RADIO_INT_BCMATCH_MASK = RADIO_INTENSET_BCMATCH_Msk, /**< Mask for enabling or disabling an interrupt on BCMATCH event. */
NRF_RADIO_INT_CCAIDLE_MASK = RADIO_INTENSET_CCAIDLE_Msk, /**< Mask for enabling or disabling an interrupt on CCAIDLE event. */
NRF_RADIO_INT_CCABUSY_MASK = RADIO_INTENSET_CCABUSY_Msk, /**< Mask for enabling or disabling an interrupt on CCABUSY event. */
NRF_RADIO_INT_PHYEND_MASK = RADIO_INTENSET_PHYEND_Msk, /**< Mask for enabling or disabling an interrupt on PHYEND event. */
} nrf_radio_int_mask_t;
@@ -120,12 +122,20 @@ typedef enum
typedef enum
{
NRF_RADIO_SHORT_READY_START_MASK = RADIO_SHORTS_READY_START_Msk, /**< Mask for setting shortcut between EVENT_READY and TASK_START. */
NRF_RADIO_SHORT_ADDRESS_RSSISTART_MASK = RADIO_SHORTS_ADDRESS_RSSISTART_Msk, /**< Mask for setting shortcut between EVENT_ADDRESS and TASK_RSSISTART. */
NRF_RADIO_SHORT_END_DISABLE_MASK = RADIO_SHORTS_END_DISABLE_Msk, /**< Mask for setting shortcut between EVENT_END and TASK_DISABLE. */
NRF_RADIO_SHORT_END_START_MASK = RADIO_SHORTS_END_START_Msk, /**< Mask for setting shortcut between EVENT_END and TASK_START. */
NRF_RADIO_SHORT_CCAIDLE_TXEN_MASK = RADIO_SHORTS_CCAIDLE_TXEN_Msk, /**< Mask for setting shortcut between EVENT_CCAIDLE and TASK_TXEN. */
NRF_RADIO_SHORT_DISABLED_TXEN_MASK = RADIO_SHORTS_DISABLED_TXEN_Msk, /**< Mask for setting shortcut between EVENT_DISABLED and TASK_TXEN. */
NRF_RADIO_SHORT_DISABLED_RXEN_MASK = RADIO_SHORTS_DISABLED_RXEN_Msk, /**< Mask for setting shortcut between EVENT_DISABLED and TASK_RXEN. */
NRF_RADIO_SHORT_ADDRESS_RSSISTART_MASK = RADIO_SHORTS_ADDRESS_RSSISTART_Msk, /**< Mask for setting shortcut between EVENT_ADDRESS and TASK_RSSISTART. */
NRF_RADIO_SHORT_ADDRESS_BCSTART_MASK = RADIO_SHORTS_ADDRESS_BCSTART_Msk, /**< Mask for setting shortcut between EVENT_ADDRESS and TASK_BCSTART. */
NRF_RADIO_SHORT_END_START_MASK = RADIO_SHORTS_END_START_Msk, /**< Mask for setting shortcut between EVENT_END and TASK_START. */
NRF_RADIO_SHORT_RXREADY_CCASTART_MASK = RADIO_SHORTS_RXREADY_CCASTART_Msk, /**< Mask for setting shortcut between EVENT_RXREADY and TASK_CCASTART. */
NRF_RADIO_SHORT_CCAIDLE_TXEN_MASK = RADIO_SHORTS_CCAIDLE_TXEN_Msk, /**< Mask for setting shortcut between EVENT_CCAIDLE and TASK_TXEN. */
NRF_RADIO_SHORT_CCABUSY_DISABLE_MASK = RADIO_SHORTS_CCABUSY_DISABLE_Msk, /**< Mask for setting shortcut between EVENT_CCABUSY and TASK_DISABLE. */
NRF_RADIO_SHORT_FRAMESTART_BCSTART_MASK = RADIO_SHORTS_FRAMESTART_BCSTART_Msk, /**< Mask for setting shortcut between EVENT_FRAMESTART and TASK_BCSTART. */
NRF_RADIO_SHORT_READY_EDSTART_MASK = RADIO_SHORTS_READY_EDSTART_Msk, /**< Mask for setting shortcut between EVENT_READY and TASK_EDSTART. */
NRF_RADIO_SHORT_EDEND_DISABLE_MASK = RADIO_SHORTS_EDEND_DISABLE_Msk, /**< Mask for setting shortcut between EVENT_EDEND and TASK_DISABLE. */
NRF_RADIO_SHORT_TXREADY_START_MASK = RADIO_SHORTS_TXREADY_START_Msk, /**< Mask for setting shortcut between EVENT_TXREADY and TASK_START. */
NRF_RADIO_SHORT_RXREADY_START_MASK = RADIO_SHORTS_RXREADY_START_Msk, /**< Mask for setting shortcut between EVENT_RXREADY and TASK_START. */
NRF_RADIO_SHORT_PHYEND_DISABLE_MASK = RADIO_SHORTS_PHYEND_DISABLE_Msk, /**< Mask for setting shortcut between EVENT_PHYEND and TASK_DISABLE. */
NRF_RADIO_SHORT_PHYEND_START_MASK = RADIO_SHORTS_PHYEND_START_Msk, /**< Mask for setting shortcut between EVENT_PHYEND and TASK_START. */
} nrf_radio_short_mask_t;
@@ -220,20 +230,14 @@ typedef enum
*
* @param[in] radio_int_mask Mask of interrupts.
*/
__STATIC_INLINE void nrf_radio_int_enable(uint32_t radio_int_mask)
{
NRF_RADIO->INTENSET = radio_int_mask;
}
__STATIC_INLINE void nrf_radio_int_enable(uint32_t radio_int_mask);
/**
* @brief Function for disabling interrupts.
*
* @param[in] radio_int_mask Mask of interrupts.
*/
__STATIC_INLINE void nrf_radio_int_disable(uint32_t radio_int_mask)
{
NRF_RADIO->INTENCLR = radio_int_mask;
}
__STATIC_INLINE void nrf_radio_int_disable(uint32_t radio_int_mask);
/**
* @brief Function for getting the state of a specific interrupt.
@@ -243,10 +247,7 @@ __STATIC_INLINE void nrf_radio_int_disable(uint32_t radio_int_mask)
* @retval true If the interrupt is not enabled.
* @retval false If the interrupt is enabled.
*/
__STATIC_INLINE bool nrf_radio_int_get(nrf_radio_int_mask_t radio_int_mask)
{
return (bool)(NRF_RADIO->INTENCLR & radio_int_mask);
}
__STATIC_INLINE bool nrf_radio_int_get(nrf_radio_int_mask_t radio_int_mask);
/**
* @brief Function for getting the address of a specific task.
@@ -255,20 +256,14 @@ __STATIC_INLINE bool nrf_radio_int_get(nrf_radio_int_mask_t radio_int_mask)
*
* @param[in] radio_task Task.
*/
__STATIC_INLINE uint32_t *nrf_radio_task_address_get(nrf_radio_task_t radio_task)
{
return (uint32_t *)((uint8_t *)NRF_RADIO + radio_task);
}
__STATIC_INLINE uint32_t *nrf_radio_task_address_get(nrf_radio_task_t radio_task);
/**
* @brief Function for setting a specific task.
*
* @param[in] radio_task Task.
*/
__STATIC_INLINE void nrf_radio_task_trigger(nrf_radio_task_t radio_task)
{
*((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_task)) = NRF_RADIO_TASK_SET;
}
__STATIC_INLINE void nrf_radio_task_trigger(nrf_radio_task_t radio_task);
/**
* @brief Function for getting address of a specific event.
@@ -277,24 +272,14 @@ __STATIC_INLINE void nrf_radio_task_trigger(nrf_radio_task_t radio_task)
*
* @param[in] radio_event Event.
*/
__STATIC_INLINE uint32_t *nrf_radio_event_address_get(nrf_radio_event_t radio_event)
{
return (uint32_t *)((uint8_t *)NRF_RADIO + radio_event);
}
__STATIC_INLINE uint32_t *nrf_radio_event_address_get(nrf_radio_event_t radio_event);
/**
* @brief Function for clearing a specific event.
*
* @param[in] radio_event Event.
*/
__STATIC_INLINE void nrf_radio_event_clear(nrf_radio_event_t radio_event)
{
*((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_event)) = NRF_RADIO_EVENT_CLEAR;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_event));
(void)dummy;
#endif
}
__STATIC_INLINE void nrf_radio_event_clear(nrf_radio_event_t radio_event);
/**
* @brief Function for getting the state of a specific event.
@@ -304,10 +289,7 @@ __STATIC_INLINE void nrf_radio_event_clear(nrf_radio_event_t radio_event)
* @retval true If the event is not set.
* @retval false If the event is set.
*/
__STATIC_INLINE bool nrf_radio_event_get(nrf_radio_event_t radio_event)
{
return (bool) * ((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_event));
}
__STATIC_INLINE bool nrf_radio_event_get(nrf_radio_event_t radio_event);
/**
* @brief Function for setting shortcuts.
@@ -315,10 +297,7 @@ __STATIC_INLINE bool nrf_radio_event_get(nrf_radio_event_t radio_event)
* @param[in] radio_short_mask Mask of shortcuts.
*
*/
__STATIC_INLINE void nrf_radio_shorts_enable(uint32_t radio_short_mask)
{
NRF_RADIO->SHORTS |= radio_short_mask;
}
__STATIC_INLINE void nrf_radio_shorts_enable(uint32_t radio_short_mask);
/**
* @brief Function for clearing shortcuts.
@@ -326,10 +305,7 @@ __STATIC_INLINE void nrf_radio_shorts_enable(uint32_t radio_short_mask)
* @param[in] radio_short_mask Mask of shortcuts.
*
*/
__STATIC_INLINE void nrf_radio_shorts_disable(uint32_t radio_short_mask)
{
NRF_RADIO->SHORTS &= ~radio_short_mask;
}
__STATIC_INLINE void nrf_radio_shorts_disable(uint32_t radio_short_mask);
/**
* @brief Function for setting shortcuts.
@@ -337,10 +313,7 @@ __STATIC_INLINE void nrf_radio_shorts_disable(uint32_t radio_short_mask)
* @param[in] radio_short_mask Mask of shortcuts.
*
*/
__STATIC_INLINE void nrf_radio_shorts_set(uint32_t radio_short_mask)
{
NRF_RADIO->SHORTS = radio_short_mask;
}
__STATIC_INLINE void nrf_radio_shorts_set(uint32_t radio_short_mask);
/**
* @brief Function for getting shortcuts.
@@ -348,69 +321,45 @@ __STATIC_INLINE void nrf_radio_shorts_set(uint32_t radio_short_mask)
* @return Mask of shortcuts.
*
*/
__STATIC_INLINE uint32_t nrf_radio_shorts_get(void)
{
return NRF_RADIO->SHORTS;
}
__STATIC_INLINE uint32_t nrf_radio_shorts_get(void);
/**
* @brief Function for getting present state of the radio module.
*/
__STATIC_INLINE nrf_radio_state_t nrf_radio_state_get(void)
{
return (nrf_radio_state_t) NRF_RADIO->STATE;
}
__STATIC_INLINE nrf_radio_state_t nrf_radio_state_get(void);
/**
* @brief Function for setting Packet Pointer to given location in memory.
*
* @param[in] p_radio_packet_ptr Pointer to tx or rx packet buffer.
*/
__STATIC_INLINE void nrf_radio_packet_ptr_set(const void *p_radio_packet_ptr)
{
NRF_RADIO->PACKETPTR = (uint32_t) p_radio_packet_ptr;
}
__STATIC_INLINE void nrf_radio_packet_ptr_set(const void *p_radio_packet_ptr);
/**
* @brief Function for getting CRC status of last received packet.
*/
__STATIC_INLINE nrf_radio_crc_status_t nrf_radio_crc_status_get(void)
{
return (nrf_radio_crc_status_t) NRF_RADIO->CRCSTATUS;
}
__STATIC_INLINE nrf_radio_crc_status_t nrf_radio_crc_status_get(void);
/**
* @brief Function for setting Clear Channel Assessment mode.
*
* @param[in] radio_cca_mode Mode of CCA
*/
__STATIC_INLINE void nrf_radio_cca_mode_set(nrf_radio_cca_mode_t radio_cca_mode)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCAMODE_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_mode << RADIO_CCACTRL_CCAMODE_Pos);
}
__STATIC_INLINE void nrf_radio_cca_mode_set(nrf_radio_cca_mode_t radio_cca_mode);
/**
* @brief Function for setting CCA Energy Busy Threshold.
*
* @param[in] radio_cca_ed_threshold Energy Detection threshold value.
*/
__STATIC_INLINE void nrf_radio_cca_ed_threshold_set(uint8_t radio_cca_ed_threshold)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCAEDTHRES_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_ed_threshold << RADIO_CCACTRL_CCAEDTHRES_Pos);
}
__STATIC_INLINE void nrf_radio_cca_ed_threshold_set(uint8_t radio_cca_ed_threshold);
/**
* @brief Function for setting CCA Correlator Busy Threshold.
*
* @param[in] radio_cca_corr_threshold Correlator Busy Threshold.
*/
__STATIC_INLINE void nrf_radio_cca_corr_threshold_set(uint8_t radio_cca_corr_threshold_set)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCACORRTHRES_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_corr_threshold_set << RADIO_CCACTRL_CCACORRTHRES_Pos);
}
__STATIC_INLINE void nrf_radio_cca_corr_threshold_set(uint8_t radio_cca_corr_threshold_set);
/**
* @brief Function for setting limit of occurances above Correlator Threshold.
@@ -419,32 +368,21 @@ __STATIC_INLINE void nrf_radio_cca_corr_threshold_set(uint8_t radio_cca_corr_thr
*
* @param[in] radio_cca_corr_cnt Limit of occurances above Correlator Threshold
*/
__STATIC_INLINE void nrf_radio_cca_corr_counter_set(uint8_t radio_cca_corr_counter_set)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCACORRCNT_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_corr_counter_set << RADIO_CCACTRL_CCACORRCNT_Pos);
}
__STATIC_INLINE void nrf_radio_cca_corr_counter_set(uint8_t radio_cca_corr_counter_set);
/**
* @brief Function for setting Radio data rate and modulation settings.
*
* @param[in] radio_mode Mode of radio data rate and modulation.
*/
__STATIC_INLINE void nrf_radio_mode_set(nrf_radio_mode_t radio_mode)
{
NRF_RADIO->MODE = ((uint32_t) radio_mode << RADIO_MODE_MODE_Pos);
}
__STATIC_INLINE void nrf_radio_mode_set(nrf_radio_mode_t radio_mode);
/**
* @brief Function for setting Length of LENGTH field in number of bits.
*
* @param[in] radio_length_length Length of LENGTH field in number of bits.
*/
__STATIC_INLINE void nrf_radio_config_length_field_length_set(uint8_t radio_length_length)
{
NRF_RADIO->PCNF0 &= (~RADIO_PCNF0_LFLEN_Msk);
NRF_RADIO->PCNF0 |= ((uint32_t) radio_length_length << RADIO_PCNF0_LFLEN_Pos);
}
__STATIC_INLINE void nrf_radio_config_length_field_length_set(uint8_t radio_length_length);
/**
* @brief Function for setting length of preamble on air.
@@ -452,44 +390,28 @@ __STATIC_INLINE void nrf_radio_config_length_field_length_set(uint8_t radio_leng
* @param[in] radio_preamble_length Length of preamble on air.
*/
__STATIC_INLINE void nrf_radio_config_preamble_length_set(
nrf_radio_preamble_length_t radio_preamble_length)
{
NRF_RADIO->PCNF0 &= (~RADIO_PCNF0_PLEN_Msk);
NRF_RADIO->PCNF0 |= ((uint32_t) radio_preamble_length << RADIO_PCNF0_PLEN_Pos);
}
nrf_radio_preamble_length_t radio_preamble_length);
/**
* @brief Function for setting if LENGTH field contains CRC.
*
* @param[in] radio_length_contains_crc True if LENGTH field should contain CRC.
*/
__STATIC_INLINE void nrf_radio_config_crc_included_set(bool radio_length_contains_crc)
{
NRF_RADIO->PCNF0 &= (~RADIO_PCNF0_CRCINC_Msk);
NRF_RADIO->PCNF0 |= ((uint32_t) radio_length_contains_crc << RADIO_PCNF0_CRCINC_Pos);
}
__STATIC_INLINE void nrf_radio_config_crc_included_set(bool radio_length_contains_crc);
/**
* @brief Function for setting maximum length of packet payload.
*
* @param[in] radio_max_packet_length Maximum length of packet payload.
*/
__STATIC_INLINE void nrf_radio_config_max_length_set(uint8_t radio_max_packet_length)
{
NRF_RADIO->PCNF1 &= (~RADIO_PCNF1_MAXLEN_Msk);
NRF_RADIO->PCNF1 |= ((uint32_t) radio_max_packet_length << RADIO_PCNF1_MAXLEN_Pos);
}
__STATIC_INLINE void nrf_radio_config_max_length_set(uint8_t radio_max_packet_length);
/**
* @brief Function for setting CRC length.
*
* @param[in] radio_crc_length CRC length in number of bytes [0-3].
*/
__STATIC_INLINE void nrf_radio_crc_length_set(uint8_t radio_crc_length)
{
NRF_RADIO->CRCCNF &= (~RADIO_CRCCNF_LEN_Msk);
NRF_RADIO->CRCCNF |= ((uint32_t) radio_crc_length << RADIO_CRCCNF_LEN_Pos);
}
__STATIC_INLINE void nrf_radio_crc_length_set(uint8_t radio_crc_length);
/**
* @brief Function for setting if address filed should be included or excluded from CRC calculation.
@@ -497,21 +419,21 @@ __STATIC_INLINE void nrf_radio_crc_length_set(uint8_t radio_crc_length)
* @param[in] radio_crc_skip_address Include or exclude packet address field out of CRC.
*/
__STATIC_INLINE void nrf_radio_crc_includes_address_set(
nrf_radio_crc_includes_addr_t radio_crc_skip_address)
{
NRF_RADIO->CRCCNF &= (~RADIO_CRCCNF_SKIPADDR_Msk);
NRF_RADIO->CRCCNF |= ((uint32_t) radio_crc_skip_address << RADIO_CRCCNF_SKIPADDR_Pos);
}
nrf_radio_crc_includes_addr_t radio_crc_skip_address);
/**
* @brief Function for setting CRC polynominal.
*
* @param[in] radio_crc_polynominal CRC polynominal to set.
*/
__STATIC_INLINE void nrf_radio_crc_polynominal_set(uint32_t radio_crc_polynominal)
{
NRF_RADIO->CRCPOLY = (radio_crc_polynominal << RADIO_CRCPOLY_CRCPOLY_Pos);
}
__STATIC_INLINE void nrf_radio_crc_polynominal_set(uint32_t radio_crc_polynominal);
/**
* @brief Function for getting CRC polynominal.
*
* @return CRC polynominal.
*/
__STATIC_INLINE uint32_t nrf_radio_crc_polynominal_get(void);
/**
* @brief Function for getting RSSI sample result.
@@ -520,146 +442,335 @@ __STATIC_INLINE void nrf_radio_crc_polynominal_set(uint32_t radio_crc_polynomina
* Actual received signal strength is therefore as follows:
* received signal strength = - returned_value dBm .
*/
__STATIC_INLINE uint8_t nrf_radio_rssi_sample_get(void)
{
return (uint8_t)(((NRF_RADIO->RSSISAMPLE) & RADIO_RSSISAMPLE_RSSISAMPLE_Msk) >>
RADIO_RSSISAMPLE_RSSISAMPLE_Pos);
}
__STATIC_INLINE uint8_t nrf_radio_rssi_sample_get(void);
/**
* @brief Function for setting MAC Header Match Unit search pattern configuration.
*
* @param[in] radio_mhmu_search_pattern Search Pattern Configuration.
*/
__STATIC_INLINE void nrf_radio_mhmu_search_pattern_set(uint32_t radio_mhmu_search_pattern)
{
NRF_RADIO->MHRMATCHCONF = radio_mhmu_search_pattern;
}
__STATIC_INLINE void nrf_radio_mhmu_search_pattern_set(uint32_t radio_mhmu_search_pattern);
/**
* @brief Function for setting MAC Header Match Unit pattern mask configuration.
*
* @param[in] radio_mhmu_pattern_mask Pattern mask.
*/
__STATIC_INLINE void nrf_radio_mhmu_pattern_mask_set(uint32_t radio_mhmu_pattern_mask)
{
NRF_RADIO->MHRMATCHMAS = radio_mhmu_pattern_mask;
}
__STATIC_INLINE void nrf_radio_mhmu_pattern_mask_set(uint32_t 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);
}
__STATIC_INLINE void nrf_radio_ramp_up_mode_set(nrf_radio_ramp_up_mode_t ramp_up_mode);
/**
* @brief Function for setting radio frequency.
*
* @param[in] radio_frequency Frequency above 2400 MHz [MHz]
*/
__STATIC_INLINE void nrf_radio_frequency_set(uint32_t radio_frequency)
{
NRF_RADIO->FREQUENCY = radio_frequency;
}
__STATIC_INLINE void nrf_radio_frequency_set(uint32_t radio_frequency);
/**
* @brief Function for getting radio frequency.
*
* @returns Frequency above 2400 MHz [MHz]
*/
__STATIC_INLINE uint32_t nrf_radio_frequency_get(void)
{
return NRF_RADIO->FREQUENCY;
}
__STATIC_INLINE uint32_t nrf_radio_frequency_get(void);
/**
* @brief Function for setting radio transmit power.
*
* @param[in] radio_tx_power Transmit power of the radio.
*/
__STATIC_INLINE void nrf_radio_tx_power_set(int8_t radio_tx_power)
{
NRF_RADIO->TXPOWER = (uint8_t) radio_tx_power;
}
__STATIC_INLINE void nrf_radio_tx_power_set(int8_t radio_tx_power);
/**
* @brief Function for setting Inter Frame Spacing
*
* @param[in] radio_ifs Inter frame spacing [us].
*/
__STATIC_INLINE void nrf_radio_ifs_set(uint32_t radio_ifs)
{
NRF_RADIO->TIFS = radio_ifs;
}
__STATIC_INLINE void nrf_radio_ifs_set(uint32_t radio_ifs);
/**
* @brief Function for getting Inter Frame Spacing
*
* @return Current Inter Frame Spacing
*/
__STATIC_INLINE uint32_t nrf_radio_ifs_get(void)
{
return NRF_RADIO->TIFS & RADIO_TIFS_TIFS_Msk;
}
__STATIC_INLINE uint32_t nrf_radio_ifs_get(void);
/**
* @brief Function for setting Bit counter compare.
*
* @param[in] radio_bcc Bit counter compare [bits].
*/
__STATIC_INLINE void nrf_radio_bcc_set(uint32_t radio_bcc)
{
NRF_RADIO->BCC = radio_bcc;
}
__STATIC_INLINE void nrf_radio_bcc_set(uint32_t radio_bcc);
/**
* @brief Function for getting Bit counter compare.
*/
__STATIC_INLINE uint32_t nrf_radio_bcc_get(void)
{
return NRF_RADIO->BCC;
}
__STATIC_INLINE uint32_t nrf_radio_bcc_get(void);
/**
* @brief Function for getting Energy Detection level.
*/
__STATIC_INLINE uint8_t nrf_radio_ed_sample_get(void)
{
return (uint8_t) NRF_RADIO->EDSAMPLE;
}
__STATIC_INLINE uint8_t nrf_radio_ed_sample_get(void);
/**
* @brief Function for setting number of iterations to perform ED scan.
*
* @param[in] radio_ed_loop_count Number of iterations during ED procedure.
*/
__STATIC_INLINE void nrf_radio_ed_loop_count_set(uint32_t radio_ed_loop_count)
{
NRF_RADIO->EDCNT = (radio_ed_loop_count & 0x001FFFFF);
}
__STATIC_INLINE void nrf_radio_ed_loop_count_set(uint32_t radio_ed_loop_count);
/**
* @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;
}
__STATIC_INLINE void nrf_radio_power_set(bool radio_power);
/**
*@}
**/
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_radio_int_enable(uint32_t radio_int_mask)
{
NRF_RADIO->INTENSET = radio_int_mask;
}
__STATIC_INLINE void nrf_radio_int_disable(uint32_t radio_int_mask)
{
NRF_RADIO->INTENCLR = radio_int_mask;
}
__STATIC_INLINE bool nrf_radio_int_get(nrf_radio_int_mask_t radio_int_mask)
{
return (bool)(NRF_RADIO->INTENCLR & radio_int_mask);
}
__STATIC_INLINE uint32_t *nrf_radio_task_address_get(nrf_radio_task_t radio_task)
{
return (uint32_t *)((uint8_t *)NRF_RADIO + radio_task);
}
__STATIC_INLINE void nrf_radio_task_trigger(nrf_radio_task_t radio_task)
{
*((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_task)) = NRF_RADIO_TASK_SET;
}
__STATIC_INLINE uint32_t *nrf_radio_event_address_get(nrf_radio_event_t radio_event)
{
return (uint32_t *)((uint8_t *)NRF_RADIO + radio_event);
}
__STATIC_INLINE void nrf_radio_event_clear(nrf_radio_event_t radio_event)
{
*((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_event)) = NRF_RADIO_EVENT_CLEAR;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_radio_event_get(nrf_radio_event_t radio_event)
{
return (bool) * ((volatile uint32_t *)((uint8_t *)NRF_RADIO + radio_event));
}
__STATIC_INLINE void nrf_radio_shorts_enable(uint32_t radio_short_mask)
{
NRF_RADIO->SHORTS |= radio_short_mask;
}
__STATIC_INLINE void nrf_radio_shorts_disable(uint32_t radio_short_mask)
{
NRF_RADIO->SHORTS &= ~radio_short_mask;
}
__STATIC_INLINE void nrf_radio_shorts_set(uint32_t radio_short_mask)
{
NRF_RADIO->SHORTS = radio_short_mask;
}
__STATIC_INLINE uint32_t nrf_radio_shorts_get(void)
{
return NRF_RADIO->SHORTS;
}
__STATIC_INLINE nrf_radio_state_t nrf_radio_state_get(void)
{
return (nrf_radio_state_t) NRF_RADIO->STATE;
}
__STATIC_INLINE void nrf_radio_packet_ptr_set(const void *p_radio_packet_ptr)
{
NRF_RADIO->PACKETPTR = (uint32_t) p_radio_packet_ptr;
}
__STATIC_INLINE nrf_radio_crc_status_t nrf_radio_crc_status_get(void)
{
return (nrf_radio_crc_status_t) NRF_RADIO->CRCSTATUS;
}
__STATIC_INLINE void nrf_radio_cca_mode_set(nrf_radio_cca_mode_t radio_cca_mode)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCAMODE_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_mode << RADIO_CCACTRL_CCAMODE_Pos);
}
__STATIC_INLINE void nrf_radio_cca_ed_threshold_set(uint8_t radio_cca_ed_threshold)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCAEDTHRES_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_ed_threshold << RADIO_CCACTRL_CCAEDTHRES_Pos);
}
__STATIC_INLINE void nrf_radio_cca_corr_threshold_set(uint8_t radio_cca_corr_threshold_set)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCACORRTHRES_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_corr_threshold_set << RADIO_CCACTRL_CCACORRTHRES_Pos);
}
__STATIC_INLINE void nrf_radio_cca_corr_counter_set(uint8_t radio_cca_corr_counter_set)
{
NRF_RADIO->CCACTRL &= (~RADIO_CCACTRL_CCACORRCNT_Msk);
NRF_RADIO->CCACTRL |= ((uint32_t) radio_cca_corr_counter_set << RADIO_CCACTRL_CCACORRCNT_Pos);
}
__STATIC_INLINE void nrf_radio_mode_set(nrf_radio_mode_t radio_mode)
{
NRF_RADIO->MODE = ((uint32_t) radio_mode << RADIO_MODE_MODE_Pos);
}
__STATIC_INLINE void nrf_radio_config_length_field_length_set(uint8_t radio_length_length)
{
NRF_RADIO->PCNF0 &= (~RADIO_PCNF0_LFLEN_Msk);
NRF_RADIO->PCNF0 |= ((uint32_t) radio_length_length << RADIO_PCNF0_LFLEN_Pos);
}
__STATIC_INLINE void nrf_radio_config_preamble_length_set(
nrf_radio_preamble_length_t radio_preamble_length)
{
NRF_RADIO->PCNF0 &= (~RADIO_PCNF0_PLEN_Msk);
NRF_RADIO->PCNF0 |= ((uint32_t) radio_preamble_length << RADIO_PCNF0_PLEN_Pos);
}
__STATIC_INLINE void nrf_radio_config_crc_included_set(bool radio_length_contains_crc)
{
NRF_RADIO->PCNF0 &= (~RADIO_PCNF0_CRCINC_Msk);
NRF_RADIO->PCNF0 |= ((uint32_t) radio_length_contains_crc << RADIO_PCNF0_CRCINC_Pos);
}
__STATIC_INLINE void nrf_radio_config_max_length_set(uint8_t radio_max_packet_length)
{
NRF_RADIO->PCNF1 &= (~RADIO_PCNF1_MAXLEN_Msk);
NRF_RADIO->PCNF1 |= ((uint32_t) radio_max_packet_length << RADIO_PCNF1_MAXLEN_Pos);
}
__STATIC_INLINE void nrf_radio_crc_length_set(uint8_t radio_crc_length)
{
NRF_RADIO->CRCCNF &= (~RADIO_CRCCNF_LEN_Msk);
NRF_RADIO->CRCCNF |= ((uint32_t) radio_crc_length << RADIO_CRCCNF_LEN_Pos);
}
__STATIC_INLINE void nrf_radio_crc_includes_address_set(
nrf_radio_crc_includes_addr_t radio_crc_skip_address)
{
NRF_RADIO->CRCCNF &= (~RADIO_CRCCNF_SKIPADDR_Msk);
NRF_RADIO->CRCCNF |= ((uint32_t) radio_crc_skip_address << RADIO_CRCCNF_SKIPADDR_Pos);
}
__STATIC_INLINE void nrf_radio_crc_polynominal_set(uint32_t radio_crc_polynominal)
{
NRF_RADIO->CRCPOLY = (radio_crc_polynominal << RADIO_CRCPOLY_CRCPOLY_Pos);
}
__STATIC_INLINE uint32_t nrf_radio_crc_polynominal_get(void)
{
return (NRF_RADIO->CRCPOLY & RADIO_CRCPOLY_CRCPOLY_Msk) >> RADIO_CRCPOLY_CRCPOLY_Pos;
}
__STATIC_INLINE uint8_t nrf_radio_rssi_sample_get(void)
{
return (uint8_t)(((NRF_RADIO->RSSISAMPLE) & RADIO_RSSISAMPLE_RSSISAMPLE_Msk) >>
RADIO_RSSISAMPLE_RSSISAMPLE_Pos);
}
__STATIC_INLINE void nrf_radio_mhmu_search_pattern_set(uint32_t radio_mhmu_search_pattern)
{
NRF_RADIO->MHRMATCHCONF = radio_mhmu_search_pattern;
}
__STATIC_INLINE void nrf_radio_mhmu_pattern_mask_set(uint32_t radio_mhmu_pattern_mask)
{
NRF_RADIO->MHRMATCHMAS = radio_mhmu_pattern_mask;
}
__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);
}
__STATIC_INLINE void nrf_radio_frequency_set(uint32_t radio_frequency)
{
NRF_RADIO->FREQUENCY = radio_frequency;
}
__STATIC_INLINE uint32_t nrf_radio_frequency_get(void)
{
return NRF_RADIO->FREQUENCY;
}
__STATIC_INLINE void nrf_radio_tx_power_set(int8_t radio_tx_power)
{
NRF_RADIO->TXPOWER = (uint8_t) radio_tx_power;
}
__STATIC_INLINE void nrf_radio_ifs_set(uint32_t radio_ifs)
{
NRF_RADIO->TIFS = radio_ifs;
}
__STATIC_INLINE uint32_t nrf_radio_ifs_get(void)
{
return NRF_RADIO->TIFS & RADIO_TIFS_TIFS_Msk;
}
__STATIC_INLINE void nrf_radio_bcc_set(uint32_t radio_bcc)
{
NRF_RADIO->BCC = radio_bcc;
}
__STATIC_INLINE uint32_t nrf_radio_bcc_get(void)
{
return NRF_RADIO->BCC;
}
__STATIC_INLINE uint8_t nrf_radio_ed_sample_get(void)
{
return (uint8_t) NRF_RADIO->EDSAMPLE;
}
__STATIC_INLINE void nrf_radio_ed_loop_count_set(uint32_t radio_ed_loop_count)
{
NRF_RADIO->EDCNT = (radio_ed_loop_count & 0x001FFFFF);
}
__STATIC_INLINE void nrf_radio_power_set(bool radio_power)
{
NRF_RADIO->POWER = (uint32_t) radio_power;
}
#endif /* SUPPRESS_INLINE_IMPLEMENTATION */
#ifdef __cplusplus
}
#endif
#endif /* NRF_RADIO_H__ */
@@ -0,0 +1,146 @@
/* Copyright (c) 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements ACK timeout procedure for the 802.15.4 driver.
*
*/
#include "nrf_802154_ack_timeout.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_notification.h"
#include "nrf_802154_request.h"
#include "timer_scheduler/nrf_802154_timer_sched.h"
static void timeout_timer_retry(void);
static uint32_t m_timeout = NRF_802154_ACK_TIMEOUT_DEFAULT_TIMEOUT; ///< ACK timeout in us.
static nrf_802154_timer_t m_timer; ///< Timer used to notify when we are waiting too long for ACK.
static volatile bool m_procedure_is_active;
static const uint8_t * mp_frame;
static void notify_tx_error(bool result)
{
if (result)
{
nrf_802154_notify_transmit_failed(mp_frame, NRF_802154_TX_ERROR_NO_ACK);
}
}
static void timeout_timer_fired(void * p_context)
{
(void)p_context;
if (m_procedure_is_active)
{
if (!nrf_802154_request_receive(NRF_802154_TERM_802154,
REQ_ORIG_ACK_TIMEOUT,
notify_tx_error))
{
timeout_timer_retry();
}
}
}
static void timeout_timer_retry(void)
{
/*
* Fire on next timer tick. dt value will be rounded up to nearest timer granularity
* by call to nrf_802154_timer_sched_add this will prevent potential infinite
* recursion when short delays are called from same context as nrf_802154_timer_sched_add.
*/
m_timer.dt++;
nrf_802154_timer_sched_add(&m_timer, true);
}
static void timeout_timer_start(void)
{
m_timer.callback = timeout_timer_fired;
m_timer.p_context = NULL;
m_timer.t0 = nrf_802154_timer_sched_time_get();
m_timer.dt = m_timeout;
m_procedure_is_active = true;
nrf_802154_timer_sched_add(&m_timer, true);
}
static void timeout_timer_stop(void)
{
m_procedure_is_active = false;
}
void nrf_802154_ack_timeout_time_set(uint32_t time)
{
m_timeout = time;
}
bool nrf_802154_ack_timeout_tx_started_hook(const uint8_t * p_frame)
{
mp_frame = p_frame;
timeout_timer_start();
return true;
}
bool nrf_802154_ack_timeout_abort(nrf_802154_term_t term_lvl, req_originator_t req_orig)
{
(void)term_lvl;
if (req_orig != REQ_ORIG_ACK_TIMEOUT)
{
timeout_timer_stop();
}
return true;
}
void nrf_802154_ack_timeout_transmitted_hook(const uint8_t * p_frame)
{
assert((p_frame == mp_frame) || (!m_procedure_is_active));
timeout_timer_stop();
}
bool nrf_802154_ack_timeout_tx_failed_hook(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
(void)error;
assert((p_frame == mp_frame) || (!m_procedure_is_active));
timeout_timer_stop();
return true;
}
@@ -0,0 +1,103 @@
/* Copyright (c) 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_802154_ACK_TIMEOUT_H__
#define NRF_802154_ACK_TIMEOUT_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_const.h"
#include "nrf_802154_types.h"
/**
* @defgroup nrf_802154_csma_ca 802.15.4 driver ACK timeout support
* @{
* @ingroup nrf_802154
* @brief ACK timeout feature.
*/
/**
* @brief Set timeout time for ACK timeout feature.
*
* @param[in] time Timeout time in us. Timeout is started at the beginning of frame
* transmission (after transmission of PHR).
* Default value is defined in nrf_802154_config.h.
*/
void nrf_802154_ack_timeout_time_set(uint32_t time);
/**
* @brief Abort started ACK timeout procedure.
*
* @param[in] term_lvl Termination level set by request aborting ongoing operation.
* @param[in] req_orig Module that originates this request.
*
* If ACK timeout procedure is not running during call, this function does nothing.
*
* @retval true ACK timeout procedure han been stopped.
*/
bool nrf_802154_ack_timeout_abort(nrf_802154_term_t term_lvl, req_originator_t req_orig);
/**
* @brief Handler of transmitted event.
*
* @param[in] p_frame Pointer to the buffer containing transmitted frame.
*/
void nrf_802154_ack_timeout_transmitted_hook(const uint8_t * p_frame);
/**
* @brief Handler of TX failed event.
*
* @param[in] p_frame Pointer to the buffer containing frame that was not transmitted.
* @param[in] error Cause of failed transmission.
*
* @retval true TX failed event should be propagated to the MAC layer.
* @retval false TX failed event should not be propagated to the MAC layer. It is handled
* internally.
*/
bool nrf_802154_ack_timeout_tx_failed_hook(const uint8_t * p_frame, nrf_802154_tx_error_t error);
/**
* @brief Handler of TX started event.
*
* @param[in] p_frame Pointer to the buffer containing frame being transmitted.
*
* @retval true TX started event should be propagated to the MAC layer.
* @retval false TX started event should not be propagated to the MAC layer. It is handled
* internally.
*/
bool nrf_802154_ack_timeout_tx_started_hook(const uint8_t * p_frame);
/**
*@}
**/
#endif // NRF_802154_CSMA_CA_H__
@@ -0,0 +1,234 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements CSMA-CA procedure for the 802.15.4 driver.
*
*/
#include "nrf_802154_csma_ca.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "nrf_802154_config.h"
#include "nrf_802154_const.h"
#include "nrf_802154_notification.h"
#include "nrf_802154_request.h"
#include "timer_scheduler/nrf_802154_timer_sched.h"
static uint8_t m_nb; ///< The number of times the CSMA-CA algorithm was required to back off while attempting the current transmission.
static uint8_t m_be; ///< Backoff exponent, which is related to how many backoff periods a device shall wait before attempting to assess a channel.
static const uint8_t * mp_psdu; ///< Pointer to PSDU of the frame being transmitted.
static nrf_802154_timer_t m_timer; ///< Timer used to back off during CSMA-CA procedure.
static bool m_is_running; ///< Indicates if CSMA-CA procedure is running.
/**
* @brief Perform appropriate actions for busy channel conditions.
*
* According to CSMA-CA description in 802.15.4 specification, when channel is busy NB and BE shall
* be incremented and the device shall wait random delay before next CCA procedure. If NB reaches
* macMaxCsmaBackoffs procedure fails.
*
* @retval true Procedure failed and TX failure should be notified to the next higher layer.
* @retval false Procedure is still ongoing and TX failure should be handled internally.
*/
static bool channel_busy(void);
/**
* @brief Check if CSMA-CA is ongoing.
*
* @retval true CSMA-CA is running.
* @retval false CSMA-CA is not running currently.
*/
static bool procedure_is_running(void)
{
return m_is_running;
}
/**
* @brief Stop CSMA-CA procedure.
*/
static void procedure_stop(void)
{
m_is_running = false;
}
/**
* Notify MAC layer that channel is busy if tx request failed and there are no retries left.
*
* @param[in] result Result of TX request.
*/
static void notify_busy_channel(bool result)
{
if (!result && (m_nb >= (NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS - 1)))
{
nrf_802154_notify_transmit_failed(mp_psdu, NRF_802154_TX_ERROR_BUSY_CHANNEL);
}
}
/**
* @brief Perform CCA procedure followed by frame transmission.
*
* If transmission is requested, CSMA-CA module waits for notification from the FSM module.
* If transmission request fails, CSMA-CA module performs procedure for busy channel condition
* @sa channel_busy().
*
* @param[in] p_context Unused variable passed from the Timer Scheduler module.
*/
static void frame_transmit(void * p_context)
{
(void)p_context;
if (!procedure_is_running())
{
return;
}
if (!nrf_802154_request_transmit(NRF_802154_TERM_NONE,
REQ_ORIG_CSMA_CA,
mp_psdu,
true,
notify_busy_channel))
{
(void)channel_busy();
}
}
/**
* @brief Delay CCA procedure for random (2^BE - 1) unit backoff periods.
*/
static void random_backoff_start(void)
{
uint8_t backoff_periods = rand() % (1 << m_be);
m_timer.callback = frame_transmit;
m_timer.p_context = NULL;
m_timer.t0 = nrf_802154_timer_sched_time_get();
m_timer.dt = backoff_periods * UNIT_BACKOFF_PERIOD;
nrf_802154_timer_sched_add(&m_timer, false);
}
static bool channel_busy(void)
{
bool result = true;
if (procedure_is_running())
{
m_nb++;
if (m_be < NRF_802154_CSMA_CA_MAX_BE)
{
m_be++;
}
if (m_nb < NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS)
{
random_backoff_start();
result = false;
}
else
{
procedure_stop();
}
}
return result;
}
void nrf_802154_csma_ca_start(const uint8_t * p_data)
{
assert(!procedure_is_running());
mp_psdu = p_data;
m_nb = 0;
m_be = NRF_802154_CSMA_CA_MIN_BE;
m_is_running = true;
random_backoff_start();
}
bool nrf_802154_csma_ca_abort(nrf_802154_term_t term_lvl, req_originator_t req_orig)
{
// Don't stop CSMA-CA if request by itself or RAAL.
if (req_orig == REQ_ORIG_CSMA_CA ||
req_orig == REQ_ORIG_RAAL)
{
return true;
}
// Stop CSMA-CA if termination level is high enough.
if (term_lvl >= NRF_802154_TERM_802154)
{
nrf_802154_timer_sched_remove(&m_timer);
procedure_stop();
return true;
}
// Return success in case procedure is already stopped.
if (!procedure_is_running())
{
return true;
}
return false;
}
bool nrf_802154_csma_ca_tx_failed_hook(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
(void)error;
bool result = true;
if (p_frame == mp_psdu)
{
result = channel_busy();
}
return result;
}
bool nrf_802154_csma_ca_tx_started_hook(const uint8_t * p_frame)
{
if (p_frame == mp_psdu)
{
assert(!nrf_802154_timer_sched_is_running(&m_timer));
procedure_stop();
}
return true;
}
@@ -0,0 +1,105 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_802154_CSMA_CA_H__
#define NRF_802154_CSMA_CA_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_const.h"
#include "nrf_802154_types.h"
/**
* @defgroup nrf_802154_csma_ca 802.15.4 driver CSMA-CA support
* @{
* @ingroup nrf_802154
* @brief CSMA-CA procedure.
*/
/**
* @brief Start CSMA-CA procedure for transmission of given frame.
*
* If CSMA-CA procedure is successful and frame is transmitted @sa nrf_802154_tx_started()
* function is called. If CSMA/CA procedure failed and frame cannot be transmitted due to busy
* channel @sa nrf_802154_transmit_failed() function is called.
*
* @note CSMA-CA does not timeout waiting for ACK automatically. Waiting for ACK shall be timed out
* by the next layer. ACK timeout timer shall start when @sa nrf_802154_tx_started()
* function is called.
*
* @param[in] p_data Pointer to PSDU of frame that should be transmitted.
*/
void nrf_802154_csma_ca_start(const uint8_t * p_data);
/**
* @brief Abort ongoing CSMA-CA procedure.
*
* @note This function shall not be called during @sa nrf_802154_csma_ca_start execution
* (i.e. from ISR with higher priority). It would result with unrecoverable runtime error.
*
* If CSMA-CA is not running during call, this function does nothing and returns true.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @retval true CSMA-CA procedure is not running anymore.
* @retval false CSMA-CA cannot be stopped due to too low termination level.
*/
bool nrf_802154_csma_ca_abort(nrf_802154_term_t term_lvl, req_originator_t req_orig);
/**
* @brief Handler of TX failed event.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that was not transmitted.
* @param[in] error Cause of failed transmission.
*
* @retval true TX failed event should be propagated to the MAC layer.
* @retval false TX failed event should not be propagated to the MAC layer. It is handled
* internally.
*/
bool nrf_802154_csma_ca_tx_failed_hook(const uint8_t * p_frame, nrf_802154_tx_error_t error);
/**
* @brief Handler of TX started event.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that is being transmitted.
*
* @retval true TX started event should be propagated to the MAC layer.
* @retval false TX started event should not be propagated to the MAC layer. It is handled
* internally.
*/
bool nrf_802154_csma_ca_tx_started_hook(const uint8_t * p_frame);
/**
*@}
**/
#endif // NRF_802154_CSMA_CA_H__
@@ -0,0 +1,433 @@
/* Copyright (c) 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements incoming frame filtering according to 3 and 4 levels of filtering.
*
* Filtering details are specified in 802.15.4-2015: 6.7.2.
* 1st and 2nd filtering level is performed by FSM module depending on promiscuous mode, when FCS is
* received.
*/
#include "nrf_802154_filter.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_802154_const.h"
#include "nrf_802154_pib.h"
#define FCF_CHECK_OFFSET (PHR_SIZE + FCF_SIZE)
#define SHORT_ADDR_CHECK_OFFSET (DEST_ADDR_OFFSET + SHORT_ADDRESS_SIZE)
#define EXTENDED_ADDR_CHECK_OFFSET (DEST_ADDR_OFFSET + EXTENDED_ADDRESS_SIZE)
/**
* @brief Check if given frame version is allowed for given frame type.
*
* @param[in] frame_type Type of incoming frame.
* @param[in] frame_version Version of incoming frame.
*
* @retval true Given frame version is allowed for given frame type.
* @retval false Given frame version is not allowed for given frame type.
*/
static bool frame_type_and_version_filter(uint8_t frame_type, uint8_t frame_version)
{
bool result;
switch (frame_type)
{
case FRAME_TYPE_BEACON:
case FRAME_TYPE_DATA:
case FRAME_TYPE_ACK:
case FRAME_TYPE_COMMAND:
result = (frame_version != FRAME_VERSION_3);
break;
case FRAME_TYPE_MULTIPURPOSE:
result = (frame_version == FRAME_VERSION_0);
break;
case FRAME_TYPE_FRAGMENT:
case FRAME_TYPE_EXTENDED:
result = true;
break;
default:
result = false;
}
return result;
}
/**
* @brief Check if given frame type may include destination address fields.
*
* @note Actual presence of destination address fields in the frame is indicated by FCF.
*
* @param[in] frame_type Type of incoming frame.
*
* @retval true Given frame type may include addressing fields.
* @retval false Given frame type may not include addressing fields.
*/
static bool dst_addressing_may_be_present(uint8_t frame_type)
{
bool result;
switch (frame_type)
{
case FRAME_TYPE_BEACON:
case FRAME_TYPE_DATA:
case FRAME_TYPE_ACK:
case FRAME_TYPE_COMMAND:
case FRAME_TYPE_MULTIPURPOSE:
result = true;
break;
case FRAME_TYPE_FRAGMENT:
case FRAME_TYPE_EXTENDED:
result = false;
break;
default:
result = false;
}
return result;
}
/**
* @brief Get offset of end of addressing fields for given frame assuming its version is 2006.
*
* If given frame contains errors that prevent getting offset, this function returns false. If there
* are no destination address fields in given frame, this function returns true and does not modify
* @p p_num_bytes. If there is destination address in given frame, this function returns true and
* inserts offset of addressing fields end to @p p_num_bytes.
*
* @param[in] p_psdu Pointer of PSDU of incoming frame.
* @param[out] p_num_bytes Offset of addressing fields end.
* @param[in] frame_type Type of incoming frame.
*
* @retval true No errors in given frame were detected - it may be further processed.
* @retval false Detected an error in given frame - it should be discarded.
*/
static bool dst_addressing_end_offset_get_2006(const uint8_t * p_psdu,
uint8_t * p_num_bytes,
uint8_t frame_type)
{
bool result;
switch (p_psdu[DEST_ADDR_TYPE_OFFSET] & DEST_ADDR_TYPE_MASK)
{
case DEST_ADDR_TYPE_SHORT:
*p_num_bytes = SHORT_ADDR_CHECK_OFFSET;
result = true;
break;
case DEST_ADDR_TYPE_EXTENDED:
*p_num_bytes = EXTENDED_ADDR_CHECK_OFFSET;
result = true;
break;
case DEST_ADDR_TYPE_NONE:
if (frame_type == FRAME_TYPE_BEACON)
{
switch (p_psdu[SRC_ADDR_TYPE_OFFSET] & SRC_ADDR_TYPE_MASK)
{
case SRC_ADDR_TYPE_SHORT:
*p_num_bytes = SHORT_ADDR_CHECK_OFFSET;
result = true;
break;
case SRC_ADDR_TYPE_EXTENDED:
*p_num_bytes = EXTENDED_ADDR_CHECK_OFFSET;
result = true;
break;
default:
result = false;
}
}
else
{
result = true;
}
break;
default:
result = false;
}
return result;
}
/**
* @brief Get offset of end of addressing fields for given frame assuming its version is 2015.
*
* If given frame contains errors that prevent getting offset, this function returns false. If there
* are no destination address fields in given frame, this function returns true and does not modify
* @p p_num_bytes. If there is destination address in given frame, this function returns true and
* inserts offset of addressing fields end to @p p_num_bytes.
*
* @param[in] p_psdu Pointer of PSDU of incoming frame.
* @param[out] p_num_bytes Offset of addressing fields end.
* @param[in] frame_type Type of incoming frame.
*
* @retval true No errors in given frame were detected - it may be further processed.
* @retval false Detected an error in given frame - it should be discarded.
*/
static bool dst_addressing_end_offset_get_2015(const uint8_t * p_psdu,
uint8_t * p_num_bytes,
uint8_t frame_type)
{
bool result = false;
switch (frame_type)
{
case FRAME_TYPE_BEACON:
case FRAME_TYPE_DATA:
case FRAME_TYPE_ACK:
case FRAME_TYPE_COMMAND:
// TODO: Implement dst addressing filtering according to 2015 spec
result = dst_addressing_end_offset_get_2006(p_psdu, p_num_bytes, frame_type);
break;
case FRAME_TYPE_MULTIPURPOSE:
// TODO: Implement dst addressing filtering according to 2015 spec
result = false;
break;
case FRAME_TYPE_FRAGMENT:
case FRAME_TYPE_EXTENDED:
// No addressing data
result = true;
break;
}
return result;
}
/**
* @brief Get offset of end of addressing fields for given frame.
*
* If given frame contains errors that prevent getting offset, this function returns false. If there
* are no destination address fields in given frame, this function returns true and does not modify
* @p p_num_bytes. If there is destination address in given frame, this function returns true and
* inserts offset of addressing fields end to @p p_num_bytes.
*
* @param[in] p_psdu Pointer of PSDU of incoming frame.
* @param[out] p_num_bytes Offset of addressing fields end.
* @param[in] frame_type Type of incoming frame.
*
* @retval true No errors in given frame were detected - it may be further processed.
* @retval false Detected an error in given frame - it should be discarded.
*/
static bool dst_addressing_end_offset_get(const uint8_t * p_psdu,
uint8_t * p_num_bytes,
uint8_t frame_type,
uint8_t frame_version)
{
bool result;
switch (frame_version)
{
case FRAME_VERSION_0:
case FRAME_VERSION_1:
result = dst_addressing_end_offset_get_2006(p_psdu, p_num_bytes, frame_type);
break;
case FRAME_VERSION_2:
result = dst_addressing_end_offset_get_2015(p_psdu, p_num_bytes, frame_type);
break;
default:
result = false;
}
return result;
}
/**
* Verify if destination PAN Id of incoming frame allows processing by this node.
*
* @param[in] p_psdu Pointer of PSDU of incoming frame.
*
* @retval true PAN Id of incoming frame allows further processing of the frame.
* @retval false PAN Id of incoming frame does not allow further processing.
*/
static bool dst_pan_id_check(const uint8_t * p_psdu)
{
bool result;
if ((0 == memcmp(&p_psdu[PAN_ID_OFFSET], nrf_802154_pib_pan_id_get(), PAN_ID_SIZE)) ||
(0 == memcmp(&p_psdu[PAN_ID_OFFSET], BROADCAST_ADDRESS, PAN_ID_SIZE)))
{
result = true;
}
else if ((FRAME_TYPE_BEACON == (p_psdu[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK)) &&
(0 == memcmp(nrf_802154_pib_pan_id_get(), BROADCAST_ADDRESS, PAN_ID_SIZE)))
{
result = true;
}
else
{
result = false;
}
return result;
}
/**
* Verify if destination short address of incoming frame allows processing by this node.
*
* @param[in] p_psdu Pointer of PSDU of incoming frame.
*
* @retval true Destination address of incoming frame allows further processing of the frame.
* @retval false Destination address of incoming frame does not allow further processing.
*/
static bool dst_short_addr_check(const uint8_t * p_psdu)
{
bool result;
if ((0 == memcmp(&p_psdu[DEST_ADDR_OFFSET],
nrf_802154_pib_short_address_get(),
SHORT_ADDRESS_SIZE)) ||
(0 == memcmp(&p_psdu[DEST_ADDR_OFFSET], BROADCAST_ADDRESS, SHORT_ADDRESS_SIZE)))
{
result = true;
}
else if (FRAME_TYPE_BEACON == (p_psdu[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK))
{
result = true;
}
else
{
result = false;
}
return result;
}
/**
* Verify if destination extended address of incoming frame allows processing by this node.
*
* @param[in] p_psdu Pointer of PSDU of incoming frame.
*
* @retval true Destination address of incoming frame allows further processing of the frame.
* @retval false Destination address of incoming frame does not allow further processing.
*/
static bool dst_extended_addr_check(const uint8_t *p_psdu)
{
bool result;
if (0 == memcmp(&p_psdu[DEST_ADDR_OFFSET],
nrf_802154_pib_extended_address_get(),
EXTENDED_ADDRESS_SIZE))
{
result = true;
}
else if (FRAME_TYPE_BEACON == (p_psdu[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK))
{
result = true;
}
else
{
result = false;
}
return result;
}
nrf_802154_rx_error_t nrf_802154_filter_frame_part(const uint8_t * p_psdu, uint8_t * p_num_bytes)
{
nrf_802154_rx_error_t result;
switch (*p_num_bytes)
{
case FCF_CHECK_OFFSET:
{
if (p_psdu[0] < ACK_LENGTH || p_psdu[0] > MAX_PACKET_SIZE)
{
// Frame length is invalid
result = NRF_802154_RX_ERROR_INVALID_FRAME;
break;
}
uint8_t frame_type = p_psdu[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK;
uint8_t frame_version = p_psdu[FRAME_VERSION_OFFSET] & FRAME_VERSION_MASK;
if (!frame_type_and_version_filter(frame_type, frame_version))
{
result = NRF_802154_RX_ERROR_INVALID_FRAME;
break;
}
if (!dst_addressing_may_be_present(frame_type))
{
result = NRF_802154_RX_ERROR_NONE;
break;
}
result = dst_addressing_end_offset_get(p_psdu, p_num_bytes, frame_type, frame_version) ?
NRF_802154_RX_ERROR_NONE : NRF_802154_RX_ERROR_INVALID_FRAME;
break;
}
case SHORT_ADDR_CHECK_OFFSET:
if (!dst_pan_id_check(p_psdu))
{
result = NRF_802154_RX_ERROR_INVALID_DEST_ADDR;
break;
}
result = dst_short_addr_check(p_psdu) ? NRF_802154_RX_ERROR_NONE :
NRF_802154_RX_ERROR_INVALID_DEST_ADDR;
break;
case EXTENDED_ADDR_CHECK_OFFSET:
if (!dst_pan_id_check(p_psdu))
{
result = NRF_802154_RX_ERROR_INVALID_DEST_ADDR;
break;
}
result = dst_extended_addr_check(p_psdu) ? NRF_802154_RX_ERROR_NONE :
NRF_802154_RX_ERROR_INVALID_DEST_ADDR;
break;
default:
assert(false);
}
return result;
}
@@ -0,0 +1,78 @@
/* Copyright (c) 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @brief This file implements incoming frame filter API.
*
*/
#ifndef NRF_802154_FILTER_H_
#define NRF_802154_FILTER_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_types.h"
/**
* @defgroup nrf_802154_filter Incoming frame filter API.
* @{
* @ingroup nrf_802154
* @brief Procedures used to discard incoming frames that contain unexpected data in PHR or MHR.
*/
/**
* @brief Verify if given part of the frame is valid.
*
* This function is called a few times for each received frame. First call is after FCF is received
* (PSDU length is 1 - @p p_num_bytes value is 1). Subsequent calls are performed when number of
* bytes requested by previous call is available. Iteration ends when function does not request
* any more bytes to check.
* If verified part of the function is correct this function returns true and sets @p p_num_bytes to
* number of bytes that should be available in PSDU during next iteration. If frame is correct and
* there is nothing more to check, function returns true and does not modify @p p_num_bytes value.
* If verified frame is incorrect this function returns false and @p p_num_bytes value is undefined.
*
* @param[in] p_psdu Pointer to PSDU of incoming frame.
* @param[inout] p_num_bytes Number of bytes available in @p p_psdu buffer. This value is set to
* requested number of bytes for next iteration or this value is
* unchanged if no more iterations shall be performed during filtering of
* given frame.
*
* @retval NRF_802154_RX_ERROR_NONE Verified part of the incoming frame is valid.
* @retval NRF_802154_RX_ERROR_INVALID_FRAME Verified part of the incoming frame is invalid.
* @retval NRF_802154_RX_ERROR_INVALID_DEST_ADDR Incoming frame has destination address that
* mismatches address of this node.
*/
nrf_802154_rx_error_t nrf_802154_filter_frame_part(const uint8_t * p_psdu, uint8_t * p_num_bytes);
#endif /* NRF_802154_FILTER_H_ */
@@ -0,0 +1,686 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements the nrf 802.15.4 radio driver.
*
*/
#include "nrf_802154.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "nrf_802154_ack_pending_bit.h"
#include "nrf_802154_config.h"
#include "nrf_802154_const.h"
#include "nrf_802154_core.h"
#include "nrf_802154_critical_section.h"
#include "nrf_802154_debug.h"
#include "nrf_802154_notification.h"
#include "nrf_802154_pib.h"
#include "nrf_802154_priority_drop.h"
#include "nrf_802154_request.h"
#include "nrf_802154_revision.h"
#include "nrf_802154_rx_buffer.h"
#include "hal/nrf_radio.h"
#include "platform/clock/nrf_802154_clock.h"
#include "platform/timer/nrf_802154_timer.h"
#include "raal/nrf_raal_api.h"
#include "timer_scheduler/nrf_802154_timer_sched.h"
#include "mac_features/nrf_802154_csma_ca.h"
#include "mac_features/nrf_802154_ack_timeout.h"
#if ENABLE_FEM
#include "fem/nrf_fem_control_api.h"
#endif
#define RAW_LENGTH_OFFSET 0
#define RAW_PAYLOAD_OFFSET 1
#if !NRF_802154_USE_RAW_API
/** Static transmit buffer used by @sa nrf_802154_transmit() family of functions.
*
* If none of functions using this buffer is called and link time optimization is enabled, this
* buffer should be removed by linker.
*/
static uint8_t m_tx_buffer[RAW_PAYLOAD_OFFSET + MAX_PACKET_SIZE];
/**
* @brief Fill transmit buffer with given data.
*
* @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).
*/
static void tx_buffer_fill(const uint8_t * p_data, uint8_t length)
{
assert(length <= MAX_PACKET_SIZE - FCS_SIZE);
m_tx_buffer[RAW_LENGTH_OFFSET] = length + FCS_SIZE;
memcpy(&m_tx_buffer[RAW_PAYLOAD_OFFSET], p_data, length);
}
#endif // !NRF_802154_USE_RAW_API
void nrf_802154_channel_set(uint8_t channel)
{
bool changed = nrf_802154_pib_channel_get() != channel;
nrf_802154_pib_channel_set(channel);
if (changed)
{
nrf_802154_request_channel_update();
}
}
uint8_t nrf_802154_channel_get(void)
{
return nrf_802154_pib_channel_get();
}
void nrf_802154_tx_power_set(int8_t power)
{
nrf_802154_pib_tx_power_set(power);
}
int8_t nrf_802154_tx_power_get(void)
{
return nrf_802154_pib_tx_power_get();
}
void nrf_802154_pan_id_set(const uint8_t * p_pan_id)
{
nrf_802154_pib_pan_id_set(p_pan_id);
}
void nrf_802154_extended_address_set(const uint8_t * p_extended_address)
{
nrf_802154_pib_extended_address_set(p_extended_address);
}
void nrf_802154_short_address_set(const uint8_t * p_short_address)
{
nrf_802154_pib_short_address_set(p_short_address);
}
int8_t nrf_802154_dbm_from_energy_level_calculate(uint8_t energy_level)
{
return ED_MIN_DBM + (energy_level / ED_RESULT_FACTOR);
}
uint32_t nrf_802154_first_symbol_timestamp_get(uint32_t end_timestamp, uint8_t psdu_length)
{
uint32_t frame_symbols = PHY_SHR_DURATION;
frame_symbols += (PHR_SIZE + psdu_length) * PHY_SYMBOLS_PER_OCTET;
return end_timestamp - (frame_symbols * PHY_US_PER_SYMBOL);
}
void nrf_802154_init(void)
{
nrf_802154_ack_pending_bit_init();
nrf_802154_core_init();
nrf_802154_clock_init();
nrf_802154_critical_section_init();
nrf_802154_debug_init();
nrf_802154_notification_init();
nrf_802154_pib_init();
nrf_802154_priority_drop_init();
nrf_802154_request_init();
nrf_802154_revision_init();
nrf_802154_rx_buffer_init();
nrf_802154_timer_init();
nrf_raal_init();
}
void nrf_802154_deinit(void)
{
nrf_802154_timer_deinit();
nrf_802154_clock_deinit();
nrf_802154_core_deinit();
}
#if !NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
void nrf_802154_radio_irq_handler(void)
{
nrf_802154_core_irq_handler();
}
#endif // !NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
#if ENABLE_FEM
void nrf_802154_fem_control_cfg_set(const nrf_802154_fem_control_cfg_t * p_cfg)
{
nrf_fem_control_cfg_set(p_cfg);
}
void nrf_802154_fem_control_cfg_get(nrf_802154_fem_control_cfg_t * p_cfg)
{
nrf_fem_control_cfg_get(p_cfg);
}
#endif // ENABLE_FEM
nrf_802154_state_t nrf_802154_state_get(void)
{
switch (nrf_802154_core_state_get())
{
case RADIO_STATE_SLEEP:
case RADIO_STATE_FALLING_ASLEEP:
return NRF_802154_STATE_SLEEP;
case RADIO_STATE_RX:
case RADIO_STATE_TX_ACK:
return NRF_802154_STATE_RECEIVE;
case RADIO_STATE_CCA_TX:
case RADIO_STATE_TX:
case RADIO_STATE_RX_ACK:
return NRF_802154_STATE_TRANSMIT;
case RADIO_STATE_ED:
return NRF_802154_STATE_ENERGY_DETECTION;
case RADIO_STATE_CCA:
return NRF_802154_STATE_CCA;
case RADIO_STATE_CONTINUOUS_CARRIER:
return NRF_802154_STATE_CONTINUOUS_CARRIER;
}
return NRF_802154_STATE_INVALID;
}
bool nrf_802154_sleep(void)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_SLEEP);
result = nrf_802154_request_sleep(NRF_802154_TERM_802154);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_SLEEP);
return result;
}
bool nrf_802154_receive(void)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RECEIVE);
result = nrf_802154_request_receive(NRF_802154_TERM_802154, REQ_ORIG_HIGHER_LAYER, NULL);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RECEIVE);
return result;
}
#if NRF_802154_USE_RAW_API
bool nrf_802154_transmit_raw(const uint8_t * p_data, bool cca)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_TRANSMIT);
result = nrf_802154_request_transmit(NRF_802154_TERM_NONE,
REQ_ORIG_HIGHER_LAYER,
p_data,
cca,
NULL);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_TRANSMIT);
return result;
}
#else // NRF_802154_USE_RAW_API
bool nrf_802154_transmit(const uint8_t * p_data, uint8_t length, bool cca)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_TRANSMIT);
tx_buffer_fill(p_data, length);
result = nrf_802154_request_transmit(NRF_802154_TERM_NONE,
REQ_ORIG_HIGHER_LAYER,
m_tx_buffer,
cca,
NULL);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_TRANSMIT);
return result;
}
#endif // NRF_802154_USE_RAW_API
bool nrf_802154_energy_detection(uint32_t time_us)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_ENERGY_DETECTION);
result = nrf_802154_request_energy_detection(NRF_802154_TERM_NONE, time_us);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_ENERGY_DETECTION);
return result;
}
bool nrf_802154_cca(void)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_CCA);
result = nrf_802154_request_cca(NRF_802154_TERM_NONE);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_CCA);
return result;
}
bool nrf_802154_continuous_carrier(void)
{
bool result;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_CONTINUOUS_CARRIER);
result = nrf_802154_request_continuous_carrier(NRF_802154_TERM_NONE);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_CONTINUOUS_CARRIER);
return result;
}
#if NRF_802154_USE_RAW_API
void nrf_802154_buffer_free_raw(uint8_t * p_data)
{
bool result;
rx_buffer_t * p_buffer = (rx_buffer_t *)p_data;
assert(p_buffer->free == false);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_BUFFER_FREE);
result = nrf_802154_request_buffer_free(p_data);
assert(result);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_BUFFER_FREE);
}
#else // NRF_802154_USE_RAW_API
void nrf_802154_buffer_free(uint8_t * p_data)
{
bool result;
rx_buffer_t * p_buffer = (rx_buffer_t *)(p_data - RAW_PAYLOAD_OFFSET);
assert(p_buffer->free == false);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_BUFFER_FREE);
result = nrf_802154_request_buffer_free(p_data - RAW_PAYLOAD_OFFSET);
assert(result);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_BUFFER_FREE);
}
#endif // NRF_802154_USE_RAW_API
int8_t nrf_802154_rssi_last_get(void)
{
uint8_t minus_dbm = nrf_radio_rssi_sample_get();
return - (int8_t)minus_dbm;
}
int8_t nrf_802154_rssi_corrected_get(int8_t rssi, int8_t temp)
{
if (temp <= -30)
{
return rssi + 3;
}
if (temp <= -10)
{
return rssi + 2;
}
if (temp <= 10)
{
return rssi + 1;
}
if (temp <= 30)
{
return rssi;
}
if (temp <= 50)
{
return rssi - 1;
}
if (temp <= 70)
{
return rssi - 2;
}
return rssi - 3;
}
bool nrf_802154_promiscuous_get(void)
{
return nrf_802154_pib_promiscuous_get();
}
void nrf_802154_promiscuous_set(bool enabled)
{
nrf_802154_pib_promiscuous_set(enabled);
}
void nrf_802154_auto_ack_set(bool enabled)
{
nrf_802154_pib_auto_ack_set(enabled);
}
bool nrf_802154_auto_ack_get(void)
{
return nrf_802154_pib_auto_ack_get();
}
void nrf_802154_auto_pending_bit_set(bool enabled)
{
nrf_802154_ack_pending_bit_set(enabled);
}
bool nrf_802154_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended)
{
return nrf_802154_ack_pending_bit_for_addr_set(p_addr, extended);
}
bool nrf_802154_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended)
{
return nrf_802154_ack_pending_bit_for_addr_clear(p_addr, extended);
}
void nrf_802154_pending_bit_for_addr_reset(bool extended)
{
nrf_802154_ack_pending_bit_for_addr_reset(extended);
}
void nrf_802154_cca_cfg_set(const nrf_802154_cca_cfg_t * p_cca_cfg)
{
nrf_802154_pib_cca_cfg_set(p_cca_cfg);
nrf_802154_request_cca_cfg_update();
}
void nrf_802154_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg)
{
nrf_802154_pib_cca_cfg_get(p_cca_cfg);
}
#if NRF_802154_CSMA_CA_ENABLED
#if NRF_802154_USE_RAW_API
void nrf_802154_transmit_csma_ca_raw(const uint8_t * p_data)
{
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_CSMACA);
nrf_802154_csma_ca_start(p_data);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_CSMACA);
}
#else // NRF_802154_USE_RAW_API
void nrf_802154_transmit_csma_ca(const uint8_t * p_data, uint8_t length)
{
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_CSMACA);
tx_buffer_fill(p_data, length);
nrf_802154_csma_ca_start(m_tx_buffer);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_CSMACA);
}
#endif // NRF_802154_USE_RAW_API
#endif // NRF_802154_CSMA_CA_ENABLED
#if NRF_802154_ACK_TIMEOUT_ENABLED
void nrf_802154_ack_timeout_set(uint32_t time)
{
nrf_802154_ack_timeout_time_set(time);
}
#endif // NRF_802154_ACK_TIMEOUT_ENABLED
__WEAK void nrf_802154_tx_ack_started(void)
{
// Intentionally empty
}
#if NRF_802154_USE_RAW_API
__WEAK void nrf_802154_received_raw(uint8_t * p_data, int8_t power, uint8_t lqi)
{
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
uint32_t timestamp = nrf_802154_timer_sched_time_get();
nrf_802154_received_timestamp_raw(p_data, power, lqi, timestamp);
#else // NRF_802154_FRAME_TIMESTAMP_ENABLED
nrf_802154_buffer_free_raw(p_data);
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
}
#else // NRF_802154_USE_RAW_API
__WEAK void nrf_802154_received(uint8_t * p_data, uint8_t length, int8_t power, uint8_t lqi)
{
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
uint32_t timestamp = nrf_802154_timer_sched_time_get();
nrf_802154_received_timestamp(p_data, length, power, lqi, timestamp);
#else // NRF_802154_FRAME_TIMESTAMP_ENABLED
(void)length;
(void)power;
(void)lqi;
nrf_802154_buffer_free(p_data);
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
}
#endif // !NRF_802154_USE_RAW_API
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
#if NRF_802154_USE_RAW_API
__WEAK void nrf_802154_received_timestamp_raw(uint8_t * p_data,
int8_t power,
uint8_t lqi,
uint32_t time)
{
(void)power;
(void)lqi;
(void)time;
nrf_802154_buffer_free_raw(p_data);
}
#else // NRF_802154_USE_RAW_API
__WEAK void nrf_802154_received_timestamp(uint8_t * p_data,
uint8_t length,
int8_t power,
uint8_t lqi,
uint32_t time)
{
(void)length;
(void)power;
(void)lqi;
(void)time;
nrf_802154_buffer_free(p_data);
}
#endif // NRF_802154_USE_RAW_API
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
__WEAK void nrf_802154_receive_failed(nrf_802154_rx_error_t error)
{
(void)error;
}
__WEAK void nrf_802154_tx_started(const uint8_t * p_frame)
{
(void)p_frame;
}
#if NRF_802154_USE_RAW_API
__WEAK void nrf_802154_transmitted_raw(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
uint8_t lqi)
{
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
uint32_t timestamp = (p_ack == NULL) ? 0 : nrf_802154_timer_sched_time_get();
nrf_802154_transmitted_timestamp_raw(p_frame, p_ack, power, lqi, timestamp);
#else // NRF_802154_FRAME_TIMESTAMP_ENABLED
(void)p_frame;
(void)power;
(void)lqi;
if (p_ack != NULL)
{
nrf_802154_buffer_free_raw(p_ack);
}
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
}
#else // NRF_802154_USE_RAW_API
__WEAK void nrf_802154_transmitted(const uint8_t * p_frame,
uint8_t * p_ack,
uint8_t length,
int8_t power,
uint8_t lqi)
{
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
uint32_t timestamp = (p_ack == NULL) ? 0 : nrf_802154_timer_sched_time_get();
nrf_802154_transmitted_timestamp(p_frame, p_ack, length, power, lqi, timestamp);
#else // NRF_802154_FRAME_TIMESTAMP_ENABLED
(void)p_frame;
(void)length;
(void)power;
(void)lqi;
if (p_ack != NULL)
{
nrf_802154_buffer_free(p_ack);
}
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
}
#endif // NRF_802154_USE_RAW_API
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
#if NRF_802154_USE_RAW_API
__WEAK void nrf_802154_transmitted_timestamp_raw(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
uint8_t lqi,
uint32_t time)
{
(void)p_frame;
(void)power;
(void)lqi;
(void)time;
if (p_ack != NULL)
{
nrf_802154_buffer_free_raw(p_ack);
}
}
#else // NRF_802154_USE_RAW_API
__WEAK void nrf_802154_transmitted_timestamp(const uint8_t * p_frame,
uint8_t * p_ack,
uint8_t length,
int8_t power,
uint8_t lqi,
uint32_t time)
{
(void)p_frame;
(void)length;
(void)power;
(void)lqi;
(void)time;
if (p_ack != NULL)
{
nrf_802154_buffer_free(p_ack);
}
}
#endif // NRF_802154_USE_RAW_API
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
__WEAK void nrf_802154_transmit_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
(void)p_frame;
(void)error;
}
__WEAK void nrf_802154_energy_detected(uint8_t result)
{
(void)result;
}
__WEAK void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error)
{
(void)error;
}
__WEAK void nrf_802154_cca_done(bool channel_free)
{
(void)channel_free;
}
__WEAK void nrf_802154_cca_failed(nrf_802154_cca_error_t error)
{
(void)error;
}
@@ -0,0 +1,951 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @brief This module contains generic 802.15.4 radio driver for nRF SoC devices.
*
*/
#ifndef NRF_802154_H_
#define NRF_802154_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_config.h"
#include "nrf_802154_types.h"
#if ENABLE_FEM
#include "fem/nrf_fem_control_api.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize 802.15.4 driver.
*
* @note This function shall be called once, before any other function from this module.
*
* Initialize radio peripheral to Sleep state.
*/
void nrf_802154_init(void);
/**
* @brief Deinitialize 802.15.4 driver.
*
* Deinitialize radio peripheral and reset it to the default state.
*/
void nrf_802154_deinit(void);
#if !NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
/**
* @brief Handle interrupt request from the RADIO peripheral.
*
* @note When NRF_802154_INTERNAL_RADIO_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_802154_radio_irq_handler(void);
#endif // !NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
/**
* @brief Set channel on which the radio shall operate right now.
*
* @param[in] channel Channel number (11-26).
*/
void nrf_802154_channel_set(uint8_t channel);
/**
* @brief Get channel on which the radio operates right now.
*
* @returns Channel number (11-26).
*/
uint8_t nrf_802154_channel_get(void);
/**
* @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_802154_tx_power_set(int8_t power);
/**
* @brief Get currently set transmit power.
*
* @return Currently used transmit power [dBm].
*/
int8_t nrf_802154_tx_power_get(void);
/***************************************************************************************************
* @section Front-end module management.
**************************************************************************************************/
#if ENABLE_FEM
/** Structure containing run-time configuration of FEM module. */
typedef nrf_fem_control_cfg_t nrf_802154_fem_control_cfg_t;
/** Macro with default configuration of FEM module. */
#define NRF_802154_FEM_DEFAULT_SETTINGS \
((nrf_802154_fem_control_cfg_t) { \
.pa_cfg = { \
.enable = 1, \
.active_high = 1, \
.gpio_pin = NRF_FEM_CONTROL_DEFAULT_PA_PIN, \
}, \
.lna_cfg = { \
.enable = 1, \
.active_high = 1, \
.gpio_pin = NRF_FEM_CONTROL_DEFAULT_LNA_PIN, \
}, \
.pa_gpiote_ch_id = NRF_FEM_CONTROL_DEFAULT_PA_GPIOTE_CHANNEL, \
.lna_gpiote_ch_id = NRF_FEM_CONTROL_DEFAULT_LNA_GPIOTE_CHANNEL, \
.ppi_ch_id_set = NRF_FEM_CONTROL_DEFAULT_SET_PPI_CHANNEL, \
.ppi_ch_id_clr = NRF_FEM_CONTROL_DEFAULT_CLR_PPI_CHANNEL, \
})
/**
* @brief Set PA & LNA GPIO toggle configuration.
*
* @note This function shall not be called when radio is in use.
*
* @param[in] p_cfg A pointer to the PA & LNA GPIO toggle configuration.
*
*/
void nrf_802154_fem_control_cfg_set(const nrf_802154_fem_control_cfg_t * p_cfg);
/**
* @brief Get PA & LNA GPIO toggle configuration.
*
* @param[out] p_cfg A pointer to the structure for the PA & LNA GPIO toggle configuration.
*
*/
void nrf_802154_fem_control_cfg_get(nrf_802154_fem_control_cfg_t * p_cfg);
#endif // ENABLE_FEM
/***************************************************************************************************
* @section Setting addresses and Pan Id of this device.
**************************************************************************************************/
/**
* @brief Set PAN Id used by this device.
*
* @param[in] p_pan_id Pointer to PAN Id (2 bytes, little-endian).
*
* This function makes copy of the PAN Id.
*/
void nrf_802154_pan_id_set(const uint8_t *p_pan_id);
/**
* @brief Set Extended Address of this device.
*
* @param[in] p_extended_address Pointer to extended address (8 bytes, little-endian).
*
* This function makes copy of the address.
*/
void nrf_802154_extended_address_set(const uint8_t *p_extended_address);
/**
* @brief Set Short Address of this device.
*
* @param[in] p_short_address Pointer to short address (2 bytes, little-endian).
*
* This function makes copy of the address.
*/
void nrf_802154_short_address_set(const uint8_t *p_short_address);
/***************************************************************************************************
* @section Functions to calculate data given by the driver.
**************************************************************************************************/
/**
* @brief Calculate dBm from energy level received during energy detection procedure.
*
* @param[in] energy_level Energy level passed by @sa nrf_802154_energy_detected
*
* @return Result of energy detection procedure in dBm.
*/
int8_t nrf_802154_dbm_from_energy_level_calculate(uint8_t energy_level);
/**
* @brief Calculate timestamp of beginning of first symbol of preamble in a received frame.
*
* @param[in] end_timestamp Timestamp of end of last symbol in the frame (in us).
* @param[in] psdu_length Number of bytes in the frame PSDU.
*
* @return Timestamp of first preamble symbol of given frame (in us).
*/
uint32_t nrf_802154_first_symbol_timestamp_get(uint32_t end_timestamp, uint8_t psdu_length);
/***************************************************************************************************
* @section Functions to request FSM transitions and check current state.
**************************************************************************************************/
/**
* @brief Get current state of the radio.
*/
nrf_802154_state_t nrf_802154_state_get(void);
/**
* @brief Change radio state to Sleep.
*
* Sleep state is the lowest power state. In this state radio cannot transmit or receive frames.
* It is the only state in which the driver releases high frequency clock and does not request
* timeslots from a radio arbiter.
*
* @note High frequency clock may be enabled even in radio Sleep state if other module requests it.
*
* @return true If the radio changes it's state to low power mode.
* @return false If the driver could not schedule changing state.
*/
bool nrf_802154_sleep(void);
/**
* @brief Change radio state to Receive.
*
* In Receive state radio receives frames and may automatically send ACK frames when appropriate.
* Received frame is reported to higher layer by @sa nrf_radio802154_received() call.
*
* @return true If the radio enters Receive state.
* @return false If the driver could not enter Receive state.
*/
bool nrf_802154_receive(void);
#if NRF_802154_USE_RAW_API
/**
* @brief Change radio state to Transmit.
*
* @note If the CPU was halted or interrupted during performing this function
* @sa nrf_802154_transmitted() or @sa nrf_802154_transmit_failed() may be
* called before nrf_802154_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.
* Depending on @sa NRF_802154_ACK_TIMEOUT_ENABLED configuration option, Radio driver automatically
* stops waiting for an ACK frame or waits infinitely for an ACK frame. If it is configured to wait
* indefinitely, MAC layer is responsible to call @sa nrf_radio802154_receive() or
* @sa nrf_radio802154_sleep() after ACK timeout.
* Transmission result is reported to higher layer by @sa nrf_radio802154_transmitted() or
* @sa nrf_radio802154_transmit_failed() 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 (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_802154_transmit_raw(const uint8_t * p_data, bool cca);
#else // NRF_802154_USE_RAW_API
/**
* @brief Change radio state to Transmit.
*
* @note If the CPU was halted or interrupted during performing this function
* @sa nrf_802154_transmitted() or @sa nrf_802154_transmit_failed() may be
* called before nrf_802154_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_802154_transmit_raw() function should
* be used instead of this.
*
* In Transmit state radio transmits given frame. If requested it waits for ACK frame.
* Depending on @sa NRF_802154_ACK_TIMEOUT_ENABLED configuration option, Radio driver automatically
* stops waiting for an ACK frame or waits infinitely for an ACK frame. If it is configured to wait
* indefinitely, MAC layer is responsible to call @sa nrf_radio802154_receive() or
* @sa nrf_radio802154_sleep() after ACK timeout.
* Transmission result is reported to higher layer by @sa nrf_radio802154_transmitted() or
* @sa nrf_radio802154_transmit_failed() 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_802154_transmit(const uint8_t * p_data, uint8_t length, bool cca);
#endif // NRF_802154_USE_RAW_API
/**
* @brief Change radio state to Energy Detection.
*
* In Energy Detection state radio detects maximum energy for given time. Result of the detection
* is reported to the higher layer by @sa nrf_802154_energy_detected() call.
*
* @note @sa nrf_802154_energy_detected() may be called before nrf_802154_energy_detection()
* returns result.
* @note Performing Energy Detection procedure make take longer than time requested in @p time_us.
* Procedure is performed only during timeslots granted by a radio arbiter. It may be
* interrupted by other protocols using radio hardware. If procedure is interrupted, it is
* automatically continued and the sum of time periods during which the procedure is carried
* out is not less than requested @p time_us.
*
* @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_802154_energy_detection(uint32_t time_us);
/**
* @brief Change radio state to CCA.
*
* @note @sa nrf_802154_cca_done() may be called before nrf_802154_cca() returns result.
*
* In CCA state radio verifies if channel is clear. Result of verification is reported to the higher
* layer by @sa nrf_802154_cca_done() call.
*
* @return true If the CCA procedure was scheduled.
* @return false If the driver could not schedule the CCA procedure.
*/
bool nrf_802154_cca(void);
/**
* @brief Change radio state to Continuous Carrier.
*
* @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_802154_continuous_carrier(void);
/***************************************************************************************************
* @section Calls to higher layer.
**************************************************************************************************/
/**
* @brief Notify that transmitting ACK frame has started.
*
* @note This function should be very short to prevent dropping frames by the driver.
*/
extern void nrf_802154_tx_ack_started(void);
#if NRF_802154_USE_RAW_API
/**
* @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 @sa nrf_802154_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 @sa nrf_802154_buffer_free_raw() function is called.
*
* 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_802154_received_raw(uint8_t * p_data, int8_t power, uint8_t lqi);
#else // NRF_802154_USE_RAW_API
/**
* @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_802154_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_802154_buffer_free() function is called.
*
* 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_802154_received(uint8_t * p_data, uint8_t length, int8_t power, uint8_t lqi);
#endif // !NRF_802154_USE_RAW_API
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
#if NRF_802154_USE_RAW_API
/**
* @brief Notify that frame was received at given time
*
* This functions works like @sa nrf_802154_received_raw and adds timestamp to parameter
* list.
*
* @note @p timestamp may be inacurate due to software latency (IRQ handling).
* @note @p timestamp granularity depends on granularity of the timer driver in platform/timer
* directory.
* @note Including timestamp to received frame uses resources like CPU time and memory. If timestamp
* is not required use @sa nrf_802154_received_raw() instead.
*
* @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.
* @param[in] time Timestamp taken when last symbol of the frame was received (in us).
*/
extern void nrf_802154_received_timestamp_raw(uint8_t * p_data,
int8_t power,
uint8_t lqi,
uint32_t time);
#else // NRF_802154_USE_RAW_API
/**
* @brief Notify that frame was received at given time
*
* This functions works like @sa nrf_802154_received and adds timestamp to parameter list.
*
* @note @p timestamp may be inacurate due to software latency (IRQ handling).
* @note @p timestamp granularity depends on granularity of the timer driver in platform/timer
* directory.
* @note Including timestamp to received frame uses resources like CPU time and memory. If timestamp
* is not required use @sa nrf_802154_received instead().
*
* @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.
* @param[in] time Timestamp taken when last symbol of the frame was received (in us).
*/
extern void nrf_802154_received_timestamp(uint8_t * p_data,
uint8_t length,
int8_t power,
uint8_t lqi,
uint32_t time);
#endif // NRF_802154_USE_RAW_API
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
/**
* @brief Notify that reception of a frame failed.
*
* @param[in] error An error code that indicates reason of the failure.
*/
extern void nrf_802154_receive_failed(nrf_802154_rx_error_t error);
/**
* @brief Notify that transmitting frame has started.
*
* @note It is possible that transmit procedure is interrupted and
* @sa nrf_802154_transmitted won't be called.
* @note This function should be very short to prevent dropping frames by the driver.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame being transmitted.
*/
extern void nrf_802154_tx_started(const uint8_t * p_frame);
#if NRF_802154_USE_RAW_API
/**
* @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_802154_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_802154_buffer_free_raw() function is called.
*
* @param[in] p_frame Pointer to buffer containing PHR and PSDU of transmitted frame.
* @param[in] p_ack Pointer to received ACK buffer. Fist byte in the buffer is length of the
* 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_802154_transmitted_raw(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
uint8_t lqi);
#else // NRF_802154_USE_RAW_API
/**
* @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_802154_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_802154_buffer_free() function is called.
* @note The next higher layer should handle @sa nrf_802154_transmitted() or
* @sa nrf_802154_transmitted_raw() function. It should not handle both.
*
* @param[in] p_frame Pointer to buffer containing PSDU of transmitted frame.
* @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 or 0 if ACK was not requested.
* @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_802154_transmitted(const uint8_t * p_frame,
uint8_t * p_ack,
uint8_t length,
int8_t power,
uint8_t lqi);
#endif // !NRF_802154_USE_RAW_API
#if NRF_802154_FRAME_TIMESTAMP_ENABLED
#if NRF_802154_USE_RAW_API
/**
* @brief Notify that frame was transmitted.
*
* This functions works like @sa nrf_802154_transmitted_raw and adds timestamp to parameter
* list.
*
* @note @p timestamp may be inacurate due to software latency (IRQ handling).
* @note @p timestamp granularity depends on granularity of the timer driver in platform/timer
* directory.
* @note Including timestamp to received frame uses resources like CPU time and memory. If timestamp
* is not required use @sa nrf_802154_received instead.
*
* @param[in] p_frame Pointer to buffer containing PSDU of transmitted frame.
* @param[in] p_ack Pointer to received ACK buffer. Fist byte in the buffer is length of the
* 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.
* @param[in] time Timestamp taken when received last symbol of ACK or 0 if ACK was not
* requested.
*/
extern void nrf_802154_transmitted_timestamp_raw(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
uint8_t lqi,
uint32_t time);
#else // NRF_802154_USE_RAW_API
/**
* @brief Notify that frame was transmitted.
*
* This functions works like @sa nrf_802154_transmitted and adds timestamp to parameter
* list.
*
* @note @p timestamp may be inacurate due to software latency (IRQ handling).
* @note @p timestamp granularity depends on granularity of the timer driver in platform/timer
* directory.
* @note Including timestamp to received frame uses resources like CPU time and memory. If timestamp
* is not required use @sa nrf_802154_received instead.
*
* @param[in] p_frame Pointer to buffer containing PSDU of transmitted frame.
* @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.
* @param[in] time Timestamp taken when received last symbol of ACK or 0 if ACK was not
* requested.
*/
extern void nrf_802154_transmitted_timestamp(const uint8_t * p_frame,
uint8_t * p_ack,
uint8_t length,
int8_t power,
uint8_t lqi,
uint32_t time);
#endif // NRF_802154_USE_RAW_API
#endif // NRF_802154_FRAME_TIMESTAMP_ENABLED
/**
* @brief Notify that frame was not transmitted due to busy channel.
*
* This function is called if transmission procedure fails.
*
* @param[in] p_frame Pointer to buffer containing PSDU of frame that was not transmitted.
* @param[in] error Reason of the failure.
*/
extern void nrf_802154_transmit_failed(const uint8_t * p_frame,
nrf_802154_tx_error_t error);
/**
* @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_802154_dbm_from_energy_level_calculate().
*
* @param[in] result Maximum energy detected during Energy Detection procedure.
*/
extern void nrf_802154_energy_detected(uint8_t result);
/**
* @brief Notify that Energy Detection procedure failed.
*
* @param[in] error Reason of the failure.
*/
extern void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error);
/**
* @brief Notify that CCA procedure has finished.
*
* @param[in] channel_free Indication if channel is free.
*/
extern void nrf_802154_cca_done(bool channel_free);
/**
* @brief Notify that CCA procedure failed.
*
* @param[in] error Reason of the failure.
*/
extern void nrf_802154_cca_failed(nrf_802154_cca_error_t error);
/***************************************************************************************************
* @section Driver memory management
**************************************************************************************************/
#if NRF_802154_USE_RAW_API
/**
* @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.
*
* @param[in] p_data A pointer to the buffer containing received data that is no more needed by
* the higher layer.
*/
void nrf_802154_buffer_free_raw(uint8_t * p_data);
#else // NRF_802154_USE_RAW_API
/**
* @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.
*
* @param[in] p_data A pointer to the buffer containing received data that is no more needed by
* the higher layer.
*/
void nrf_802154_buffer_free(uint8_t * p_data);
#endif // NRF_802154_USE_RAW_API
/***************************************************************************************************
* @section RSSI measurement function.
**************************************************************************************************/
/**
* @brief Begin RSSI measurement.
*
* @note This function should be called in Receive state.
*
* Begin RSSI measurement. The result will be available in 8 uS. The result can be read by
* @sa nrf_radio802154_rssi_last_get() function.
*/
void nrf_802154_rssi_measure(void);
/**
* @brief Get result of last RSSI measurement.
*
* @returns RSSI measurement result [dBm].
*/
int8_t nrf_802154_rssi_last_get(void);
/**
* @brief Adjust given RSSI measurement using a temperature correction factor.
*
* @param[in] rssi Measured RSSI value [dBm].
* @param[in] temp Temperature value when RSSI sample took place [C].
*
* @returns RSSI [dBm] corrected by a temperature factor (Errata 153).
*/
int8_t nrf_802154_rssi_corrected_get(int8_t rssi, int8_t temp);
/***************************************************************************************************
* @section Promiscuous mode.
**************************************************************************************************/
/**
* @brief Enable or disable promiscuous radio mode.
*
* @note Promiscuous mode is disabled by default.
*
* In promiscuous mode driver notifies higher layer that it received any frame (regardless
* frame type or destination address).
* In normal mode (not promiscuous) higher layer is not notified about ACK frames and frames with
* unknown type. Also frames with destination address not matching this device address are ignored.
*
* @param[in] enabled If promiscuous mode should be enabled.
*/
void nrf_802154_promiscuous_set(bool enabled);
/**
* @brief Check if radio is in promiscuous mode.
*
* @retval True Radio is in promiscuous mode.
* @retval False Radio is not in promiscuous mode.
*/
bool nrf_802154_promiscuous_get(void);
/***************************************************************************************************
* @section Auto ACK management.
**************************************************************************************************/
/**
* @brief Enable or disable auto ACK procedure.
*
* @note Auto ACK procedure is enabled by default.
*
* If auto ACK procedure is enabled the driver prepares and sends ACK frames automatically
* aTurnaroundTime (192 us) after proper frame is received. The driver sets sequence number in
* the ACK frame and pending bit according to auto pending bit feature settings. When auto ACK
* procedure is enabled the driver notifies the next higher layer about received frame after ACK
* frame is transmitted.
* If auto ACK procedure is disabled the driver does not transmit ACK frames. It notifies the next
* higher layer about received frame when a frame is received. In this mode the next higher layer
* is responsible for sending ACK frame. ACK frames should be sent using @sa nrf_802154_transmit()
* function.
*
* @param[in] enabled If auto ACK procedure should be enabled.
*/
void nrf_802154_auto_ack_set(bool enabled);
/**
* @brief Check if auto ACK procedure is enabled.
*
* @retval True Auto ACK procedure is enabled.
* @retval False Auto ACK procedure is disabled.
*/
bool nrf_802154_auto_ack_get(void);
/**
* @brief Enable or disable setting pending bit in automatically transmitted ACK frames.
*
* @note Setting pending bit in automatically transmitted ACK frames is enabled by default.
*
* Radio driver automatically sends ACK frames in response frames destined to this node with Ack
* Request bit set. Pending bit in ACK frame can be set or cleared regarding data in indirect queue
* destined to ACK destination.
*
* If setting pending bit in ACK frames is disabled, pending bit in every ACK frame is set.
* If setting pending bit in ACK frames is enabled, radio driver checks if there is data
* in indirect queue destined to ACK destination. If there is no such data, pending bit is cleared.
*
* @note It is possible that due to ISR latency, radio driver cannot verify if there is data in
* indirect queue before ACK is sent. In this case pending bit is set.
*
* @param[in] enabled If setting pending bit in ACK frames is enabled.
*/
void nrf_802154_auto_pending_bit_set(bool enabled);
/**
* @brief Add address of peer node for which there is pending data in the buffer.
*
* @note This function makes a copy of given address.
*
* @param[in] p_addr Array of bytes containing address of the node (little-endian).
* @param[in] extended If given address is Extended MAC Address or Short MAC Address.
*
* @retval True Address successfully added to the list.
* @retval False There is not enough memory to store this address in the list.
*/
bool nrf_802154_pending_bit_for_addr_set(const uint8_t *p_addr, bool extended);
/**
* @brief Remove address of peer node for which there is no more pending data in the buffer.
*
* @param[in] p_addr Array of bytes containing address of the node (little-endian).
* @param[in] extended If given address is Extended MAC Address or Short MAC Address.
*
* @retval True Address successfully removed from the list.
* @retval False There is no such address in the list.
*/
bool nrf_802154_pending_bit_for_addr_clear(const uint8_t *p_addr, bool extended);
/**
* @brief Remove all addresses of given type from pending bit list.
*
* @param[in] extended If function should remove all Exnteded MAC Adresses of all Short Addresses.
*/
void nrf_802154_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_802154_cca_cfg_set(const nrf_802154_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_802154_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg);
/***************************************************************************************************
* @section CSMA-CA procedure.
**************************************************************************************************/
#if NRF_802154_CSMA_CA_ENABLED
#if NRF_802154_USE_RAW_API
/**
* @brief Perform CSMA-CA procedure and transmit frame in case of success.
*
* End of CSMA-CA procedure is notified by @sa nrf_802154_transmitted_raw() or
* @sa nrf_802154_transmit_failed() function.
*
* @note The driver may be configured to automatically time out waiting for ACK frame depending on
* @sa NRF_802154_ACK_TIMEOUT_ENABLED configuration option. If automatic ACK timeout is
* disabled, CSMA-CA procedure does not time out waiting for ACK frame in case frame with ACK
* request bit set was transmitted. MAC layer should manage timer to time out waiting for ACK
* frame. This timer may be started by @sa nrf_802154_tx_started() function. When the timer
* expires MAC layer should call @sa nrf_802154_receive() or @sa nrf_802154_sleep() to stop
* waiting for ACK frame.
* @note Before CSMA-CA procedure is used, application should initialize random seed with srand().
*
* @param[in] p_data Pointer to frame to transmit. @sa nrf_802154_transmit_raw()
*/
void nrf_802154_transmit_csma_ca_raw(const uint8_t * p_data);
#else // NRF_802154_USE_RAW_API
/**
* @brief Perform CSMA-CA procedure and transmit frame in case of success.
*
* End of CSMA-CA procedure is notified by @sa nrf_802154_transmitted() or
* @sa nrf_802154_transmit_failed() function.
*
* @note The driver may be configured to automatically time out waiting for ACK frame depending on
* @sa NRF_802154_ACK_TIMEOUT_ENABLED configuration option. If automatic ACK timeout is
* disabled, CSMA-CA procedure does not time out waiting for ACK frame in case frame with ACK
* request bit set was transmitted. MAC layer should manage timer to time out waiting for ACK
* frame. This timer may be started by @sa nrf_802154_tx_started() function. When the timer
* expires MAC layer should call @sa nrf_802154_receive() or @sa nrf_802154_sleep() to stop
* waiting for ACK frame.
* @note Before CSMA-CA procedure is used, application should initialize random seed with srand().
*
* @param[in] p_data Pointer to frame to transmit. @sa nrf_802154_transmit()
* @param[in] length Length of given frame. @sa nrf_802154_transmit()
*/
void nrf_802154_transmit_csma_ca(const uint8_t * p_data, uint8_t length);
#endif // NRF_802154_USE_RAW_API
#endif // NRF_802154_CSMA_CA_ENABLED
/***************************************************************************************************
* @section ACK timeout procedure.
**************************************************************************************************/
#if NRF_802154_ACK_TIMEOUT_ENABLED
/**
* @brief Set timeout time for ACK timeout feature.
*
* Timeout is notified by @sa nrf_802154_transmit_failed() function.
*
* @param[in] time Timeout time in us. Timeout is started at the beginning of frame transmission
* (after transmission of PHR). Default value is defined in nrf_802154_config.h
* @sa NRF_802154_ACK_TIMEOUT_DEFAULT_TIMEOUT .
*/
void nrf_802154_ack_timeout_set(uint32_t time);
#endif // NRF_802154_ACK_TIMEOUT_ENABLED
#ifdef __cplusplus
}
#endif
#endif /* NRF_802154_H_ */
@@ -0,0 +1,413 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements procedures to set pending bit in nRF 802.15.4 radio driver.
*
*/
#include "nrf_802154_ack_pending_bit.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_802154_config.h"
#include "nrf_802154_const.h"
#include "hal/nrf_radio.h"
/// Maximum number of Short Addresses of nodes for which there is pending data in buffer.
#define NUM_PENDING_SHORT_ADDRESSES NRF_802154_PENDING_SHORT_ADDRESSES
/// Maximum number of Extended Addresses of nodes for which there is pending data in buffer.
#define NUM_PENDING_EXTENDED_ADDRESSES NRF_802154_PENDING_EXTENDED_ADDRESSES
/// Value used to mark Short Address as unused.
#define UNUSED_PENDING_SHORT_ADDRESS ((uint8_t [SHORT_ADDRESS_SIZE]) {0xff, 0xff})
/// Value used to mark Extended Address as unused.
#define UNUSED_PENDING_EXTENDED_ADDRESS ((uint8_t [EXTENDED_ADDRESS_SIZE]) {0})
/// If pending bit in ACK frame should be set to valid or default value.
static bool m_setting_pending_bit_enabled;
/// Array of Short Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_pending_short[NUM_PENDING_SHORT_ADDRESSES][SHORT_ADDRESS_SIZE];
/// Array of Extended Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_pending_extended[NUM_PENDING_EXTENDED_ADDRESSES][EXTENDED_ADDRESS_SIZE];
/// Current number of Short Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_num_of_pending_short;
/// Current number of Extended Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_num_of_pending_extended;
/**
* @brief Compare two extended addresses.
*
* @param[in] p_first_addr Pointer to a first address that should be compared.
* @param[in] p_second_addr Pointer to a second address that should be compared.
*
* @retval -1 First address is less than the second address.
* @retval 0 First address is equal to the second address.
* @retval 1 First address is greater than the second address.
*/
static int8_t extended_addr_compare(const uint8_t * p_first_addr, const uint8_t * p_second_addr)
{
uint64_t first_addr;
uint64_t second_addr;
// Cast address pointer to uint64_t variables in 2 steps to prevent unaligned access errors.
first_addr = *(uint32_t *)p_first_addr;
first_addr = (first_addr << 32) | (*(uint32_t *)(p_first_addr + sizeof(uint32_t)));
second_addr = *(uint32_t *)p_second_addr;
second_addr = (second_addr << 32) | (*(uint32_t *)(p_second_addr + sizeof(uint32_t)));
if (first_addr < second_addr)
{
return -1;
}
else if (first_addr > second_addr)
{
return 1;
}
else
{
return 0;
}
}
/**
* @brief Compare two short addresses.
*
* @param[in] p_first_addr Pointer to a first address that should be compared.
* @param[in] p_second_addr Pointer to a second address that should be compared.
*
* @retval -1 First address is less than the second address.
* @retval 0 First address is equal to the second address.
* @retval 1 First address is greater than the second address.
*/
static int8_t short_addr_compare(const uint8_t * p_first_addr, const uint8_t * p_second_addr)
{
uint16_t first_addr = *(uint16_t *)(p_first_addr);
uint16_t second_addr = *(uint16_t *)(p_second_addr);
if (first_addr < second_addr)
{
return -1;
}
else if (first_addr > second_addr)
{
return 1;
}
else
{
return 0;
}
}
/**
* @brief Compare two addresses.
*
* @param[in] p_first_addr Pointer to a first address that should be compared.
* @param[in] p_second_addr Pointer to a second address that should be compared.
* @param[in] extended Indication if @p p_first_addr and @p p_second_addr are extended or short addresses.
*
* @retval -1 First address is less than the second address.
* @retval 0 First address is equal to the second address.
* @retval 1 First address is greater than the second address.
*/
static int8_t addr_compare(const uint8_t * p_first_addr, const uint8_t * p_second_addr, bool extended)
{
if (extended)
{
return extended_addr_compare(p_first_addr, p_second_addr);
}
else
{
return short_addr_compare(p_first_addr, p_second_addr);
}
}
/**
* @brief Perform a binary search for an address in a list of addresses.
*
* @param[in] p_addr Pointer to an address that is searched for.
* @param[in] p_addr_array Pointer to a list of addresses to be searched.
* @param[out] p_location If the address @p p_addr appears in the list, this is its index in the address list.
* Otherwise, it is the index which @p p_addr would have if it was placed in the list
* (ascending order assumed).
* @param[in] extended Indication if @p p_addr is an extended or a short addresses.
*
* @retval true Address @p p_addr is in the list.
* @retval false Address @p p_addr is not in the list.
*/
static bool addr_binary_search(const uint8_t * p_addr,
const uint8_t * p_addr_array,
uint8_t * p_location,
bool extended)
{
uint8_t addr_array_len = extended ? m_num_of_pending_extended : m_num_of_pending_short;
uint8_t entry_size = extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE;
int8_t low = 0;
int8_t midpoint = 0;
int8_t high = addr_array_len;
while (high >= low)
{
midpoint = low + (high - low) / 2;
if (midpoint >= addr_array_len)
{
break;
}
switch (addr_compare(p_addr, p_addr_array + entry_size * midpoint, extended))
{
case -1:
high = midpoint - 1;
break;
case 0:
*p_location = midpoint;
return true;
case 1:
low = midpoint + 1;
break;
default:
break;
}
}
/* If in the last iteration of the loop the last case was utilized, it means that the midpoint
* found by the algorithm is less than the address to be added. The midpoint should be therefore
* shifted to the next position. As a simplified example, a { 1, 3, 4 } array can be considered.
* Suppose that a number equal to 2 is about to be added to the array. At the beginning of the
* last iteration, midpoint is equal to 1 and low and high are equal to 0. Midpoint is then set
* to 0 and with last case being utilized, low is set to 1. However, midpoint equal to 0 is
* incorrect, as in the last iteration first element of the array proves to be less than the
* element to be added to the array. With the below code, midpoint is then shifted to 1. */
if (low == midpoint + 1)
{
midpoint++;
}
*p_location = midpoint;
return false;
}
/**
* @brief Find an address in a list of addresses.
*
* @param[in] p_addr Pointer to an address that is searched for.
* @param[out] p_location If the address @p p_addr appears in the list, this is its index in the address list.
* Otherwise, it is the index which @p p_addr would have if it was placed in the list
* (ascending order assumed).
* @param[in] extended Indication if @p p_addr is an extended or a short addresses.
*
* @retval true Address @p p_addr is in the list.
* @retval false Address @p p_addr is not in the list.
*/
static bool addr_index_find(const uint8_t * p_addr,
uint8_t * p_location,
bool extended)
{
if (extended)
{
return addr_binary_search(p_addr, (uint8_t *)m_pending_extended, p_location, extended);
}
else
{
return addr_binary_search(p_addr, (uint8_t *)m_pending_short, p_location, extended);
}
}
/**
* @brief Add an address to the address list in ascending order.
*
* @param[in] p_addr Pointer to the address to be added.
* @param[in] location Index of the location where @p p_addr should be added.
* @param[in] extended Indication if @p p_addr is an extended or a short addresses.
*
* @retval true Address @p p_addr has been added to the list successfully.
* @retval false Address @p p_addr could not be added to the list.
*/
static bool addr_add(const uint8_t * p_addr, uint8_t location, bool extended)
{
uint8_t * p_addr_array = extended ? (uint8_t *)m_pending_extended :
(uint8_t *)m_pending_short;
uint8_t max_addr_array_len = extended ? NUM_PENDING_EXTENDED_ADDRESSES :
NUM_PENDING_SHORT_ADDRESSES;
uint8_t * p_addr_array_len = extended ? &m_num_of_pending_extended : &m_num_of_pending_short;
uint8_t entry_size = extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE;
if (*p_addr_array_len == max_addr_array_len)
{
return false;
}
memmove(p_addr_array + entry_size * (location + 1),
p_addr_array + entry_size * (location),
(*p_addr_array_len - location) * entry_size);
memcpy(p_addr_array + entry_size * location, p_addr, entry_size);
(*p_addr_array_len)++;
return true;
}
/**
* @brief Remove an address from the address list keeping it in ascending order.
*
* @param[in] location Index of the element to be removed from the list.
* @param[in] extended Indication if address to remove is an extended or a short address.
*
* @retval true Address @p p_addr has been removed from the list successfully.
* @retval false Address @p p_addr could not removed from the list.
*/
static bool addr_remove(uint8_t location, bool extended)
{
uint8_t * p_addr_array = extended ? (uint8_t *)m_pending_extended :
(uint8_t *)m_pending_short;
uint8_t * p_addr_array_len = extended ? &m_num_of_pending_extended : &m_num_of_pending_short;
uint8_t entry_size = extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE;
if (*p_addr_array_len == 0)
{
return false;
}
memmove(p_addr_array + entry_size * location,
p_addr_array + entry_size * (location + 1),
(*p_addr_array_len - location - 1) * entry_size);
(*p_addr_array_len)--;
return true;
}
void nrf_802154_ack_pending_bit_init(void)
{
m_setting_pending_bit_enabled = true;
m_num_of_pending_extended = 0;
m_num_of_pending_short = 0;
}
void nrf_802154_ack_pending_bit_set(bool enabled)
{
m_setting_pending_bit_enabled = enabled;
}
bool nrf_802154_ack_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended)
{
uint8_t location = 0;
if (addr_index_find(p_addr, &location, extended))
{
return true;
}
else
{
return addr_add(p_addr, location, extended);
}
}
bool nrf_802154_ack_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended)
{
uint8_t location = 0;
if (addr_index_find(p_addr, &location, extended))
{
return addr_remove(location, extended);
}
else
{
return false;
}
}
void nrf_802154_ack_pending_bit_for_addr_reset(bool extended)
{
if (extended)
{
m_num_of_pending_extended = 0;
}
else
{
m_num_of_pending_short = 0;
}
}
bool nrf_802154_ack_pending_bit_should_be_set(const uint8_t * p_psdu)
{
const uint8_t * p_src_addr;
uint8_t location;
bool extended;
// If automatic setting of pending bit in ACK frames is disabled the pending bit is always set.
if (!m_setting_pending_bit_enabled)
{
return true;
}
switch (p_psdu[DEST_ADDR_TYPE_OFFSET] & DEST_ADDR_TYPE_MASK)
{
case DEST_ADDR_TYPE_SHORT:
p_src_addr = &p_psdu[SRC_ADDR_OFFSET_SHORT_DST];
break;
case DEST_ADDR_TYPE_EXTENDED:
p_src_addr = &p_psdu[SRC_ADDR_OFFSET_EXTENDED_DST];
break;
default:
return true;
}
if (0 == (p_psdu[PAN_ID_COMPR_OFFSET] & PAN_ID_COMPR_MASK))
{
p_src_addr += PAN_ID_SIZE;
}
switch (p_psdu[SRC_ADDR_TYPE_OFFSET] & SRC_ADDR_TYPE_MASK)
{
case SRC_ADDR_TYPE_SHORT:
extended = false;
break;
case SRC_ADDR_TYPE_EXTENDED:
extended = true;
break;
default:
return true;
}
return addr_index_find(p_src_addr, &location, extended);
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
*
*/
#ifndef NRF_DRV_RADIO802154_ACK_PENDING_BIT_H_
#define NRF_DRV_RADIO802154_ACK_PENDING_BIT_H_
#ifndef NRF_802154_ACK_PENDING_BIT_H_
#define NRF_802154_ACK_PENDING_BIT_H_
#include <stdbool.h>
#include <stdint.h>
@@ -46,14 +46,14 @@ extern "C" {
/**
* @brief Initialize this module.
*/
void nrf_drv_radio802154_ack_pending_bit_init(void);
void nrf_802154_ack_pending_bit_init(void);
/**
* @brief Enable or disable procedure of setting pending bit in ACK frame.
*
* @param[in] enabled True if procedure should be enabled, false otherwise.
*/
void nrf_drv_radio802154_ack_pending_bit_set(bool enabled);
void nrf_802154_ack_pending_bit_set(bool enabled);
/**
* @brief Add address to ACK pending bit list.
@@ -68,7 +68,7 @@ void nrf_drv_radio802154_ack_pending_bit_set(bool enabled);
* @retval true Address successfully added to the list.
* @retval false Address was not added to the list (list is full).
*/
bool nrf_drv_radio802154_ack_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended);
bool nrf_802154_ack_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended);
/**
* @brief Remove address from ACK pending bit list.
@@ -83,7 +83,7 @@ bool nrf_drv_radio802154_ack_pending_bit_for_addr_set(const uint8_t * p_addr, bo
* @retval true Address successfully removed from the list.
* @retval false Address was not removed from the list (address is missing in the list).
*/
bool nrf_drv_radio802154_ack_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended);
bool nrf_802154_ack_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended);
/**
* @brief Remove all addresses of given length from ACK pending bit list.
@@ -91,7 +91,7 @@ bool nrf_drv_radio802154_ack_pending_bit_for_addr_clear(const uint8_t * p_addr,
* @param[in] extended Indication if all extended or all short addresses should be removed from
* the list.
*/
void nrf_drv_radio802154_ack_pending_bit_for_addr_reset(bool extended);
void nrf_802154_ack_pending_bit_for_addr_reset(bool extended);
/**
* @brief Check if pending bit should be set in ACK sent in response to given frame.
@@ -101,11 +101,11 @@ void nrf_drv_radio802154_ack_pending_bit_for_addr_reset(bool extended);
* @retval true Pending bit should be set.
* @retval false Pending bit should be cleared.
*/
bool nrf_drv_radio802154_ack_pending_bit_should_be_set(const uint8_t * p_psdu);
bool nrf_802154_ack_pending_bit_should_be_set(const uint8_t * p_psdu);
#ifdef __cplusplus
}
#endif
#endif /* NRF_DRV_RADIO802154_ACK_PENDING_BIT_H_ */
#endif /* NRF_802154_ACK_PENDING_BIT_H_ */
@@ -0,0 +1,462 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_802154_CONFIG_H__
#define NRF_802154_CONFIG_H__
#ifdef NRF_802154_PROJECT_CONFIG
#include NRF_802154_PROJECT_CONFIG
#endif
#include <nrf.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_802154_config 802.15.4 driver configuration
* @{
* @ingroup nrf_802154
* @brief Configuration of 802.15.4 radio driver for nRF SoC.
*/
/***************************************************************************************************
* @section Radio Driver Configuration.
**************************************************************************************************/
/**
* @def NRF_802154_CCA_MODE
*
* CCA Mode used by the driver.
*
*/
#ifndef NRF_802154_CCA_MODE_DEFAULT
#define NRF_802154_CCA_MODE_DEFAULT NRF_RADIO_CCA_MODE_ED
#endif
/**
* @def NRF_802154_CCA_ED_THRESHOLD
*
* Energy Detection Threshold used in CCA procedure.
*
*/
#ifndef NRF_802154_CCA_ED_THRESHOLD_DEFAULT
#define NRF_802154_CCA_ED_THRESHOLD_DEFAULT 0x14
#endif
/**
* @def NRF_802154_CCA_CORR_THRESHOLD
*
* Correlator Threshold used in CCA procedure.
*
*/
#ifndef NRF_802154_CCA_CORR_THRESHOLD_DEFAULT
#define NRF_802154_CCA_CORR_THRESHOLD_DEFAULT 0x14
#endif
/**
* @def NRF_802154_CCA_CORR_LIMIT
*
* Correlator limit used in CCA procedure.
*
*/
#ifndef NRF_802154_CCA_CORR_LIMIT_DEFAULT
#define NRF_802154_CCA_CORR_LIMIT_DEFAULT 0x02
#endif
/**
* @def NRF_802154_INTERNAL_RADIO_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_802154_radio_irq_handler(). In this case internal handling should be disabled.
*/
#ifndef NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
#if RAAL_SOFTDEVICE
#define NRF_802154_INTERNAL_RADIO_IRQ_HANDLING 0
#else // RAAL_SOFTDEVICE
#define NRF_802154_INTERNAL_RADIO_IRQ_HANDLING 1
#endif // RAAL_SOFTDEVICE
#endif // NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
/**
* @def NRF_802154_IRQ_PRIORITY
*
* Interrupt priority for RADIO peripheral.
* It is recommended to keep IRQ priority high (low number) to prevent losing frames due to
* preemption.
*
*/
#ifndef NRF_802154_IRQ_PRIORITY
#define NRF_802154_IRQ_PRIORITY 0
#endif
/**
* @def NRF_802154_TIMER_INSTANCE
*
* TIMER instance used by the driver for Ack IFS and by FEM module.
*
*/
#ifndef NRF_802154_TIMER_INSTANCE
#define NRF_802154_TIMER_INSTANCE NRF_TIMER1
#endif
/**
* @def NRF_802154_COUNTER_TIMER_INSTANCE
*
* Timer instance used by the driver for detecting when PSDU is being received.
*
* @note This configuration is only used when NRF_RADIO_EVENT_BCMATCH event handling is disabled
* (@sa NRF_802154_DISABLE_BCC_MATCHING).
*/
#ifndef NRF_802154_COUNTER_TIMER_INSTANCE
#define NRF_802154_COUNTER_TIMER_INSTANCE NRF_TIMER2
#endif
/**
* @def NRF_802154_SWI_EGU_INSTANCE
*
* SWI EGU instance used by the driver to synchronize PPIs and for requests and notifications if
* SWI is in use.
*
* @note This option is used by core module regardless driver configuration.
*
*/
#ifndef NRF_802154_SWI_EGU_INSTANCE
#define NRF_802154_SWI_EGU_INSTANCE NRF_EGU3
#endif
/**
* @def NRF_802154_SWI_IRQ_HANDLER
*
* SWI EGU IRQ handler used by the driver for requests and notifications if SWI is in use.
*
* @note This option is used when the driver uses SWI to process requests and notifications.
*
*/
#ifndef NRF_802154_SWI_IRQ_HANDLER
#define NRF_802154_SWI_IRQ_HANDLER SWI3_EGU3_IRQHandler
#endif
/**
* @def NRF_802154_SWI_IRQN
*
* SWI EGU IRQ number used by the driver for requests and notifications if SWI is in use.
*
* @note This option is used when the driver uses SWI to process requests and notifications.
*
*/
#ifndef NRF_802154_SWI_IRQN
#define NRF_802154_SWI_IRQN SWI3_EGU3_IRQn
#endif
/**
* @def NRF_802154_SWI_PRIORITY
*
* Priority of software interrupt used for requests and notifications.
*
*/
#ifndef NRF_802154_SWI_PRIORITY
#define NRF_802154_SWI_PRIORITY 5
#endif
/**
* @def NRF_802154_USE_RAW_API
*
* When this flag is set RAW API is available for the MAC layer. It is recommended to use RAW API,
* because it provides more optimized functions.
*
* @note If RAW API is not available for the MAC layer, only less optimized functions performing
* copy are available.
*
*/
#ifndef NRF_802154_USE_RAW_API
#define NRF_802154_USE_RAW_API 1
#endif
/**
* @def NRF_802154_PENDING_SHORT_ADDRESSES
*
* Number of slots containing short addresses of nodes for which pending data is stored.
*
*/
#ifndef NRF_802154_PENDING_SHORT_ADDRESSES
#define NRF_802154_PENDING_SHORT_ADDRESSES 10
#endif
/**
* @def NRF_802154_PENDING_EXTENDED_ADDRESSES
*
* Number of slots containing extended addresses of nodes for which pending data is stored.
*
*/
#ifndef NRF_802154_PENDING_EXTENDED_ADDRESSES
#define NRF_802154_PENDING_EXTENDED_ADDRESSES 10
#endif
/**
* @def NRF_802154_RX_BUFFERS
*
* Number of buffers in receive queue.
*
*/
#ifndef NRF_802154_RX_BUFFERS
#define NRF_802154_RX_BUFFERS 16
#endif
/**
* @def NRF_802154_EXCLUDE_BCC_MATCHING
*
* Setting this flag disables NRF_RADIO_EVENT_BCMATCH handling, and therefore address filtering
* during frame reception. With this flag set to 1, address filtering is done after receiving
* a frame, during NRF_RADIO_EVENT_END handling.
*
*/
#ifndef NRF_802154_DISABLE_BCC_MATCHING
#define NRF_802154_DISABLE_BCC_MATCHING 0
#endif
/**
* @def NRF_802154_NOTIFY_CRCERROR
*
* With this flag set to 1 CRC errors would be notified to upper layers. This requires interrupt
* handler to be used.
*
*/
#ifndef NRF_802154_NOTIFY_CRCERROR
#define NRF_802154_NOTIFY_CRCERROR 1
#endif
/**
* @def NRF_802154_FRAME_TIMESTAMP_ENABLED
*
* If timestamps should be added to received frames.
* Enabling this feature enables @sa nrf_802154_received_timsestamp_raw,
* @sa nrf_802154_received_timestamp, @sa nrf_802154_transmitted_timestamp_raw and
* @sa nrf_802154_transmitted_timestamp functions that add timestamps to received frames.
*
*/
#ifndef NRF_802154_FRAME_TIMESTAMP_ENABLED
#define NRF_802154_FRAME_TIMESTAMP_ENABLED 1
#endif
/***************************************************************************************************
* @section Clock Driver Configuration.
**************************************************************************************************/
/**
* @def NRF_802154_CLOCK_IRQ_PRIORITY
*
* Priority of clock interrupt used in standalone clock driver implementation.
*
* @note This configuration is only applicable for Clock Abstraction Layer implementation
* in nrf_802154_clock_nodrv.c.
*
*/
#ifndef NRF_802154_CLOCK_IRQ_PRIORITY
#define NRF_802154_CLOCK_IRQ_PRIORITY 10
#endif
/**
* @def NRF_802154_CLOCK_IRQ_PRIORITY
*
* Low frequency clock source used in standalone clock driver implementation.
*
* @note This configuration is only applicable for Clock Abstraction Layer implementation
* in nrf_802154_clock_nodrv.c.
*
*/
#ifndef NRF_802154_CLOCK_LFCLK_SOURCE
#define NRF_802154_CLOCK_LFCLK_SOURCE NRF_CLOCK_LFCLK_Xtal
#endif
/***************************************************************************************************
* @section RTC Driver Configuration.
**************************************************************************************************/
/**
* @def NRF_802154_RTC_IRQ_PRIORITY
*
* Priority of RTC interrupt used in standalone timer driver implementation.
*
* @note This configuration is only applicable for Timer Abstraction Layer implementation
* in nrf_802154_timer_nodrv.c.
*
*/
#ifndef NRF_802154_RTC_IRQ_PRIORITY
#define NRF_802154_RTC_IRQ_PRIORITY 6
#endif
/**
* @def NRF_802154_RTC_INSTANCE
*
* RTC instance used in standalone timer driver implementation.
*
* @note This configuration is only applicable for Timer Abstraction Layer implementation
* in nrf_802154_timer_nodrv.c.
*
*/
#ifndef NRF_802154_RTC_INSTANCE
#define NRF_802154_RTC_INSTANCE NRF_RTC2
#endif
/**
* @def NRF_802154_RTC_IRQ_HANDLER
*
* RTC interrupt handler name used in standalone timer driver implementation.
*
* @note This configuration is only applicable for Timer Abstraction Layer implementation
* in nrf_802154_timer_nodrv.c.
*
*/
#ifndef NRF_802154_RTC_IRQ_HANDLER
#define NRF_802154_RTC_IRQ_HANDLER RTC2_IRQHandler
#endif
/**
* @def NRF_802154_RTC_IRQN
*
* RTC Interrupt number used in standalone timer driver implementation.
*
* @note This configuration is only applicable for Timer Abstraction Layer implementation
* in nrf_802154_timer_nodrv.c.
*
*/
#ifndef NRF_802154_RTC_IRQN
#define NRF_802154_RTC_IRQN RTC2_IRQn
#endif
/***************************************************************************************************
* @section CSMA/CA procedure configuration.
**************************************************************************************************/
/**
* @def NRF_802154_CSMA_CA_ENABLED
*
* If CSMA-CA procedure should be enabled by the driver. Disabling CSMA-CA procedure improves
* driver performance.
*
*/
#ifndef NRF_802154_CSMA_CA_ENABLED
#define NRF_802154_CSMA_CA_ENABLED 1
#endif
/**
* @def NRF_802154_CSMA_CA_MIN_BE
*
* The minimum value of the backoff exponent (BE) in the CSMA-CA algorithm.
* (IEEE 802.15.4-2015: 6.2.5.1)
*
*/
#ifndef NRF_802154_CSMA_CA_MIN_BE
#define NRF_802154_CSMA_CA_MIN_BE 3
#endif
/**
* @def NRF_802154_CSMA_CA_MAX_BE
*
* The maximum value of the backoff exponent, BE, in the CSMA-CA algorithm.
* (IEEE 802.15.4-2015: 6.2.5.1)
*
*/
#ifndef NRF_802154_CSMA_CA_MAX_BE
#define NRF_802154_CSMA_CA_MAX_BE 5
#endif
/**
* @def NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS
*
* The maximum number of backoffs the CSMA-CA algorithm will attempt before declaring a channel
* access failure.
*
*/
#ifndef NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS
#define NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS 4
#endif
/***************************************************************************************************
* @section ACK timeout feature configuration.
**************************************************************************************************/
/**
* @def NRF_802154_ACK_TIMEOUT_ENABLED
*
* If ACK timeout feature should be enabled in the driver.
*
*/
#ifndef NRF_802154_ACK_TIMEOUT_ENABLED
#define NRF_802154_ACK_TIMEOUT_ENABLED 1
#endif
/**
* @def NRF_802154_ACK_TIMEOUT_DEFAULT_TIMEOUT
*
* Default timeout time in us for ACK timeout feature.
*
*/
#ifndef NRF_802154_ACK_TIMEOUT_DEFAULT_TIMEOUT
#define NRF_802154_ACK_TIMEOUT_DEFAULT_TIMEOUT 7000
#endif
/***************************************************************************************************
* @section Transmission start notification feature configuration.
**************************************************************************************************/
/**
* @def NRF_802154_TX_STARTED_NOTIFY_ENABLED
*
* If notification of started transmission should be enabled in the driver.
*
* @note This feature is enabled by default if Ack Timeout feature or CSMA-CA feature is enabled.
* These features depend on notification of transmission start.
*/
#ifndef NRF_802154_TX_STARTED_NOTIFY_ENABLED
#if NRF_802154_ACK_TIMEOUT_ENABLED || NRF_802154_CSMA_CA_ENABLED
#define NRF_802154_TX_STARTED_NOTIFY_ENABLED 1
#else
#define NRF_802154_TX_STARTED_NOTIFY_ENABLED 0
#endif
#endif // NRF_802154_TX_STARTED_NOTIFY_ENABLED
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif // NRF_802154_CONFIG_H__
@@ -33,44 +33,95 @@
*
*/
#ifndef NRF_DRV_RADIO802154_CONST_H_
#define NRF_DRV_RADIO802154_CONST_H_
#ifndef NRF_802154_CONST_H_
#define NRF_802154_CONST_H_
#define ACK_HEADER_WITH_PENDING 0x12 ///< First byte of ACK frame containing pending bit
#define ACK_HEADER_WITHOUT_PENDING 0x02 ///< First byte of ACK frame without pending bit
#include <stdint.h>
#include "nrf_802154_config.h"
#define ACK_HEADER_WITH_PENDING 0x12 ///< First byte of ACK frame containing pending bit
#define ACK_HEADER_WITHOUT_PENDING 0x02 ///< First byte of ACK frame without pending bit
#define ACK_LENGTH 5 ///< Length of ACK frame
#define ACK_REQUEST_BIT (1 << 5) ///< Ack request bit
#define ACK_REQUEST_OFFSET 1 ///< Byte containing Ack request bit (+1 for frame length byte)
#define DEST_ADDR_TYPE_EXTENDED 0x0c ///< Bits containing extended destination address type
#define DEST_ADDR_TYPE_MASK 0x0c ///< Mask of bits containing destination address type
#define ACK_REQUEST_BIT (1 << 5) ///< Ack request bit
#define DEST_ADDR_TYPE_OFFSET 2 ///< Byte containing destination address type (+1 for frame length byte)
#define DEST_ADDR_TYPE_MASK 0x0c ///< Mask of bits containing destination address type
#define DEST_ADDR_TYPE_EXTENDED 0x0c ///< Bits containing extended destination address type
#define DEST_ADDR_TYPE_NONE 0x00 ///< Bits containing not present destination address type
#define DEST_ADDR_TYPE_SHORT 0x08 ///< Bits containing short destination address type
#define DEST_ADDR_OFFSET 5 ///< Offset of destination address in Data frame
#define DEST_ADDR_OFFSET 6 ///< Offset of destination address in Data frame (+1 for frame length byte)
#define DSN_OFFSET 3 ///< Byte containing DSN value (+1 for frame length byte)
#define FRAME_PENDING_BIT (1 << 4) ///< Pending bit
#define FRAME_PENDING_OFFSET 1 ///< Byte containing pending bit (+1 for frame length byte)
#define FRAME_PENDING_BIT (1 << 4) ///< Pending bit
#define FRAME_TYPE_OFFSET 1 ///< Byte containing frame type bits (+1 for frame length byte)
#define FRAME_TYPE_MASK 0x07 ///< Mask of bits containing frame type
#define FRAME_TYPE_ACK 0x02 ///< Bits containing ACK frame type
#define FRAME_TYPE_BEACON 0x00 ///< Bits containing Beacon frame type
#define FRAME_TYPE_COMMAND 0x03 ///< Bits containing Command frame type
#define FRAME_TYPE_DATA 0x01 ///< Bits containing Data frame type
#define FRAME_TYPE_MASK 0x07 ///< Mask of bits containing frame type
#define FRAME_TYPE_OFFSET 1 ///< Byte containing frame type bits (+1 for frame length byte)
#define FRAME_TYPE_EXTENDED 0x07 ///< Bits containing Extended frame type
#define FRAME_TYPE_FRAGMENT 0x06 ///< Bits containing Fragment or Frak frame type
#define FRAME_TYPE_MULTIPURPOSE 0x05 ///< Bits containing Multipurpose frame type
#define FRAME_VERSION_OFFSET 2 ///< Byte containing frame version bits (+1 for frame length byte)
#define FRAME_VERSION_MASK 0x30 ///< Mask of bits containing frame version
#define FRAME_VERSION_0 0x00 ///< Bits containing frame version 0b00
#define FRAME_VERSION_1 0x10 ///< Bits containing frame version 0b01
#define FRAME_VERSION_2 0x20 ///< Bits containing frame version 0b10
#define FRAME_VERSION_3 0x30 ///< Bits containing frame version 0b11
#define PAN_ID_COMPR_OFFSET 1 ///< Byte containing Pan Id compression bit (+1 for frame length byte)
#define PAN_ID_COMPR_MASK 0x40 ///< Pan Id compression bit
#define PAN_ID_OFFSET 3 ///< Offset of Pan Id in Data frame
#define PAN_ID_OFFSET 4 ///< Offset of Pan Id in Data frame (+1 for frame length byte)
#define SRC_ADDR_TYPE_EXTENDED 0xc0 ///< Bits containing extended source address type
#define SRC_ADDR_TYPE_NONE 0x00 ///< Bits containing not present source address type
#define SRC_ADDR_TYPE_MASK 0xc0 ///< Mask of bits containing source address type
#define SRC_ADDR_TYPE_OFFSET 2 ///< Byte containing source address type (+1 for frame length byte)
#define SRC_ADDR_TYPE_SHORT 0x80 ///< Bits containing short source address type
#define SRC_ADDR_OFFSET_SHORT_DST 8 ///< Offset of source address in Data frame if destination address is short
#define SRC_ADDR_OFFSET_EXTENDED_DST 14 ///< Offset of source address in Data frame if destination address is extended
#define PHR_SIZE 1 ///< Size of PHR field
#define FCF_SIZE 2 ///< Size of FCF field
#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 ACK_LENGTH 5 ///< Length of ACK frame
#define MAX_PACKET_SIZE 127 ///< Maximal size of radio packet
#define TURNAROUND_TIME 192UL ///< aTurnaroundTime [us]
#define CCA_TIME 128UL ///< aCcaTime [us]
#define UNIT_BACKOFF_PERIOD (TURNAROUND_TIME + CCA_TIME) ///< aUnitBackoffPeriod [us]
#define PHY_US_PER_SYMBOL 16 ///< Duration of single symbol in microseconds [us]
#define PHY_SYMBOLS_PER_OCTET 2 ///< Number of symbols in single byte (octet)
#define PHY_SHR_DURATION 10 ///< Number of symbols in Synchronization Header (SHR)
#define ED_MIN_DBM (-94) ///< dBm value corresponding to value 0 in EDSAMPLE register
#define ED_RESULT_FACTOR 4 ///< Factor needed to calculate ED result based on data from RADIO peripheral
#define ED_RESULT_MAX 0xff ///< Maximal ED result
#define BROADCAST_ADDRESS ((uint8_t [SHORT_ADDRESS_SIZE]) {0xff, 0xff}) ///< Broadcast Short Address
typedef enum
{
REQ_ORIG_HIGHER_LAYER,
REQ_ORIG_CORE,
REQ_ORIG_RAAL,
#if NRF_802154_CSMA_CA_ENABLED
REQ_ORIG_CSMA_CA,
#endif // NRF_802154_CSMA_CA_ENABLED
#if NRF_802154_ACK_TIMEOUT_ENABLED
REQ_ORIG_ACK_TIMEOUT,
#endif // NRF_802154_ACK_TIMEOUT_ENABLED
} req_originator_t;
#endif // NRD_DRV_RADIO802154_CONST_H_
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,18 +29,20 @@
*/
/**
* @brief This module contains Finite State Machine of nRF 802.15.4 radio driver.
* @brief This module contains core of the nRF IEEE 802.15.4 radio driver.
*
*/
#ifndef NRF_DRV_RADIO802154_FSM_H_
#define NRF_DRV_RADIO802154_FSM_H_
#ifndef NRF_802154_CORE_H_
#define NRF_802154_CORE_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154_config.h"
#include "nrf_drv_radio802154_rx_buffer.h"
#include "nrf_802154_config.h"
#include "nrf_802154_notification.h"
#include "nrf_802154_rx_buffer.h"
#include "nrf_802154_types.h"
#ifdef __cplusplus
extern "C" {
@@ -52,47 +54,44 @@ extern "C" {
typedef enum
{
// Sleep
RADIO_STATE_DISABLING, // Entering low power (DISABLED) mode
RADIO_STATE_SLEEP, // Low power (DISABLED) mode
RADIO_STATE_SLEEP, ///< Low power (DISABLED) mode - the only state in which HF clock is released and RAAL disabled.
RADIO_STATE_FALLING_ASLEEP, ///< Prior entering SLEEP state RAAL and HF clock are active.
// 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_RX, ///< Receiver is enabled and it is receiving frames.
RADIO_STATE_TX_ACK, ///< Received frame and transmitting ACK.
// Transmit
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
RADIO_STATE_CCA_TX, ///< Performing CCA followed by frame transmission.
RADIO_STATE_TX, ///< 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
RADIO_STATE_CCA, ///< Performing CCA procedure.
// Continuous carrier
RADIO_STATE_CONTINUOUS_CARRIER, // Emitting continuous carrier wave.
RADIO_STATE_CONTINUOUS_CARRIER, ///< Emitting continuous carrier wave.
} radio_state_t;
/**
* @brief Initialize 802.15.4 driver FSM.
* @brief Initialize 802.15.4 driver core.
*/
void nrf_drv_radio802154_fsm_init(void);
void nrf_802154_core_init(void);
/**
* @brief Deinitialize 802.15.4 driver FSM.
* @brief Deinitialize 802.15.4 driver core.
*/
void nrf_drv_radio802154_fsm_deinit(void);
void nrf_802154_core_deinit(void);
/**
* @brief Get current state of nRF 802.15.4 driver.
*
* @return Current state of the 802.15.4 driver.
*/
radio_state_t nrf_drv_radio802154_fsm_state_get(void);
radio_state_t nrf_802154_core_state_get(void);
/***************************************************************************************************
* @section State machine transition requests
@@ -104,12 +103,12 @@ radio_state_t nrf_drv_radio802154_fsm_state_get(void);
* @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 state.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
*
* @retval true Entering SLEEP state succeeded.
* @retval false Entering SLEEP state failed (driver is performing other procedure).
*/
bool nrf_drv_radio802154_fsm_sleep(void);
bool nrf_802154_core_sleep(nrf_802154_term_t term_lvl);
/**
* @brief Request transition to RECEIVE state.
@@ -117,12 +116,17 @@ bool nrf_drv_radio802154_fsm_sleep(void);
* @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 TRANSMIT state.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @param[in] notify_function Function called to notify status of this procedure instead of
* default notification. If NULL default notification is used.
*
* @retval true Entering RECEIVE state succeeded.
* @retval false Entering RECEIVE state failed (driver is performing other procedure).
*/
bool nrf_drv_radio802154_fsm_receive(void);
bool nrf_802154_core_receive(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
nrf_802154_notification_func_t notify_function);
/**
* @brief Request transition to TRANSMIT state.
@@ -130,15 +134,21 @@ bool nrf_drv_radio802154_fsm_receive(void);
* @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 state.
*
* @param[in] p_data Pointer to a frame to transmit.
* @param[in] cca If the driver should perform CCA procedure before transmission.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @param[in] p_data Pointer to a frame to transmit.
* @param[in] cca If the driver should perform CCA procedure before transmission.
* @param[in] notify_function Function called to notify status of this procedure instead of
* default notification. If NULL default notification is used.
*
* @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, bool cca);
bool nrf_802154_core_transmit(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
const uint8_t * p_data,
bool cca,
nrf_802154_notification_func_t notify_function);
/**
* @brief Request transition to ENERGY_DETECTION state.
@@ -149,12 +159,13 @@ bool nrf_drv_radio802154_fsm_transmit(const uint8_t * p_data, bool cca);
* @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] time_us Minimal time of energy detection procedure.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @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(uint32_t time_us);
bool nrf_802154_core_energy_detection(nrf_802154_term_t term_lvl, uint32_t time_us);
/**
* @brief Request transition to CCA state.
@@ -162,13 +173,12 @@ bool nrf_drv_radio802154_fsm_energy_detection(uint32_t time_us);
* @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.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
*
* @retval true Entering CCA state succeeded.
* @retval false Entering CCA state failed (driver is performing other procedure).
*/
bool nrf_drv_radio802154_fsm_cca(void);
bool nrf_802154_core_cca(nrf_802154_term_t term_lvl);
/**
* @brief Request transition to CONTINUOUS_CARRIER state.
@@ -176,54 +186,53 @@ bool nrf_drv_radio802154_fsm_cca(void);
* @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.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
*
* @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);
bool nrf_802154_core_continuous_carrier(nrf_802154_term_t term_lvl);
/***************************************************************************************************
* @section State machine notifications
**************************************************************************************************/
/**
* @brief Notify the FSM that higher layer freed a frame buffer.
* @brief Notify the Core module that higher layer freed a frame buffer.
*
* 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.
* When there were no free buffers available the core does not start receiver. If core receives this
* notification it changes internal state to make sure receiver is started if requested.
*
* @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.
* @param[in] p_data Pointer to buffer that has been freed.
*/
void nrf_drv_radio802154_fsm_notify_buffer_free(rx_buffer_t * p_buffer);
bool nrf_802154_core_notify_buffer_free(uint8_t * p_data);
/**
* @brief Notify the FSM that next higher layer requested change of the channel.
* @brief Notify the Core module 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
* Core 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);
bool nrf_802154_core_channel_update(void);
/**
* @brief Notify the FSM that next higher layer requested change of the CCA configuration.
* @brief Notify the Core module that next higher layer requested change of the CCA configuration.
*/
void nrf_drv_radio802154_fsm_cca_cfg_update(void);
bool nrf_802154_core_cca_cfg_update(void);
#if !NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
#if !NRF_802154_INTERNAL_IRQ_HANDLING
/**
* @brief Notify the FSM that there is a pending IRQ that should be handled.
* @brief Notify the Core module that there is a pending IRQ that should be handled.
*/
void nrf_drv_radio802154_fsm_irq_handler(void);
#endif // !NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
void nrf_802154_core_irq_handler(void);
#endif // !NRF_802154_INTERNAL_IRQ_HANDLING
#ifdef __cplusplus
}
#endif
#endif /* NRF_DRV_RADIO802154_FSM_H_ */
#endif /* NRF_802154_CORE_H_ */
@@ -0,0 +1,185 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements hooks for the 802.15.4 driver Core module.
*
* Hooks are used by optional driver features to modify way in which notifications are propagated
* through the driver.
*
*/
#include "nrf_802154_core_hooks.h"
#include <stdbool.h>
#include "mac_features/nrf_802154_ack_timeout.h"
#include "mac_features/nrf_802154_csma_ca.h"
#include "nrf_802154_config.h"
#include "nrf_802154_types.h"
typedef bool (* abort_hook)(nrf_802154_term_t term_lvl, req_originator_t req_orig);
typedef void (* transmitted_hook)(const uint8_t * p_frame);
typedef bool (* tx_failed_hook)(const uint8_t * p_frame, nrf_802154_tx_error_t error);
typedef bool (* tx_started_hook)(const uint8_t * p_frame);
/* Since some compilers do not allow empty initializers for arrays with unspecified bounds,
* NULL pointer is appended to below arrays if the compiler used is not GCC. It is intentionally
* unused, but it prevents the arrays from being empty. GCC manages to optimize empty arrays away,
* so such a solution is unnecessary. */
static const abort_hook m_abort_hooks[] =
{
#if NRF_802154_CSMA_CA_ENABLED
nrf_802154_csma_ca_abort,
#endif
#if NRF_802154_ACK_TIMEOUT_ENABLED
nrf_802154_ack_timeout_abort,
#endif
NULL,
};
static const transmitted_hook m_transmitted_hooks[] =
{
#if NRF_802154_ACK_TIMEOUT_ENABLED
nrf_802154_ack_timeout_transmitted_hook,
#endif
NULL,
};
static const tx_failed_hook m_tx_failed_hooks[] =
{
#if NRF_802154_CSMA_CA_ENABLED
nrf_802154_csma_ca_tx_failed_hook,
#endif
#if NRF_802154_ACK_TIMEOUT_ENABLED
nrf_802154_ack_timeout_tx_failed_hook,
#endif
NULL,
};
static const tx_started_hook m_tx_started_hooks[] =
{
#if NRF_802154_CSMA_CA_ENABLED
nrf_802154_csma_ca_tx_started_hook,
#endif
#if NRF_802154_ACK_TIMEOUT_ENABLED
nrf_802154_ack_timeout_tx_started_hook,
#endif
NULL,
};
bool nrf_802154_core_hooks_terminate(nrf_802154_term_t term_lvl, req_originator_t req_orig)
{
bool result = true;
for (uint32_t i = 0; i < sizeof(m_abort_hooks) / sizeof(m_abort_hooks[0]); i++)
{
if (m_abort_hooks[i] == NULL)
{
break;
}
result = m_abort_hooks[i](term_lvl, req_orig);
if (!result)
{
break;
}
}
return result;
}
void nrf_802154_core_hooks_transmitted(const uint8_t * p_frame)
{
for (uint32_t i = 0; i < sizeof(m_transmitted_hooks) / sizeof(m_transmitted_hooks[0]); i++)
{
if (m_transmitted_hooks[i] == NULL)
{
break;
}
m_transmitted_hooks[i](p_frame);
}
}
bool nrf_802154_core_hooks_tx_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
bool result = true;
for (uint32_t i = 0; i < sizeof(m_tx_failed_hooks) / sizeof(m_tx_failed_hooks[0]); i++)
{
if (m_tx_failed_hooks[i] == NULL)
{
break;
}
result = m_tx_failed_hooks[i](p_frame, error);
if (!result)
{
break;
}
}
return result;
}
bool nrf_802154_core_hooks_tx_started(const uint8_t * p_frame)
{
bool result = true;
for (uint32_t i = 0; i < sizeof(m_tx_started_hooks) / sizeof(m_tx_started_hooks[0]); i++)
{
if (m_tx_started_hooks[i] == NULL)
{
break;
}
result = m_tx_started_hooks[i](p_frame);
if (!result)
{
break;
}
}
return result;
}
@@ -0,0 +1,95 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_802154_CORE_HOOKS_H__
#define NRF_802154_CORE_HOOKS_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_const.h"
#include "nrf_802154_types.h"
/**
* @defgroup nrf_802154_hooks Hooks for the 802.15.4 driver core
* @{
* @ingroup nrf_802154
* @brief Hooks for the 802.15.4 driver core module.
*
* Hooks are used by optional driver features to modify way in which notifications are propagated
* through the driver.
*/
/**
* @brief Process hooks for the terminate request.
*
* @param[in] term_lvl Termination level of request that terminates current operation.
* @param[in] req_orig Module that originates this request.
*
* @retval true All procedures are aborted.
* @retval false There is ongoing procedure that cannot be aborted due to too low @p priority.
*/
bool nrf_802154_core_hooks_terminate(nrf_802154_term_t term_lvl, req_originator_t req_orig);
/**
* @brief Process hooks for the transmitted event.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that was transmitted.
*/
void nrf_802154_core_hooks_transmitted(const uint8_t * p_frame);
/**
* @brief Process hooks for the TX failed event.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that was not transmitted.
* @param[in] error Cause of failed transmission.
*
* @retval true TX failed event should be propagated to the MAC layer.
* @retval false TX failed event should not be propagated to the MAC layer. It is handled
* internally.
*/
bool nrf_802154_core_hooks_tx_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error);
/**
* @brief Process hooks for the TX started event.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that is being transmitted.
*
* @retval true TX started event should be propagated to the MAC layer.
* @retval false TX started event should not be propagated to the MAC layer. It is handled
* internally.
*/
bool nrf_802154_core_hooks_tx_started(const uint8_t * p_frame);
/**
*@}
**/
#endif // NRF_802154_CORE_HOOKS_H__
@@ -0,0 +1,220 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements critical sections used with requests by 802.15.4 driver.
*
*/
#include "nrf_802154_critical_section.h"
#include <assert.h>
#include <stdint.h>
#include "nrf_802154_config.h"
#include "nrf_802154_debug.h"
#include "hal/nrf_radio.h"
#include "platform/timer/nrf_802154_timer.h"
#include "raal/nrf_raal_api.h"
#include <nrf.h>
#define CMSIS_IRQ_NUM_VECTACTIVE_DIFF 16
#define NESTED_CRITICAL_SECTION_ALLOWED_PRIORITY_NONE (-1)
static volatile uint8_t m_nested_critical_section_counter; ///< Counter of nested critical sections
static volatile int8_t m_nested_critical_section_allowed_priority; ///< Indicator if nested critical sections are currently allowed
/** @brief Enter critical section for RADIO peripheral
*
* @note RADIO peripheral registers (and NVIC) are modified only when timeslot is granted for the
* 802.15.4 driver.
*/
static void radio_critical_section_enter(void)
{
if (nrf_raal_timeslot_is_granted())
{
NVIC_DisableIRQ(RADIO_IRQn);
__DSB();
__ISB();
}
}
/** @brief Exit critical section for RADIO peripheral
*
* @note RADIO peripheral registers (and NVIC) are modified only when timeslot is granted for the
* 802.15.4 driver.
*/
static void radio_critical_section_exit(void)
{
if (nrf_raal_timeslot_is_granted())
{
NVIC_EnableIRQ(RADIO_IRQn);
}
}
/** @brief Convert active priority value to int8_t type.
*
* @param[in] active_priority Active priority in uint32_t format
*
* @return Active_priority value in int8_t format.
*/
static int8_t active_priority_convert(uint32_t active_priority)
{
return active_priority == UINT32_MAX ? INT8_MAX : (int8_t)active_priority;
}
/** @brief Check if active vector priority is equal to priority that allows nested crit sections.
*
* @retval true Active vector priority allows nested critical sections.
* @retval false Active vector priority denies nested critical sections.
*/
static bool nested_critical_section_is_allowed_in_this_context(void)
{
return m_nested_critical_section_allowed_priority ==
active_priority_convert(
nrf_802154_critical_section_active_vector_priority_get());
}
static bool critical_section_enter(bool forced)
{
bool result = true;
uint8_t cnt;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_CRIT_SECT_ENTER);
do
{
cnt = __LDREXB(&m_nested_critical_section_counter);
assert(cnt < UINT8_MAX);
if (!forced && cnt > 0 && !nested_critical_section_is_allowed_in_this_context())
{
__CLREX();
result = false;
break;
}
radio_critical_section_enter();
nrf_raal_critical_section_enter();
}
while (__STREXB(cnt + 1, &m_nested_critical_section_counter));
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_CRIT_SECT_ENTER);
return result;
}
void nrf_802154_critical_section_init(void)
{
m_nested_critical_section_counter = 0;
m_nested_critical_section_allowed_priority = NESTED_CRITICAL_SECTION_ALLOWED_PRIORITY_NONE;
}
bool nrf_802154_critical_section_enter(void)
{
return critical_section_enter(false);
}
void nrf_802154_critical_section_forcefully_enter(void)
{
bool critical_section_entered = critical_section_enter(true);
assert(critical_section_entered);
}
void nrf_802154_critical_section_exit(void)
{
uint8_t cnt;
static bool exiting_crit_sect;
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_CRIT_SECT_EXIT);
do
{
cnt = __LDREXB(&m_nested_critical_section_counter);
assert(cnt > 0);
if (cnt == 1)
{
assert(!exiting_crit_sect);
exiting_crit_sect = true;
// RAAL critical section shall be exited before RADIO IRQ handler is enabled. In other
// case RADIO IRQ handler may be called out of timeslot.
nrf_raal_critical_section_exit();
radio_critical_section_exit();
exiting_crit_sect = false;
}
}
while (__STREXB(cnt - 1, &m_nested_critical_section_counter));
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_CRIT_SECT_EXIT);
}
void nrf_802154_critical_section_nesting_allow(void)
{
assert(m_nested_critical_section_allowed_priority ==
NESTED_CRITICAL_SECTION_ALLOWED_PRIORITY_NONE);
m_nested_critical_section_allowed_priority = active_priority_convert(
nrf_802154_critical_section_active_vector_priority_get());
}
void nrf_802154_critical_section_nesting_deny(void)
{
assert(m_nested_critical_section_allowed_priority >= 0);
m_nested_critical_section_allowed_priority = NESTED_CRITICAL_SECTION_ALLOWED_PRIORITY_NONE;
}
uint32_t nrf_802154_critical_section_active_vector_priority_get(void)
{
uint32_t active_vector_id = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
IRQn_Type irq_number;
uint32_t active_priority;
// Check if this function is called from main thread.
if (active_vector_id == 0)
{
return UINT32_MAX;
}
assert(active_vector_id >= CMSIS_IRQ_NUM_VECTACTIVE_DIFF);
irq_number = (IRQn_Type)(active_vector_id - CMSIS_IRQ_NUM_VECTACTIVE_DIFF);
active_priority = NVIC_GetPriority(irq_number);
return active_priority;
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,8 +28,8 @@
*
*/
#ifndef NRF_DRIVER_RADIO802154_CRITICAL_SECTION_H__
#define NRF_DRIVER_RADIO802154_CRITICAL_SECTION_H__
#ifndef NRF_802154_CRITICAL_SECTION_H__
#define NRF_802154_CRITICAL_SECTION_H__
#include <stdbool.h>
#include <stdint.h>
@@ -39,21 +39,62 @@ extern "C" {
#endif
/**
* @defgroup nrf_driver_radio802154_critical_section 802.15.4 driver critical section
* @defgroup nrf_802154_critical_section 802.15.4 driver critical section
* @{
* @ingroup nrf_driver_radio802154
* @ingroup nrf_802154
* @brief Critical section used with requests to the 802.15.4 driver.
*/
/**
* @brief Enter critical section in the 802.15.4 driver.
* @brief Initialize critical section module.
*/
void nrf_drv_radio802154_critical_section_enter(void);
void nrf_802154_critical_section_init(void);
/**
* @brief Enter critical section in the 802.15.4 driver.
*
* @note Entering critical section may be prohibited at given time. If critical section is not
* entered, request should not be proceeded.
*
* @retval true Entered critical section.
* @retval false Could not enter critical section.
*/
bool nrf_802154_critical_section_enter(void);
/**
* @brief Exit critical section in the 802.15.4 driver.
*/
void nrf_drv_radio802154_critical_section_exit(void);
void nrf_802154_critical_section_exit(void);
/**
* @brief Forcefully enter critical section in the 802.15.4 driver.
*
* This function enters critical section regardless critical sections is already entered.
*
* This function is intended to be used by RADIO IRQ handler and RAAL notifications handlers to
* prevent interrupting of these procedures by FSM requests from higher priority IRQ handlers.
*/
void nrf_802154_critical_section_forcefully_enter(void);
/**
* @brief Allow entering nested critical section.
*
* This function is intended to be used with notification module in order to allow processing
* requests called from notification context.
*/
void nrf_802154_critical_section_nesting_allow(void);
/**
* @brief Disallow entering nested critical section.
*/
void nrf_802154_critical_section_nesting_deny(void);
/**
* @brief Get current IRQ priority.
*
* @return IRQ priority
*/
uint32_t nrf_802154_critical_section_active_vector_priority_get(void);
/**
*@}
@@ -63,4 +104,4 @@ void nrf_drv_radio802154_critical_section_exit(void);
}
#endif
#endif // NRF_DRIVER_RADIO802154_CRITICAL_SECTION_H__
#endif // NRF_802154_CRITICAL_SECTION_H__
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
*
*/
#include "nrf_drv_radio802154_debug.h"
#include "nrf_802154_debug.h"
#include <stdint.h>
@@ -45,9 +45,9 @@
#if ENABLE_DEBUG_LOG
/// Buffer used to store debug log messages.
volatile uint32_t nrf_drv_radio802154_debug_log_buffer[NRF_DRV_RADIO802154_DEBUG_LOG_BUFFER_LEN];
volatile uint32_t nrf_802154_debug_log_buffer[NRF_802154_DEBUG_LOG_BUFFER_LEN];
/// Index of the log buffer pointing to the element that should be filled with next log message.
volatile uint32_t nrf_drv_radio802154_debug_log_ptr = 0;
volatile uint32_t nrf_802154_debug_log_ptr = 0;
#endif
#if ENABLE_DEBUG_GPIO
@@ -129,7 +129,7 @@ static void raal_softdevice_event_gpio_toggle_init(void)
}
#endif // ENABLE_DEBUG_GPIO
void nrf_drv_radio802154_debug_init(void)
void nrf_802154_debug_init(void)
{
#if ENABLE_DEBUG_GPIO
radio_event_gpio_toggle_init();
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
*
*/
#ifndef NRF_DRV_RADIO802154_DEBUG_H_
#define NRF_DRV_RADIO802154_DEBUG_H_
#ifndef NRF_802154_DEBUG_H_
#define NRF_802154_DEBUG_H_
#include <stdint.h>
@@ -42,12 +42,10 @@
extern "C" {
#endif
#define NRF_DRV_RADIO802154_DEBUG_LOG_BUFFER_LEN 1024
#define NRF_802154_DEBUG_LOG_BUFFER_LEN 1024
#define EVENT_TRACE_ENTER 0x0001UL
#define EVENT_TRACE_EXIT 0x0002UL
#define EVENT_MUTEX_LOCK 0x0003UL
#define EVENT_MUTEX_UNLOCK 0x0004UL
#define EVENT_SET_STATE 0x0005UL
#define EVENT_RADIO_RESET 0x0006UL
@@ -58,6 +56,7 @@ extern "C" {
#define FUNCTION_BUFFER_FREE 0x0005UL
#define FUNCTION_CCA 0x0006UL
#define FUNCTION_CONTINUOUS_CARRIER 0x0007UL
#define FUNCTION_CSMACA 0x0008UL
#define FUNCTION_IRQ_HANDLER 0x0100UL
#define FUNCTION_EVENT_FRAMESTART 0x0101UL
@@ -69,6 +68,8 @@ extern "C" {
#define FUNCTION_EVENT_CCABUSY 0x0107UL
#define FUNCTION_EVENT_EDEND 0x0108UL
#define FUNCTION_EVENT_PHYEND 0x0109UL
#define FUNCTION_EVENT_CRCOK 0x010AUL
#define FUNCTION_EVENT_CRCERROR 0x010BUL
#define FUNCTION_AUTO_ACK_ABORT 0x0201UL
#define FUNCTION_TIMESLOT_STARTED 0x0202UL
@@ -108,48 +109,48 @@ extern "C" {
#define PIN_DBG_RTC0_EVT_REM 31
#if ENABLE_DEBUG_LOG
extern volatile uint32_t nrf_drv_radio802154_debug_log_buffer[
NRF_DRV_RADIO802154_DEBUG_LOG_BUFFER_LEN];
extern volatile uint32_t nrf_drv_radio802154_debug_log_ptr;
extern volatile uint32_t nrf_802154_debug_log_buffer[
NRF_802154_DEBUG_LOG_BUFFER_LEN];
extern volatile uint32_t nrf_802154_debug_log_ptr;
#define nrf_drv_radio802154_log(EVENT_CODE, EVENT_ARG) \
#define nrf_802154_log(EVENT_CODE, EVENT_ARG) \
do { \
uint32_t ptr = nrf_drv_radio802154_debug_log_ptr; \
nrf_drv_radio802154_debug_log_buffer[ptr] = ((EVENT_CODE) | ((EVENT_ARG) << 16)); \
nrf_drv_radio802154_debug_log_ptr = \
ptr < (NRF_DRV_RADIO802154_DEBUG_LOG_BUFFER_LEN - 1) ? ptr + 1 : 0; \
uint32_t ptr = nrf_802154_debug_log_ptr; \
nrf_802154_debug_log_buffer[ptr] = ((EVENT_CODE) | ((EVENT_ARG) << 16)); \
nrf_802154_debug_log_ptr = \
ptr < (NRF_802154_DEBUG_LOG_BUFFER_LEN - 1) ? ptr + 1 : 0; \
} while (0)
#else // ENABLE_DEBUG_LOG
#define nrf_drv_radio802154_log(EVENT_CODE, EVENT_ARG)
#define nrf_802154_log(EVENT_CODE, EVENT_ARG)
#endif // ENABLE_DEBUG_LOG
#if ENABLE_DEBUG_GPIO
#define nrf_drv_radio802154_pin_set(pin) NRF_P0->OUTSET = (1UL << (pin))
#define nrf_drv_radio802154_pin_clr(pin) NRF_P0->OUTCLR = (1UL << (pin))
#define nrf_drv_radio802154_pin_tgl(pin) do { volatile uint32_t ps = NRF_P0->OUT; \
NRF_P0->OUTSET = (~ps & (1UL << (pin))); \
NRF_P0->OUTCLR = (ps & (1UL << (pin))); \
#define nrf_802154_pin_set(pin) NRF_P0->OUTSET = (1UL << (pin))
#define nrf_802154_pin_clr(pin) NRF_P0->OUTCLR = (1UL << (pin))
#define nrf_802154_pin_tgl(pin) do { volatile uint32_t ps = NRF_P0->OUT; \
NRF_P0->OUTSET = (~ps & (1UL << (pin))); \
NRF_P0->OUTCLR = (ps & (1UL << (pin))); \
} while(0);
#else // ENABLE_DEBUG_GPIO
#define nrf_drv_radio802154_pin_set(pin)
#define nrf_drv_radio802154_pin_clr(pin)
#define nrf_drv_radio802154_pin_tgl(pin)
#define nrf_802154_pin_set(pin)
#define nrf_802154_pin_clr(pin)
#define nrf_802154_pin_tgl(pin)
#endif // ENABLE_DEBUG_GPIO
/**
* @brief Initialize debug helpers for nRF 802.15.4 driver.
*/
void nrf_drv_radio802154_debug_init(void);
void nrf_802154_debug_init(void);
#ifdef __cplusplus
}
#endif
#endif /* NRF_DRV_RADIO802154_DEBUG_H_ */
#endif /* NRF_802154_DEBUG_H_ */
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,29 +28,39 @@
*
*/
#ifndef NRF_DRIVER_RADIO802154_NOTIFICATION_H__
#define NRF_DRIVER_RADIO802154_NOTIFICATION_H__
#ifndef NRF_802154_NOTIFICATION_H__
#define NRF_802154_NOTIFICATION_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154.h"
#include "nrf_802154.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_driver_radio802154_notification 802.15.4 driver notification
* @defgroup nrf_802154_notification 802.15.4 driver notification
* @{
* @ingroup nrf_driver_radio802154
* @ingroup nrf_802154
* @brief Notifications to the next higher layer triggered from 802.15.4 radio driver.
*/
/**
* @brief Function type used for external notification
*
* This function is called instead of default notification. Function is passed to request to notify
* atomically during request processing.
*
* @param[in] result If called request succeeded.
*/
typedef void (*nrf_802154_notification_func_t)(bool result);
/**
* @brief Initialize notification module.
*/
void nrf_drv_radio802154_notification_init(void);
void nrf_802154_notification_init(void);
/**
* @brief Notify next higher layer that a frame was received.
@@ -59,44 +69,65 @@ void nrf_drv_radio802154_notification_init(void);
* @param[in] power RSSI measured during the frame reception.
* @param[in] lqi LQI indicating measured link quality during the frame reception.
*/
void nrf_drv_radio802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi);
void nrf_802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi);
/**
* @brief Notify next higher layer that reception of a frame failed.
*
* @param[in] error An error code that indicates reason of the failure.
*/
void nrf_drv_radio802154_notify_receive_failed(nrf_drv_radio802154_rx_error_t error);
void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error);
/**
* @brief Notify next higher layer that a frame was transmitted.
*
* @param[in] p_ack Pointer to buffer containing PSDU of ACK frame. NULL if ACK was not requested.
* @param[in] power RSSI of received frame or 0 if ACK was not requested.
* @param[in] lqi LQI of received frame of 0 if ACK was not requested.
* @param[in] p_frame Pointer to buffer containing PSDU of transmitted frame.
* @param[in] p_ack Pointer to buffer containing PSDU of ACK frame. NULL if ACK was not
* requested.
* @param[in] power RSSI of received frame or 0 if ACK was not requested.
* @param[in] lqi LQI of received frame of 0 if ACK was not requested.
*/
void nrf_drv_radio802154_notify_transmitted(uint8_t * p_ack, int8_t power, int8_t lqi);
void nrf_802154_notify_transmitted(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
int8_t lqi);
/**
* @brief Notify next higher layer that a frame was not transmitted.
*
* @param[in] error An error code indicating reason of the failure.
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that failed transmit
* operation.
* @param[in] error An error code indicating reason of the failure.
*/
void nrf_drv_radio802154_notify_transmit_failed(nrf_drv_radio802154_tx_error_t error);
void nrf_802154_notify_transmit_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error);
/**
* @brief Notify next higher layer that energy detection procedure ended.
*
* @param[in] result Detected energy level.
*/
void nrf_drv_radio802154_notify_energy_detected(uint8_t result);
void nrf_802154_notify_energy_detected(uint8_t result);
/**
* @brief Notify next higher layer that energy detection procedure failed.
*
* @param[in] error An error code indicating reason of the failure.
*/
void nrf_802154_notify_energy_detection_failed(nrf_802154_ed_error_t error);
/**
* @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);
void nrf_802154_notify_cca(bool is_free);
/**
* @brief Notify next higher layer that CCA procedure failed.
*
* @param[in] error An error code indicating reason of the failure.
*/
void nrf_802154_notify_cca_failed(nrf_802154_cca_error_t error);
/**
*@}
@@ -106,4 +137,4 @@ void nrf_drv_radio802154_notify_cca(bool is_free);
}
#endif
#endif // NRF_DRIVER_RADIO802154_NOTIFICATION_H__
#endif // NRF_802154_NOTIFICATION_H__
@@ -0,0 +1,110 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements notifications triggered directly by the nrf 802.15.4 radio driver.
*
*/
#include "nrf_802154_notification.h"
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154.h"
#include "nrf_802154_critical_section.h"
#define RAW_LENGTH_OFFSET 0
#define RAW_PAYLOAD_OFFSET 1
void nrf_802154_notification_init(void)
{
// Intentionally empty
}
void nrf_802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi)
{
#if NRF_802154_USE_RAW_API
nrf_802154_received_raw(p_data, power, lqi);
#else // NRF_802154_USE_RAW_API
nrf_802154_received(p_data + RAW_PAYLOAD_OFFSET, p_data[RAW_LENGTH_OFFSET], power, lqi);
#endif // NRF_802154_USE_RAW_API
}
void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error)
{
nrf_802154_receive_failed(error);
}
void nrf_802154_notify_transmitted(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
int8_t lqi)
{
#if NRF_802154_USE_RAW_API
nrf_802154_transmitted_raw(p_frame, p_ack, power, lqi);
#else // NRF_802154_USE_RAW_API
nrf_802154_transmitted(p_frame + RAW_PAYLOAD_OFFSET,
p_ack + RAW_PAYLOAD_OFFSET,
p_ack[RAW_LENGTH_OFFSET],
power,
lqi);
#endif // NRF_802154_USE_RAW_API
}
void nrf_802154_notify_transmit_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
#if NRF_802154_USE_RAW_API
nrf_802154_transmit_failed(p_frame, error);
#else // NRF_802154_USE_RAW_API
nrf_802154_transmit_failed(p_frame + RAW_PAYLOAD_OFFSET, error);
#endif // NRF_802154_USE_RAW_API
}
void nrf_802154_notify_energy_detected(uint8_t result)
{
nrf_802154_energy_detected(result);
}
void nrf_802154_notify_energy_detection_failed(nrf_802154_ed_error_t error)
{
nrf_802154_energy_detection_failed(error);
}
void nrf_802154_notify_cca(bool is_free)
{
nrf_802154_cca_done(is_free);
}
void nrf_802154_notify_cca_failed(nrf_802154_cca_error_t error)
{
nrf_802154_cca_failed(error);
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,47 +34,60 @@
*
*/
#include "nrf_drv_radio802154_notification.h"
#include "nrf_802154_notification.h"
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154.h"
#include "nrf_drv_radio802154_swi.h"
#include "nrf_802154.h"
#include "nrf_802154_swi.h"
#include "raal/nrf_raal_api.h"
void nrf_drv_radio802154_notification_init(void)
void nrf_802154_notification_init(void)
{
nrf_drv_radio802154_swi_init();
nrf_802154_swi_init();
}
void nrf_drv_radio802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi)
void nrf_802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi)
{
nrf_drv_radio802154_swi_notify_received(p_data, power, lqi);
nrf_802154_swi_notify_received(p_data, power, lqi);
}
void nrf_drv_radio802154_notify_receive_failed(nrf_drv_radio802154_rx_error_t error)
void nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error)
{
nrf_drv_radio802154_swi_notify_receive_failed(error);
nrf_802154_swi_notify_receive_failed(error);
}
void nrf_drv_radio802154_notify_transmitted(uint8_t * p_ack, int8_t power, int8_t lqi)
void nrf_802154_notify_transmitted(const uint8_t * p_frame,
uint8_t * p_ack,
int8_t power,
int8_t lqi)
{
nrf_drv_radio802154_swi_notify_transmitted(p_ack, power, lqi);
nrf_802154_swi_notify_transmitted(p_frame, p_ack, power, lqi);
}
void nrf_drv_radio802154_notify_transmit_failed(nrf_drv_radio802154_tx_error_t error)
void nrf_802154_notify_transmit_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
nrf_drv_radio802154_swi_notify_transmit_failed(error);
nrf_802154_swi_notify_transmit_failed(p_frame, error);
}
void nrf_drv_radio802154_notify_energy_detected(uint8_t result)
void nrf_802154_notify_energy_detected(uint8_t result)
{
nrf_drv_radio802154_swi_notify_energy_detected(result);
nrf_802154_swi_notify_energy_detected(result);
}
void nrf_drv_radio802154_notify_cca(bool is_free)
void nrf_802154_notify_energy_detection_failed(nrf_802154_ed_error_t error)
{
nrf_drv_radio802154_swi_notify_cca(is_free);
nrf_802154_swi_notify_energy_detection_failed(error);
}
void nrf_802154_notify_cca(bool is_free)
{
nrf_802154_swi_notify_cca(is_free);
}
void nrf_802154_notify_cca_failed(nrf_802154_cca_error_t error)
{
nrf_802154_swi_notify_cca_failed(error);
}
@@ -0,0 +1,194 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements storage of PIB attributes in nRF 802.15.4 radio driver.
*
*/
#include "nrf_802154_pib.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_802154_config.h"
#include "nrf_802154_const.h"
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.
nrf_802154_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_802154_pib_data_t;
static nrf_802154_pib_data_t m_data; ///< Buffer containing PIB data.
void nrf_802154_pib_init(void)
{
m_data.promiscuous = false;
m_data.auto_ack = true;
m_data.channel = 11;
memset(m_data.pan_id, 0xff, sizeof(m_data.pan_id));
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 = NRF_802154_CCA_MODE_DEFAULT;
m_data.cca.ed_threshold = NRF_802154_CCA_ED_THRESHOLD_DEFAULT;
m_data.cca.corr_threshold = NRF_802154_CCA_CORR_THRESHOLD_DEFAULT;
m_data.cca.corr_limit = NRF_802154_CCA_CORR_LIMIT_DEFAULT;
}
bool nrf_802154_pib_promiscuous_get(void)
{
return m_data.promiscuous;
}
void nrf_802154_pib_promiscuous_set(bool enabled)
{
m_data.promiscuous = enabled;
}
bool nrf_802154_pib_auto_ack_get(void)
{
return m_data.auto_ack;
}
void nrf_802154_pib_auto_ack_set(bool enabled)
{
m_data.auto_ack = enabled;
}
uint8_t nrf_802154_pib_channel_get(void)
{
return m_data.channel;
}
void nrf_802154_pib_channel_set(uint8_t channel)
{
m_data.channel = channel;
}
int8_t nrf_802154_pib_tx_power_get(void)
{
return m_data.tx_power;
}
void nrf_802154_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;
}
const uint8_t * nrf_802154_pib_pan_id_get(void)
{
return m_data.pan_id;
}
void nrf_802154_pib_pan_id_set(const uint8_t * p_pan_id)
{
memcpy(m_data.pan_id, p_pan_id, PAN_ID_SIZE);
}
const uint8_t * nrf_802154_pib_extended_address_get(void)
{
return m_data.extended_addr;
}
void nrf_802154_pib_extended_address_set(const uint8_t * p_extended_address)
{
memcpy(m_data.extended_addr, p_extended_address, EXTENDED_ADDRESS_SIZE);
}
const uint8_t * nrf_802154_pib_short_address_get(void)
{
return m_data.short_addr;
}
void nrf_802154_pib_short_address_set(const uint8_t * p_short_address)
{
memcpy(m_data.short_addr, p_short_address, SHORT_ADDRESS_SIZE);
}
void nrf_802154_pib_cca_cfg_set(const nrf_802154_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_802154_pib_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg)
{
memcpy(p_cca_cfg, &m_data.cca, sizeof(m_data.cca));
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,13 +33,13 @@
*
*/
#ifndef NRF_DRV_RADIO802154_PIB_H_
#define NRF_DRV_RADIO802154_PIB_H_
#ifndef NRF_802154_PIB_H_
#define NRF_802154_PIB_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154.h"
#include "nrf_802154.h"
#ifdef __cplusplus
extern "C" {
@@ -48,7 +48,7 @@ extern "C" {
/**
* @brief Initialize this module.
*/
void nrf_drv_radio802154_pib_init(void);
void nrf_802154_pib_init(void);
/**
* @brief Check if promiscuous mode is enabled.
@@ -56,14 +56,14 @@ void nrf_drv_radio802154_pib_init(void);
* @retval true If promiscuous mode is enabled.
* @retval false If promiscuous mode is disabled.
*/
bool nrf_drv_radio802154_pib_promiscuous_get(void);
bool nrf_802154_pib_promiscuous_get(void);
/**
* @brief Enable or disable promiscuous mode.
*
* @param[in] enabled If promiscuous mode should be enabled.
*/
void nrf_drv_radio802154_pib_promiscuous_set(bool enabled);
void nrf_802154_pib_promiscuous_set(bool enabled);
/**
* @brief Check if auto ACK procedure is enabled.
@@ -71,14 +71,14 @@ void nrf_drv_radio802154_pib_promiscuous_set(bool enabled);
* @retval true If auto ACK procedure is enabled.
* @retval false If auto ACK procedure is disabled.
*/
bool nrf_drv_radio802154_pib_auto_ack_get(void);
bool nrf_802154_pib_auto_ack_get(void);
/**
* @brief Enable or disable auto ACK procedure.
*
* @param[in] enabled If auto ACK procedure should be enabled.
*/
void nrf_drv_radio802154_pib_auto_ack_set(bool enabled);
void nrf_802154_pib_auto_ack_set(bool enabled);
/**
@@ -86,28 +86,35 @@ void nrf_drv_radio802154_pib_auto_ack_set(bool enabled);
*
* @return Channel number used by the driver.
*/
uint8_t nrf_drv_radio802154_pib_channel_get(void);
uint8_t nrf_802154_pib_channel_get(void);
/**
* @brief Set channel that will be used by the driver.
*
* @param[in] channel Number of channel used by the driver.
*/
void nrf_drv_radio802154_pib_channel_set(uint8_t channel);
void nrf_802154_pib_channel_set(uint8_t channel);
/**
* @brief Get transmit power.
*
* @returns Transmit power [dBm].
*/
int8_t nrf_drv_radio802154_pib_tx_power_get(void);
int8_t nrf_802154_pib_tx_power_get(void);
/**
* @brief Set transmit power used for ACK frames.
*
* @param[in] dbm Transmit power [dBm].
*/
void nrf_drv_radio802154_pib_tx_power_set(int8_t dbm);
void nrf_802154_pib_tx_power_set(int8_t dbm);
/**
* @brief Get PAN Id used by this device.
*
* @returns Pointer to buffer containing PAN Id value (2 bytes, little-endian).
*/
const uint8_t * nrf_802154_pib_pan_id_get(void);
/**
* @brief Set PAN Id used by this device.
@@ -116,7 +123,14 @@ void nrf_drv_radio802154_pib_tx_power_set(int8_t dbm);
*
* This function makes copy of the PAN Id.
*/
void nrf_drv_radio802154_pib_pan_id_set(const uint8_t * p_pan_id);
void nrf_802154_pib_pan_id_set(const uint8_t * p_pan_id);
/**
* @brief Get Extended Address of this device
*
* @returns Pointer to buffer containing extended address (8 bytes, little-endian).
*/
const uint8_t * nrf_802154_pib_extended_address_get(void);
/**
* @brief Set Extended Address of this device.
@@ -125,7 +139,14 @@ void nrf_drv_radio802154_pib_pan_id_set(const uint8_t * p_pan_id);
*
* This function makes copy of the address.
*/
void nrf_drv_radio802154_pib_extended_address_set(const uint8_t * p_extended_address);
void nrf_802154_pib_extended_address_set(const uint8_t * p_extended_address);
/**
* @brief Get Short Address of this device
*
* @returns Pointer to buffer containing short address (2 bytes, little-endian).
*/
const uint8_t * nrf_802154_pib_short_address_get(void);
/**
* @brief Set Short Address of this device.
@@ -134,38 +155,25 @@ void nrf_drv_radio802154_pib_extended_address_set(const uint8_t * p_extended_add
*
* This function makes copy of the address.
*/
void nrf_drv_radio802154_pib_short_address_set(const uint8_t * p_short_address);
/**
* @brief Check if destination address in given frame matches address stored in this module or
* broadcast address.
*
* This function is intended to check if received frame is destined to this node.
*
* @param[in] p_psdu Pointer to PSDU of frame to check.
*
* @return If destination address in given PSDU matches address stored in this module or broadcast
* address.
*/
bool nrf_drv_radio802154_pib_dest_addr_matches(const uint8_t * p_psdu);
void nrf_802154_pib_short_address_set(const uint8_t * p_short_address);
/**
* @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);
void nrf_802154_pib_cca_cfg_set(const nrf_802154_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);
void nrf_802154_pib_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg);
#ifdef __cplusplus
}
#endif
#endif /* NRF_DRV_RADIO802154_PIB_H_ */
#endif /* NRF_802154_PIB_H_ */
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,17 +28,17 @@
*
*/
#ifndef NRF_DRIVER_RADIO802154_PRIORITY_DROP_H__
#define NRF_DRIVER_RADIO802154_PRIORITY_DROP_H__
#ifndef NRF_802154_PRIORITY_DROP_H__
#define NRF_802154_PRIORITY_DROP_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_driver_radio802154_priority_drop 802.15.4 driver procedures with lower priority.
* @defgroup nrf_802154_priority_drop 802.15.4 driver procedures with lower priority.
* @{
* @ingroup nrf_driver_radio802154
* @ingroup nrf_802154
* @brief Internal procedures of 802.15.4 driver that should be called with lower priority than
* the caller's priority.
*/
@@ -46,14 +46,14 @@ extern "C" {
/**
* @brief Initialize notification module.
*/
void nrf_drv_radio802154_priority_drop_init(void);
void nrf_802154_priority_drop_init(void);
/**
* @brief Request discarding of the timeslot.
*
* @note This function should be called through this module to prevent calling it from arbiter context.
*/
void nrf_drv_radio802154_priority_drop_timeslot_exit(void);
void nrf_802154_priority_drop_timeslot_exit(void);
/**
*@}
@@ -63,5 +63,5 @@ void nrf_drv_radio802154_priority_drop_timeslot_exit(void);
}
#endif
#endif // NRF_DRIVER_RADIO802154_PRIORITY_DROP_H__
#endif // NRF_802154_PRIORITY_DROP_H__
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,16 +35,16 @@
*
*/
#include "nrf_drv_radio802154_priority_drop.h"
#include "nrf_802154_priority_drop.h"
#include "raal/nrf_raal_api.h"
void nrf_drv_radio802154_priority_drop_init(void)
void nrf_802154_priority_drop_init(void)
{
// Intentionally empty
}
void nrf_drv_radio802154_priority_drop_timeslot_exit(void)
void nrf_802154_priority_drop_timeslot_exit(void)
{
nrf_raal_continuous_mode_exit();
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,17 +35,17 @@
*
*/
#include "nrf_drv_radio802154_priority_drop.h"
#include "nrf_802154_priority_drop.h"
#include "nrf_drv_radio802154_swi.h"
#include "nrf_802154_swi.h"
void nrf_drv_radio802154_priority_drop_init(void)
void nrf_802154_priority_drop_init(void)
{
nrf_drv_radio802154_swi_init();
nrf_802154_swi_init();
}
void nrf_drv_radio802154_priority_drop_timeslot_exit(void)
void nrf_802154_priority_drop_timeslot_exit(void)
{
nrf_drv_radio802154_swi_timeslot_exit();
nrf_802154_swi_timeslot_exit();
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,21 +33,20 @@
*
*/
#ifndef NRF_DRV_RADIO802154_PROCEDURES_DURATION_H_
#define NRF_DRV_RADIO802154_PROCEDURES_DURATION_H_
#ifndef NRF_802154_PROCEDURES_DURATION_H_
#define NRF_802154_PROCEDURES_DURATION_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_802154_const.h"
#define TX_RAMP_UP_TIME 40 // us
#define RX_RAMP_UP_TIME 40 // us
#define RX_RAMP_DOWN_TIME 0 // us
#define MAX_RAMP_DOWN_TIME 6 // us
#define PHY_US_PER_SYMBOL 16 // us/sym
#define PHY_SYMBOLS_PER_OCTET 2 // sym/byte
#define PHY_SHR_DURATION 10 // sym
#define A_CCA_DURATION 8 // sym
#define A_TURNAROUND_TIME 12 // sym
#define A_UNIT_BACKOFF_PERIOD 20 // sym
@@ -59,9 +58,19 @@
PHY_SHR_DURATION + \
(NUM_OCTETS_IN_ACK * PHY_SYMBOLS_PER_OCTET))
static inline uint16_t nrf_drv_radio802154_tx_duration_get(uint8_t psdu_length,
bool cca,
bool ack_requested)
__STATIC_INLINE uint16_t nrf_802154_tx_duration_get(uint8_t psdu_length,
bool cca,
bool ack_requested);
__STATIC_INLINE uint16_t nrf_802154_rx_duration_get(uint8_t psdu_length, bool ack_requested);
__STATIC_INLINE uint16_t nrf_802154_cca_duration_get(void);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint16_t nrf_802154_tx_duration_get(uint8_t psdu_length,
bool cca,
bool ack_requested)
{
// ramp down
// if CCA: + RX ramp up + CCA + RX ramp down
@@ -86,11 +95,11 @@ static inline uint16_t nrf_drv_radio802154_tx_duration_get(uint8_t psdu_length,
return result;
}
static inline uint16_t nrf_drv_radio802154_rx_duration_get(uint8_t psdu_length, bool ack_requested)
__STATIC_INLINE uint16_t nrf_802154_rx_duration_get(uint8_t psdu_length, bool ack_requested)
{
// SHR + PHR + PSDU
// if ACK: + aTurnaroundTime + ACK frame duration
uint16_t result = PHY_SHR_DURATION + (psdu_length + 1) * PHY_SYMBOLS_PER_OCTET;
uint16_t result = PHY_SHR_DURATION + ((psdu_length + 1) * PHY_SYMBOLS_PER_OCTET);
if (ack_requested)
{
@@ -104,12 +113,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)
__STATIC_INLINE uint16_t nrf_802154_cca_duration_get(void)
{
// ramp down + rx ramp up + CCA
uint16_t result = MAX_RAMP_DOWN_TIME + RX_RAMP_UP_TIME + A_CCA_DURATION * PHY_US_PER_SYMBOL;
uint16_t result = MAX_RAMP_DOWN_TIME + RX_RAMP_UP_TIME + (A_CCA_DURATION * PHY_US_PER_SYMBOL);
return result;
}
#endif /* NRF_DRV_RADIO802154_PROCEDURES_DURATION_H_ */
#endif /* SUPPRESS_INLINE_IMPLEMENTATION */
#endif /* NRF_802154_PROCEDURES_DURATION_H_ */
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,97 +28,123 @@
*
*/
#ifndef NRF_DRIVER_RADIO802154_REQUEST_H__
#define NRF_DRIVER_RADIO802154_REQUEST_H__
#ifndef NRF_802154_REQUEST_H__
#define NRF_802154_REQUEST_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_const.h"
#include "nrf_802154_notification.h"
#include "nrf_802154_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_driver_radio802154_request 802.15.4 driver request
* @defgroup nrf_802154_request 802.15.4 driver request
* @{
* @ingroup nrf_driver_radio802154
* @ingroup nrf_802154
* @brief Requests to the driver triggered from the MAC layer.
*/
/**
* @brief Initialize request module.
*/
void nrf_drv_radio802154_request_init(void);
void nrf_802154_request_init(void);
/**
* @brief Request entering sleep state.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
*
* @retval true The driver will enter sleep state.
* @retval false The driver cannot enter sleep state due to ongoing operation.
*/
bool nrf_drv_radio802154_request_sleep(void);
bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl);
/**
* @brief Request entering receive state.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @param[in] notify_function Function called to notify status of this procedure instead of
* default notification. If NULL default notification is used.
*
* @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(void);
bool nrf_802154_request_receive(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
nrf_802154_notification_func_t notify_function);
/**
* @brief Request entering transmit state.
*
* @param[in] p_data Pointer to the frame to transmit.
* @param[in] cca If the driver should perform CCA procedure before transmission.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @param[in] p_data Pointer to the frame to transmit.
* @param[in] cca If the driver should perform CCA procedure before transmission.
* @param[in] notify_function Function called to notify status of this procedure instead of
* default notification. If NULL default notification is used.
*
* @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, bool cca);
bool nrf_802154_request_transmit(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
const uint8_t * p_data,
bool cca,
nrf_802154_notification_func_t notify_function);
/**
* @brief Request entering energy detection state.
*
* @param[in] time_us Requested duration of energy detection procedure.
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @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(uint32_t time_us);
bool nrf_802154_request_energy_detection(nrf_802154_term_t term_lvl, uint32_t time_us);
/**
* @brief Request entering CCA state.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
*
* @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);
bool nrf_802154_request_cca(nrf_802154_term_t term_lvl);
/**
* @brief Request entering continuous carrier state.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
*
* @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);
bool nrf_802154_request_continuous_carrier(nrf_802154_term_t term_lvl);
/**
* @brief Request the driver to free given buffer.
*
* @param[in] p_data Pointer to the buffer to free.
*/
void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data);
bool nrf_802154_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);
bool nrf_802154_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);
bool nrf_802154_request_cca_cfg_update(void);
/**
*@}
@@ -128,4 +154,4 @@ void nrf_drv_radio802154_request_cca_cfg_update(void);
}
#endif
#endif // NRF_DRIVER_RADIO802154_REQUEST_H__
#endif // NRF_802154_REQUEST_H__
@@ -0,0 +1,139 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements requests to the driver triggered directly by the MAC layer.
*
*/
#include "nrf_802154_request.h"
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_core.h"
#include "nrf_802154_critical_section.h"
#include "hal/nrf_radio.h"
#define REQUEST_FUNCTION(func_core, params_core) \
bool result; \
\
if (nrf_802154_critical_section_enter()) \
{ \
result = func_core params_core; \
nrf_802154_critical_section_exit(); \
} \
else \
{ \
result = false; \
} \
\
return result;
#define REQUEST_FUNCTION_NO_ARGS(func_core) \
REQUEST_FUNCTION(func_core, ())
#define REQUEST_FUNCTION_1_ARG(func_core, arg) \
REQUEST_FUNCTION(func_core, (arg))
#define REQUEST_FUNCTION_2_ARGS(func_core, arg1, arg2) \
REQUEST_FUNCTION(func_core, (arg1, arg2))
#define REQUEST_FUNCTION_3_ARGS(func_core, arg1, arg2, arg3) \
REQUEST_FUNCTION(func_core, (arg1, arg2, arg3))
#define REQUEST_FUNCTION_4_ARGS(func_core, arg1, arg2, arg3, arg4) \
REQUEST_FUNCTION(func_core, (arg1, arg2, arg3, arg4))
#define REQUEST_FUNCTION_5_ARGS(func_core, arg1, arg2, arg3, arg4, arg5) \
REQUEST_FUNCTION(func_core, (arg1, arg2, arg3, arg4, arg5))
void nrf_802154_request_init(void)
{
// Intentionally empty
}
bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_sleep, term_lvl)
}
bool nrf_802154_request_receive(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
nrf_802154_notification_func_t notify_function)
{
REQUEST_FUNCTION_3_ARGS(nrf_802154_core_receive, term_lvl, req_orig, notify_function)
}
bool nrf_802154_request_transmit(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
const uint8_t * p_data,
bool cca,
nrf_802154_notification_func_t notify_function)
{
REQUEST_FUNCTION_5_ARGS(nrf_802154_core_transmit,
term_lvl,
req_orig,
p_data,
cca,
notify_function)
}
bool nrf_802154_request_energy_detection(nrf_802154_term_t term_lvl, uint32_t time_us)
{
REQUEST_FUNCTION_2_ARGS(nrf_802154_core_energy_detection, term_lvl, time_us)
}
bool nrf_802154_request_cca(nrf_802154_term_t term_lvl)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_cca, term_lvl)
}
bool nrf_802154_request_continuous_carrier(nrf_802154_term_t term_lvl)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_continuous_carrier, term_lvl)
}
bool nrf_802154_request_buffer_free(uint8_t * p_data)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_notify_buffer_free, p_data)
}
bool nrf_802154_request_channel_update(void)
{
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_channel_update)
}
bool nrf_802154_request_cca_cfg_update(void)
{
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_cca_cfg_update)
}
@@ -0,0 +1,189 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements requests to the driver triggered by the MAC layer through SWI.
*
*/
#include "nrf_802154_request.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154_config.h"
#include "nrf_802154_core.h"
#include "nrf_802154_critical_section.h"
#include "nrf_802154_debug.h"
#include "nrf_802154_rx_buffer.h"
#include "nrf_802154_swi.h"
#include "hal/nrf_radio.h"
#include <nrf.h>
#define REQUEST_FUNCTION(func_core, params_core, func_swi, params_swi) \
bool result = false; \
\
if (active_vector_priority_is_high()) \
{ \
if (nrf_802154_critical_section_enter()) \
{ \
result = func_core params_core; \
nrf_802154_critical_section_exit(); \
} \
else \
{ \
result = false; \
} \
} \
else \
{ \
func_swi params_swi; \
} \
\
return result;
#define REQUEST_FUNCTION_NO_ARGS(func_core, func_swi) \
REQUEST_FUNCTION(func_core, (), func_swi, (&result))
#define REQUEST_FUNCTION_1_ARG(func_core, func_swi, arg) \
REQUEST_FUNCTION(func_core, (arg), func_swi, (arg, &result))
#define REQUEST_FUNCTION_2_ARGS(func_core, func_swi, arg1, arg2) \
REQUEST_FUNCTION(func_core, (arg1, arg2), func_swi, (arg1, arg2, &result))
#define REQUEST_FUNCTION_3_ARGS(func_core, func_swi, arg1, arg2, arg3) \
REQUEST_FUNCTION(func_core, (arg1, arg2, arg3), func_swi, (arg1, arg2, arg3, &result))
#define REQUEST_FUNCTION_4_ARGS(func_core, func_swi, arg1, arg2, arg3, arg4) \
REQUEST_FUNCTION(func_core, \
(arg1, arg2, arg3, arg4), \
func_swi, \
(arg1, arg2, arg3, arg4, &result))
#define REQUEST_FUNCTION_5_ARGS(func_core, func_swi, arg1, arg2, arg3, arg4, arg5) \
REQUEST_FUNCTION(func_core, \
(arg1, arg2, arg3, arg4, arg5), \
func_swi, \
(arg1, arg2, arg3, arg4, arg5, &result))
/** Check if active vector priority is high enough to call requests directly.
*
* @retval true Active vector priority is greater or equal to SWI priority.
* @retval false Active vector priority is lower than SWI priority.
*/
static bool active_vector_priority_is_high(void)
{
return nrf_802154_critical_section_active_vector_priority_get() <= NRF_802154_SWI_PRIORITY;
}
void nrf_802154_request_init(void)
{
nrf_802154_swi_init();
}
bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_sleep,
nrf_802154_swi_sleep,
term_lvl)
}
bool nrf_802154_request_receive(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
nrf_802154_notification_func_t notify_function)
{
REQUEST_FUNCTION_3_ARGS(nrf_802154_core_receive,
nrf_802154_swi_receive,
term_lvl,
req_orig,
notify_function)
}
bool nrf_802154_request_transmit(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
const uint8_t * p_data,
bool cca,
nrf_802154_notification_func_t notify_function)
{
REQUEST_FUNCTION_5_ARGS(nrf_802154_core_transmit,
nrf_802154_swi_transmit,
term_lvl,
req_orig,
p_data,
cca,
notify_function)
}
bool nrf_802154_request_energy_detection(nrf_802154_term_t term_lvl,
uint32_t time_us)
{
REQUEST_FUNCTION_2_ARGS(nrf_802154_core_energy_detection,
nrf_802154_swi_energy_detection,
term_lvl,
time_us)
}
bool nrf_802154_request_cca(nrf_802154_term_t term_lvl)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_cca,
nrf_802154_swi_cca,
term_lvl)
}
bool nrf_802154_request_continuous_carrier(nrf_802154_term_t term_lvl)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_continuous_carrier,
nrf_802154_swi_continuous_carrier,
term_lvl)
}
bool nrf_802154_request_buffer_free(uint8_t * p_data)
{
REQUEST_FUNCTION_1_ARG(nrf_802154_core_notify_buffer_free,
nrf_802154_swi_buffer_free,
p_data)
}
bool nrf_802154_request_channel_update(void)
{
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_channel_update,
nrf_802154_swi_channel_update)
}
bool nrf_802154_request_cca_cfg_update(void)
{
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_cca_cfg_update,
nrf_802154_swi_cca_cfg_update)
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
*
*/
#include "nrf_drv_radio802154_revision.h"
#include "nrf_802154_revision.h"
#include <assert.h>
@@ -44,9 +44,9 @@ typedef enum
NRF52840_REVISION_AAAA,
NRF52840_REVISION_AABA,
NRF52840_REVISION_UNKNOWN,
} nrf_drv_radio802154_chip_revision;
} nrf_802154_chip_revision;
static nrf_drv_radio802154_chip_revision m_nrf52840_revision = NRF52840_REVISION_UNKNOWN;
static nrf_802154_chip_revision m_nrf52840_revision = NRF52840_REVISION_UNKNOWN;
/**
* @brief Internal auxiliary function to check if the program is running on NRF52840 chip.
@@ -88,7 +88,7 @@ static inline bool nrf_revision_type_52840_aaba(void)
(((*(uint32_t *)0xF0000FEC) & 0xF0) == 0x00)); // sub-revision
}
void nrf_drv_radio802154_revision_init(void)
void nrf_802154_revision_init(void)
{
if (nrf_revision_type_52840_aaaa())
{
@@ -104,7 +104,7 @@ void nrf_drv_radio802154_revision_init(void)
}
}
bool nrf_drv_radio802154_revision_has_phyend_event(void)
bool nrf_802154_revision_has_phyend_event(void)
{
#if NRF52840_AAAA
return false;
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
*
*/
#ifndef NRF_DRV_RADIO802154_REVISION_H_
#define NRF_DRV_RADIO802154_REVISION_H_
#ifndef NRF_802154_REVISION_H_
#define NRF_802154_REVISION_H_
#include <stdbool.h>
#include <stdint.h>
@@ -50,7 +50,7 @@ extern "C" {
* @note If the chip revision is not recognized, this module assumes that it is running on a newer
* chip revision that has all of the features, that the most recent known revision has.
*/
void nrf_drv_radio802154_revision_init(void);
void nrf_802154_revision_init(void);
/**
* @brief Function to check if the program is running on NRF52840 revision that supports PHYEND event.
@@ -58,10 +58,10 @@ void nrf_drv_radio802154_revision_init(void);
* @retval true If PHYEND event is supported.
* @retval false If PHYEND event is not supported.
*/
bool nrf_drv_radio802154_revision_has_phyend_event(void);
bool nrf_802154_revision_has_phyend_event(void);
#ifdef __cplusplus
}
#endif
#endif /* NRF_DRV_RADIO802154_REVISION_H_ */
#endif /* NRF_802154_REVISION_H_ */
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,33 +34,33 @@
*
*/
#include "nrf_drv_radio802154_rx_buffer.h"
#include "nrf_802154_rx_buffer.h"
#include <stddef.h>
#include "nrf_drv_radio802154_config.h"
#include "nrf_802154_config.h"
#if NRF_DRV_RADIO802154_RX_BUFFERS < 1
#if NRF_802154_RX_BUFFERS < 1
#error Not enough rx buffers in the 802.15.4 radio driver.
#endif
rx_buffer_t nrf_drv_radio802154_rx_buffers[NRF_DRV_RADIO802154_RX_BUFFERS]; ///< Receive buffers.
rx_buffer_t nrf_802154_rx_buffers[NRF_802154_RX_BUFFERS]; ///< Receive buffers.
void nrf_drv_radio802154_rx_buffer_init(void)
void nrf_802154_rx_buffer_init(void)
{
for (uint32_t i = 0; i < NRF_DRV_RADIO802154_RX_BUFFERS; i++)
for (uint32_t i = 0; i < NRF_802154_RX_BUFFERS; i++)
{
nrf_drv_radio802154_rx_buffers[i].free = true;
nrf_802154_rx_buffers[i].free = true;
}
}
rx_buffer_t * nrf_drv_radio802154_rx_buffer_free_find(void)
rx_buffer_t * nrf_802154_rx_buffer_free_find(void)
{
for (uint32_t i = 0; i < NRF_DRV_RADIO802154_RX_BUFFERS; i++)
for (uint32_t i = 0; i < NRF_802154_RX_BUFFERS; i++)
{
if (nrf_drv_radio802154_rx_buffers[i].free)
if (nrf_802154_rx_buffers[i].free)
{
return &nrf_drv_radio802154_rx_buffers[i];
return &nrf_802154_rx_buffers[i];
}
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,13 +33,13 @@
*
*/
#ifndef NRF_DRV_RADIO802154_RX_BUFFER_H_
#define NRF_DRV_RADIO802154_RX_BUFFER_H_
#ifndef NRF_802154_RX_BUFFER_H_
#define NRF_802154_RX_BUFFER_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154_const.h"
#include "nrf_802154_const.h"
#ifdef __cplusplus
extern "C" {
@@ -57,27 +57,27 @@ typedef struct
/**
* @brief Array containing all buffers used to receive frame.
*
* This array is in global scope to allow optimizations in FSM module in case there is only
* This array is in global scope to allow optimizations in Core module in case there is only
* one buffer provided by this module.
*
*/
extern rx_buffer_t nrf_drv_radio802154_rx_buffers[];
extern rx_buffer_t nrf_802154_rx_buffers[];
/**
* @brief Initialize buffer for received frames.
*/
void nrf_drv_radio802154_rx_buffer_init(void);
void nrf_802154_rx_buffer_init(void);
/**
* @brief Get free buffer to receive a frame.
*
* @return Pointer to free buffer of NULL if no free buffer is available.
*/
rx_buffer_t * nrf_drv_radio802154_rx_buffer_free_find(void);
rx_buffer_t * nrf_802154_rx_buffer_free_find(void);
#ifdef __cplusplus
}
#endif
#endif /* NRF_DRV_RADIO802154_RX_BUFFER_H_ */
#endif /* NRF_802154_RX_BUFFER_H_ */
@@ -0,0 +1,821 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements SWI manager for nRF 802.15.4 driver.
*
*/
#include "nrf_802154_swi.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154.h"
#include "nrf_802154_config.h"
#include "nrf_802154_core.h"
#include "nrf_802154_critical_section.h"
#include "nrf_802154_rx_buffer.h"
#include "hal/nrf_egu.h"
#include "raal/nrf_raal_api.h"
/** Size of notification queue.
*
* One slot for each receive buffer, one for transmission, one for busy channel and one for energy
* detection.
*/
#define NTF_QUEUE_SIZE (NRF_802154_RX_BUFFERS + 3)
/** Size of requests queue.
*
* Two is minimal queue size. It is not expected in current implementation to queue a few requests.
*/
#define REQ_QUEUE_SIZE 2
#define SWI_EGU NRF_802154_SWI_EGU_INSTANCE ///< Label of SWI peripheral.
#define SWI_IRQn NRF_802154_SWI_IRQN ///< Symbol of SWI IRQ number.
#define SWI_IRQHandler NRF_802154_SWI_IRQ_HANDLER ///< Symbol of SWI IRQ handler.
#define NTF_INT NRF_EGU_INT_TRIGGERED0 ///< Label of notification interrupt.
#define NTF_TASK NRF_EGU_TASK_TRIGGER0 ///< Label of notification task.
#define NTF_EVENT NRF_EGU_EVENT_TRIGGERED0 ///< Label of notification event.
#define TIMESLOT_EXIT_INT NRF_EGU_INT_TRIGGERED1 ///< Label of timeslot exit interrupt.
#define TIMESLOT_EXIT_TASK NRF_EGU_TASK_TRIGGER1 ///< Label of timeslot exit task.
#define TIMESLOT_EXIT_EVENT NRF_EGU_EVENT_TRIGGERED1 ///< Label of timeslot exit event.
#define REQ_INT NRF_EGU_INT_TRIGGERED2 ///< Label of request interrupt.
#define REQ_TASK NRF_EGU_TASK_TRIGGER2 ///< Label of request task.
#define REQ_EVENT NRF_EGU_EVENT_TRIGGERED2 ///< Label of request event.
#define RAW_LENGTH_OFFSET 0
#define RAW_PAYLOAD_OFFSET 1
/// Types of notifications in notification queue.
typedef enum
{
NTF_TYPE_RECEIVED, ///< Frame received
NTF_TYPE_RECEIVE_FAILED, ///< Frame reception failed
NTF_TYPE_TRANSMITTED, ///< Frame transmitted
NTF_TYPE_TRANSMIT_FAILED, ///< Frame transmission failure
NTF_TYPE_ENERGY_DETECTED, ///< Energy detection procedure ended
NTF_TYPE_ENERGY_DETECTION_FAILED, ///< Energy detection procedure failed
NTF_TYPE_CCA, ///< CCA procedure ended
NTF_TYPE_CCA_FAILED, ///< CCA procedure failed
} nrf_802154_ntf_type_t;
/// Notification data in the notification queue.
typedef struct
{
nrf_802154_ntf_type_t type; ///< Notification type.
union
{
struct
{
uint8_t * p_psdu; ///< Pointer to received frame PSDU.
int8_t power; ///< RSSI of received frame.
int8_t lqi; ///< LQI of received frame.
} received; ///< Received frame details.
struct
{
nrf_802154_rx_error_t error; ///< An error code that indicates reason of the failure.
} receive_failed;
struct
{
const uint8_t * p_frame; ///< Pointer to frame that was transmitted.
uint8_t * p_psdu; ///< Pointer to received ACK PSDU or NULL.
int8_t power; ///< RSSI of received ACK or 0.
int8_t lqi; ///< LQI of received ACK or 0.
} transmitted; ///< Transmitted frame details.
struct
{
const uint8_t * p_frame; ///< Pointer to frame that was requested to be transmitted, but failed.
nrf_802154_tx_error_t error; ///< An error code that indicates reason of the failure.
} transmit_failed;
struct
{
int8_t result; ///< Energy detection result.
} energy_detected; ///< Energy detection details.
struct
{
nrf_802154_ed_error_t error; ///< An error code that indicates reason of the failure.
} energy_detection_failed; ///< Energy detection failure details.
struct
{
bool result; ///< CCA result.
} cca; ///< CCA details.
struct
{
nrf_802154_cca_error_t error; ///< An error code that indicates reason of the failure.
} cca_failed; ///< CCA failure details.
} data; ///< Notification data depending on it's type.
} nrf_802154_ntf_data_t;
/// Type of requests in request queue.
typedef enum
{
REQ_TYPE_SLEEP,
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_802154_req_type_t;
/// Request data in request queue.
typedef struct
{
nrf_802154_req_type_t type; ///< Type of the request.
union
{
struct
{
nrf_802154_term_t term_lvl; ///< Request priority.
bool * p_result; ///< Sleep request result.
} sleep; ///< Sleep request details.
struct
{
nrf_802154_notification_func_t notif_func; ///< Error notified in case of success.
nrf_802154_term_t term_lvl; ///< Request priority.
req_originator_t req_orig; ///< Request originator.
bool * p_result; ///< Receive request result.
} receive; ///< Receive request details.
struct
{
nrf_802154_notification_func_t notif_func; ///< Error notified in case of success.
nrf_802154_term_t term_lvl; ///< Request priority.
req_originator_t req_orig; ///< Request originator.
const uint8_t * p_data; ///< Pointer to PSDU to transmit.
bool cca; ///< If CCA was requested prior to transmission.
bool * p_result; ///< Transmit request result.
} transmit; ///< Transmit request details.
struct
{
nrf_802154_term_t term_lvl; ///< Request priority.
bool * p_result; ///< Energy detection request result.
uint32_t time_us; ///< Requested time of energy detection procedure.
} energy_detection; ///< Energy detection request details.
struct
{
nrf_802154_term_t term_lvl; ///< Request priority.
bool * p_result; ///< CCA request result.
} cca; ///< CCA request details.
struct
{
nrf_802154_term_t term_lvl; ///< Request priority.
bool * p_result; ///< Continuous carrier request result.
} continuous_carrier; ///< Continuous carrier request details.
struct
{
uint8_t * p_data; ///< Pointer to receive buffer to free.
bool * p_result; ///< Buffer free request result.
} buffer_free; ///< Buffer free request details.
struct
{
bool * p_result; ///< Channel update request result.
} channel_update; ///< Channel update request details.
struct
{
bool * p_result; ///< CCA config update request result.
} cca_cfg_update; ///< CCA config update request details.
} data; ///< Request data depending on it's type.
} nrf_802154_req_data_t;
static nrf_802154_ntf_data_t m_ntf_queue[NTF_QUEUE_SIZE]; ///< Notification queue.
static uint8_t m_ntf_r_ptr; ///< Notification queue read index.
static uint8_t m_ntf_w_ptr; ///< Notification queue write index.
static nrf_802154_req_data_t m_req_queue[REQ_QUEUE_SIZE]; ///< Request queue.
static uint8_t m_req_r_ptr; ///< Request queue read index.
static uint8_t m_req_w_ptr; ///< Request queue write index.
/**
* Increment given index for any queue.
*
* @param[inout] p_ptr Index to increment.
* @param[in] queue_size Number of elements in the queue.
*/
static void queue_ptr_increment(uint8_t * p_ptr, uint8_t queue_size)
{
if (++(*p_ptr) >= queue_size)
{
*p_ptr = 0;
}
}
/**
* Check if given queue is full.
*
* @param[in] r_ptr Read index associated with given queue.
* @param[in] w_ptr Write index associated with given queue.
* @param[in] queue_size Number of elements in the queue.
*
* @retval true Given queue is full.
* @retval false Given queue is not full.
*/
static bool queue_is_full(uint8_t r_ptr, uint8_t w_ptr, uint8_t queue_size)
{
if (w_ptr == (r_ptr - 1))
{
return true;
}
if ((r_ptr == 0) && (w_ptr == queue_size - 1))
{
return true;
}
return false;
}
/**
* Check if given queue is empty.
*
* @param[in] r_ptr Read index associated with given queue.
* @param[in] w_ptr Write index associated with given queue.
*
* @retval true Given queue is empty.
* @retval false Given queue is not empty.
*/
static bool queue_is_empty(uint8_t r_ptr, uint8_t w_ptr)
{
return (r_ptr == w_ptr);
}
/**
* Increment given index associated with notification queue.
*
* @param[inout] p_ptr Pointer to the index to increment.
*/
static void ntf_queue_ptr_increment(uint8_t * p_ptr)
{
queue_ptr_increment(p_ptr, NTF_QUEUE_SIZE);
}
/**
* Check if notification queue is full.
*
* @retval true Notification queue is full.
* @retval false Notification queue is not full.
*/
static bool ntf_queue_is_full(void)
{
return queue_is_full(m_ntf_r_ptr, m_ntf_w_ptr, NTF_QUEUE_SIZE);
}
/**
* Check if notification queue is empty.
*
* @retval true Notification queue is empty.
* @retval false Notification queue is not empty.
*/
static bool ntf_queue_is_empty(void)
{
return queue_is_empty(m_ntf_r_ptr, m_ntf_w_ptr);
}
/**
* Increment given index associated with request queue.
*
* @param[inout] p_ptr Pointer to the index to increment.
*/
static void req_queue_ptr_increment(uint8_t * p_ptr)
{
queue_ptr_increment(p_ptr, REQ_QUEUE_SIZE);
}
/**
* Check if request queue is full.
*
* @retval true Request queue is full.
* @retval false Request queue is not full.
*/
static bool req_queue_is_full(void)
{
return queue_is_full(m_req_r_ptr, m_req_w_ptr, REQ_QUEUE_SIZE);
}
/**
* Check if request queue is empty.
*
* @retval true Request queue is empty.
* @retval false Request queue is not empty.
*/
static bool req_queue_is_empty(void)
{
return queue_is_empty(m_req_r_ptr, m_req_w_ptr);
}
/**
* 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_802154_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_802154_swi_init(void)
{
m_ntf_r_ptr = 0;
m_ntf_w_ptr = 0;
nrf_egu_int_enable(SWI_EGU, NTF_INT | TIMESLOT_EXIT_INT | REQ_INT);
NVIC_SetPriority(SWI_IRQn, NRF_802154_SWI_PRIORITY);
NVIC_ClearPendingIRQ(SWI_IRQn);
NVIC_EnableIRQ(SWI_IRQn);
}
void nrf_802154_swi_notify_received(uint8_t * p_data, int8_t power, int8_t lqi)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_RECEIVED;
p_slot->data.received.p_psdu = p_data;
p_slot->data.received.power = power;
p_slot->data.received.lqi = lqi;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_notify_receive_failed(nrf_802154_rx_error_t error)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_RECEIVE_FAILED;
p_slot->data.receive_failed.error = error;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_notify_transmitted(const uint8_t * p_frame,
uint8_t * p_data,
int8_t power,
int8_t lqi)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_TRANSMITTED;
p_slot->data.transmitted.p_frame = p_frame;
p_slot->data.transmitted.p_psdu = p_data;
p_slot->data.transmitted.power = power;
p_slot->data.transmitted.lqi = lqi;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_notify_transmit_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_TRANSMIT_FAILED;
p_slot->data.transmit_failed.p_frame = p_frame;
p_slot->data.transmit_failed.error = error;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_notify_energy_detected(uint8_t result)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_ENERGY_DETECTED;
p_slot->data.energy_detected.result = result;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_notify_energy_detection_failed(nrf_802154_ed_error_t error)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_ENERGY_DETECTION_FAILED;
p_slot->data.energy_detection_failed.error = error;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_notify_cca(bool channel_free)
{
assert(!ntf_queue_is_full());
nrf_802154_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_802154_swi_notify_cca_failed(nrf_802154_cca_error_t error)
{
assert(!ntf_queue_is_full());
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_w_ptr];
p_slot->type = NTF_TYPE_CCA_FAILED;
p_slot->data.cca_failed.error = error;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_802154_swi_timeslot_exit(void)
{
assert(!nrf_egu_event_check(SWI_EGU, TIMESLOT_EXIT_EVENT));
nrf_egu_task_trigger(SWI_EGU, TIMESLOT_EXIT_TASK);
}
void nrf_802154_swi_sleep(nrf_802154_term_t term_lvl, bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_SLEEP;
p_slot->data.sleep.term_lvl = term_lvl;
p_slot->data.sleep.p_result = p_result;
req_exit();
}
void nrf_802154_swi_receive(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
nrf_802154_notification_func_t notify_function,
bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_RECEIVE;
p_slot->data.receive.term_lvl = term_lvl;
p_slot->data.receive.req_orig = req_orig;
p_slot->data.receive.notif_func = notify_function;
p_slot->data.receive.p_result = p_result;
req_exit();
}
void nrf_802154_swi_transmit(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
const uint8_t * p_data,
bool cca,
nrf_802154_notification_func_t notify_function,
bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_TRANSMIT;
p_slot->data.transmit.term_lvl = term_lvl;
p_slot->data.transmit.req_orig = req_orig;
p_slot->data.transmit.p_data = p_data;
p_slot->data.transmit.cca = cca;
p_slot->data.transmit.notif_func = notify_function;
p_slot->data.transmit.p_result = p_result;
req_exit();
}
void nrf_802154_swi_energy_detection(nrf_802154_term_t term_lvl,
uint32_t time_us,
bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_ENERGY_DETECTION;
p_slot->data.energy_detection.term_lvl = term_lvl;
p_slot->data.energy_detection.time_us = time_us;
p_slot->data.energy_detection.p_result = p_result;
req_exit();
}
void nrf_802154_swi_cca(nrf_802154_term_t term_lvl, bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_CCA;
p_slot->data.cca.term_lvl = term_lvl;
p_slot->data.cca.p_result = p_result;
req_exit();
}
void nrf_802154_swi_continuous_carrier(nrf_802154_term_t term_lvl, bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_CONTINUOUS_CARRIER;
p_slot->data.continuous_carrier.term_lvl = term_lvl;
p_slot->data.continuous_carrier.p_result = p_result;
req_exit();
}
void nrf_802154_swi_buffer_free(uint8_t * p_data, bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_BUFFER_FREE;
p_slot->data.buffer_free.p_data = p_data;
p_slot->data.buffer_free.p_result = p_result;
req_exit();
}
void nrf_802154_swi_channel_update(bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_CHANNEL_UPDATE;
p_slot->data.channel_update.p_result = p_result;
req_exit();
}
void nrf_802154_swi_cca_cfg_update(bool * p_result)
{
nrf_802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_CCA_CFG_UPDATE;
p_slot->data.cca_cfg_update.p_result = p_result;
req_exit();
}
void SWI_IRQHandler(void)
{
if (nrf_egu_event_check(SWI_EGU, NTF_EVENT))
{
nrf_egu_event_clear(SWI_EGU, NTF_EVENT);
while (!ntf_queue_is_empty())
{
nrf_802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_r_ptr];
switch (p_slot->type)
{
case NTF_TYPE_RECEIVED:
#if NRF_802154_USE_RAW_API
nrf_802154_received_raw(p_slot->data.received.p_psdu,
p_slot->data.received.power,
p_slot->data.received.lqi);
#else // NRF_802154_USE_RAW_API
nrf_802154_received(p_slot->data.received.p_psdu + RAW_PAYLOAD_OFFSET,
p_slot->data.received.p_psdu[RAW_LENGTH_OFFSET],
p_slot->data.received.power,
p_slot->data.received.lqi);
#endif
break;
case NTF_TYPE_RECEIVE_FAILED:
nrf_802154_receive_failed(p_slot->data.receive_failed.error);
break;
case NTF_TYPE_TRANSMITTED:
#if NRF_802154_USE_RAW_API
nrf_802154_transmitted_raw(p_slot->data.transmitted.p_frame,
p_slot->data.transmitted.p_psdu,
p_slot->data.transmitted.power,
p_slot->data.transmitted.lqi);
#else // NRF_802154_USE_RAW_API
nrf_802154_transmitted(p_slot->data.transmitted.p_frame + RAW_PAYLOAD_OFFSET,
p_slot->data.transmitted.p_psdu + RAW_PAYLOAD_OFFSET,
p_slot->data.transmitted.p_psdu[RAW_LENGTH_OFFSET],
p_slot->data.transmitted.power,
p_slot->data.transmitted.lqi);
#endif
break;
case NTF_TYPE_TRANSMIT_FAILED:
#if NRF_802154_USE_RAW_API
nrf_802154_transmit_failed(p_slot->data.transmit_failed.p_frame,
p_slot->data.transmit_failed.error);
#else // NRF_802154_USE_RAW_API
nrf_802154_transmit_failed(p_slot->data.transmit_failed.p_frame + RAW_PAYLOAD_OFFSET,
p_slot->data.transmit_failed.error);
#endif
break;
case NTF_TYPE_ENERGY_DETECTED:
nrf_802154_energy_detected(p_slot->data.energy_detected.result);
break;
case NTF_TYPE_ENERGY_DETECTION_FAILED:
nrf_802154_energy_detection_failed(
p_slot->data.energy_detection_failed.error);
break;
case NTF_TYPE_CCA:
nrf_802154_cca_done(p_slot->data.cca.result);
break;
case NTF_TYPE_CCA_FAILED:
nrf_802154_cca_failed(p_slot->data.cca_failed.error);
break;
default:
assert(false);
}
ntf_queue_ptr_increment(&m_ntf_r_ptr);
}
}
if (nrf_egu_event_check(SWI_EGU, TIMESLOT_EXIT_EVENT))
{
nrf_raal_continuous_mode_exit();
nrf_egu_event_clear(SWI_EGU, TIMESLOT_EXIT_EVENT);
}
if (nrf_egu_event_check(SWI_EGU, REQ_EVENT))
{
nrf_egu_event_clear(SWI_EGU, REQ_EVENT);
while (!req_queue_is_empty())
{
nrf_802154_req_data_t * p_slot = &m_req_queue[m_req_r_ptr];
bool in_crit_sect;
in_crit_sect = nrf_802154_critical_section_enter();
switch (p_slot->type)
{
case REQ_TYPE_SLEEP:
*(p_slot->data.sleep.p_result) = in_crit_sect ?
nrf_802154_core_sleep(p_slot->data.sleep.term_lvl) :
false;
break;
case REQ_TYPE_RECEIVE:
*(p_slot->data.receive.p_result) = in_crit_sect ?
nrf_802154_core_receive(p_slot->data.receive.term_lvl,
p_slot->data.receive.req_orig,
p_slot->data.receive.notif_func) :
false;
break;
case REQ_TYPE_TRANSMIT:
*(p_slot->data.transmit.p_result) = in_crit_sect ?
nrf_802154_core_transmit(p_slot->data.transmit.term_lvl,
p_slot->data.transmit.req_orig,
p_slot->data.transmit.p_data,
p_slot->data.transmit.cca,
p_slot->data.transmit.notif_func) :
false;
break;
case REQ_TYPE_ENERGY_DETECTION:
*(p_slot->data.energy_detection.p_result) = in_crit_sect ?
nrf_802154_core_energy_detection(
p_slot->data.energy_detection.term_lvl,
p_slot->data.energy_detection.time_us) :
false;
break;
case REQ_TYPE_CCA:
*(p_slot->data.cca.p_result) = in_crit_sect ?
nrf_802154_core_cca(p_slot->data.cca.term_lvl) :
false;
break;
case REQ_TYPE_CONTINUOUS_CARRIER:
*(p_slot->data.continuous_carrier.p_result) = in_crit_sect ?
nrf_802154_core_continuous_carrier(
p_slot->data.continuous_carrier.term_lvl) :
false;
break;
case REQ_TYPE_BUFFER_FREE:
*(p_slot->data.buffer_free.p_result) = in_crit_sect ?
nrf_802154_core_notify_buffer_free(
p_slot->data.buffer_free.p_data):
false;
break;
case REQ_TYPE_CHANNEL_UPDATE:
*(p_slot->data.channel_update.p_result) = in_crit_sect ?
nrf_802154_core_channel_update() :
false;
break;
case REQ_TYPE_CCA_CFG_UPDATE:
*(p_slot->data.cca_cfg_update.p_result) = in_crit_sect ?
nrf_802154_core_cca_cfg_update() :
false;
break;
default:
assert(false);
}
if (in_crit_sect)
{
nrf_802154_critical_section_exit();
}
req_queue_ptr_increment(&m_req_r_ptr);
}
}
}
@@ -0,0 +1,222 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_802154_SWI_H__
#define NRF_802154_SWI_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_802154.h"
#include "nrf_802154_const.h"
#include "nrf_802154_notification.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_802154_swi 802.15.4 driver SWI management
* @{
* @ingroup nrf_802154
* @brief SWI manager for 802.15.4 driver.
*/
/**
* @brief Initialize SWI module.
*/
void nrf_802154_swi_init(void);
/**
* @brief Notify next higher layer that a frame was received from SWI priority level.
*
* @param[in] p_data Array of bytes containing PSDU. First byte contains frame length, other contain the frame itself.
* @param[in] power RSSI measured during the frame reception.
* @param[in] lqi LQI indicating measured link quality during the frame reception.
*/
void nrf_802154_swi_notify_received(uint8_t * p_data, int8_t power, int8_t lqi);
/**
* @brief Notify next higher layer that reception of a frame failed.
*
* @param[in] error An error code that indicates reason of the failure.
*/
void nrf_802154_swi_notify_receive_failed(nrf_802154_rx_error_t error);
/**
* @brief Notify next higher layer that a frame was transmitted from SWI priority level.
*
* @param[in] p_frame Pointer to buffer containing PSDU of transmitted frame.
* @param[in] p_ack Pointer to buffer containing PSDU of ACK frame. NULL if ACK was not requested.
* @param[in] power RSSI of received frame or 0 if ACK was not requested.
* @param[in] lqi LQI of received frame of 0 if ACK was not requested.
*/
void nrf_802154_swi_notify_transmitted(const uint8_t * p_frame,
uint8_t * p_data,
int8_t power,
int8_t lqi);
/**
* @brief Notify next higher layer that a frame was not transmitted from SWI priority level.
*
* @param[in] p_frame Pointer to buffer containing PSDU of the frame that failed transmit
* operation.
* @param[in] error Reason of the transmission failure.
*/
void nrf_802154_swi_notify_transmit_failed(const uint8_t * p_frame, nrf_802154_tx_error_t error);
/**
* @brief Notify next higher layer that energy detection procedure ended from SWI priority level.
*
* @param[in] result Detected energy level.
*/
void nrf_802154_swi_notify_energy_detected(uint8_t result);
/**
* @brief Notify next higher layer that energy detection procedure failed from SWI priority level.
*
* @param[in] error Reason of the energy detection failure.
*/
void nrf_802154_swi_notify_energy_detection_failed(nrf_802154_ed_error_t error);
/**
* @brief Notify next higher layer that CCA procedure ended from SWI priority level.
*
* @param[in] channel_free If detected free channel.
*/
void nrf_802154_swi_notify_cca(bool channel_free);
/**
* @brief Notify next higher layer that CCA procedure failed from SWI priority level.
*
* @param[in] error Reason of the CCA failure.
*/
void nrf_802154_swi_notify_cca_failed(nrf_802154_cca_error_t error);
/**
* @brief Request discarding of the timeslot from SWI priority level.
*
* @note This function should be called through notification module to prevent calling it from arbiter context.
*/
void nrf_802154_swi_timeslot_exit(void);
/**
* @brief Request entering sleep state from SWI priority.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[out] p_result Result of entering sleep state.
*/
void nrf_802154_swi_sleep(nrf_802154_term_t term_lvl, bool * p_result);
/**
* @brief Request entering receive state from SWI priority.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @param[in] notify_function Function called to notify status of this procedure instead of
* default notification. If NULL default notification is used.
* @param[out] p_result Result of entering receive state.
*/
void nrf_802154_swi_receive(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
nrf_802154_notification_func_t notify_function,
bool * p_result);
/**
* @biref Request entering transmit state from SWI priority.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] req_orig Module that originates this request.
* @param[in] p_data Pointer to PSDU of the frame to transmit.
* @param[in] cca If the driver should perform CCA procedure before transmission.
* @param[in] notify_function Function called to notify status of this procedure instead of
* default notification. If NULL default notification is used.
* @param[out] p_result Result of entering transmit state.
*/
void nrf_802154_swi_transmit(nrf_802154_term_t term_lvl,
req_originator_t req_orig,
const uint8_t * p_data,
bool cca,
nrf_802154_notification_func_t notify_function,
bool * p_result);
/**
* @brief Request entering energy detection state from SWI priority.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[in] time_us Requested duration of energy detection procedure.
* @param[out] p_result Result of entering energy detection state.
*/
void nrf_802154_swi_energy_detection(nrf_802154_term_t term_lvl,
uint32_t time_us,
bool * p_result);
/**
* @brief Request entering CCA state from SWI priority.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[out] p_result Result of entering CCA state.
*/
void nrf_802154_swi_cca(nrf_802154_term_t term_lvl, bool * p_result);
/**
* @brief Request entering continuous carrier state from SWI priority.
*
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
* @param[out] p_result Result of entering continuous carrier state.
*/
void nrf_802154_swi_continuous_carrier(nrf_802154_term_t term_lvl, bool * p_result);
/**
* @brief Notify Core module that given buffer is not used anymore and can be freed.
*
* @param[in] p_data Pointer to the buffer to free.
*/
void nrf_802154_swi_buffer_free(uint8_t * p_data, bool * p_result);
/**
* @brief Notify Core module that the next higher layer requested channel change.
*/
void nrf_802154_swi_channel_update(bool * p_result);
/**
* @brief Notify Core module that the next higher layer requested CCA configuration change.
*/
void nrf_802154_swi_cca_cfg_update(bool * p_result);
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif // NRF_802154_SWI_H__
@@ -0,0 +1,124 @@
/* Copyright (c) 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_802154_TYPES_H__
#define NRF_802154_TYPES_H__
#include <stdint.h>
#include "hal/nrf_radio.h"
/**
* @defgroup nrf_802154_types Types definitions used in the 802.15.4 driver.
* @{
* @ingroup nrf_802154
* @brief Definitions of types used in the 802.15.4 driver.
*/
/**
* @brief States of the driver.
*/
typedef uint8_t nrf_802154_state_t;
#define NRF_802154_STATE_INVALID 0x01 /**< Radio in an invalid state. */
#define NRF_802154_STATE_SLEEP 0x02 /**< Radio in Sleep state. */
#define NRF_802154_STATE_RECEIVE 0x03 /**< Radio in Receive state. */
#define NRF_802154_STATE_TRANSMIT 0x04 /**< Radio in Transmit state. */
#define NRF_802154_STATE_ENERGY_DETECTION 0x05 /**< Radio in Energy Detection state. */
#define NRF_802154_STATE_CCA 0x06 /**< Radio in CCA state. */
#define NRF_802154_STATE_CONTINUOUS_CARRIER 0x07 /**< Radio in Continuous Carrier state. */
/**
* @brief Errors reported during frame transmission.
*/
typedef uint8_t nrf_802154_tx_error_t;
#define NRF_802154_TX_ERROR_NONE 0x00 /**< There is no transmit error. */
#define NRF_802154_TX_ERROR_BUSY_CHANNEL 0x01 /**< CCA reported busy channel prior to transmission. */
#define NRF_802154_TX_ERROR_INVALID_ACK 0x02 /**< Received ACK frame is other than expected. */
#define NRF_802154_TX_ERROR_NO_MEM 0x03 /**< No receive buffer are available to receive an ACK. */
#define NRF_802154_TX_ERROR_TIMESLOT_ENDED 0x04 /**< Radio timeslot ended during transmission procedure. */
#define NRF_802154_TX_ERROR_NO_ACK 0x05 /**< ACK frame was not received during timeout period. */
#define NRF_802154_TX_ERROR_ABORTED 0x06 /**< Procedure was aborted by other driver operation with FORCE priority. */
/**
* @brief Possible errors during frame reception.
*/
typedef uint8_t nrf_802154_rx_error_t;
#define NRF_802154_RX_ERROR_NONE 0x00 /**< There is no receive error */
#define NRF_802154_RX_ERROR_INVALID_FRAME 0x01 /**< Received a malformed frame */
#define NRF_802154_RX_ERROR_INVALID_FCS 0x02 /**< Received a frame with invalid checksum. */
#define NRF_802154_RX_ERROR_INVALID_DEST_ADDR 0x03 /**< Received a frame with mismatched destination address. */
#define NRF_802154_RX_ERROR_RUNTIME 0x04 /**< A runtime error occured (e.g. CPU was hold for too long.) */
#define NRF_802154_RX_ERROR_TIMESLOT_ENDED 0x05 /**< Radio timeslot ended during frame reception. */
#define NRF_802154_RX_ERROR_ABORTED 0x06 /**< Procedure was aborted by other driver operation with FORCE priority. */
/**
* @brief Possible errors during energy detection.
*/
typedef uint8_t nrf_802154_ed_error_t;
#define NRF_802154_ED_ERROR_ABORTED 0x01 /**< Procedure was aborted by other driver operation with FORCE priority. */
/**
* @brief Possible errors during CCA procedure.
*/
typedef uint8_t nrf_802154_cca_error_t;
#define NRF_802154_CCA_ERROR_ABORTED 0x01 /**< Procedure was aborted by other driver operation with FORCE priority. */
/**
* @brief Termination level selected for particular request.
*
* Each request is able to terminate ongoing operation. This type selects which operation should be
* aborted by given request.
*/
typedef uint8_t nrf_802154_term_t;
#define NRF_802154_TERM_NONE 0x00 /**< Request is skipped if another operation is ongoing. */
#define NRF_802154_TERM_802154 0x01 /**< Request terminates ongoing 802.15.4 operation. */
/**
* @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_802154_cca_cfg_t;
/**
*@}
**/
#endif // NRF_802154_TYPES_H__
@@ -1,478 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements the nrf 802.15.4 radio driver.
*
*/
#include "nrf_drv_radio802154.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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"
#include "nrf_drv_radio802154_pib.h"
#include "nrf_drv_radio802154_priority_drop.h"
#include "nrf_drv_radio802154_request.h"
#include "nrf_drv_radio802154_revision.h"
#include "nrf_drv_radio802154_rx_buffer.h"
#include "hal/nrf_radio.h"
#include "platform/clock/nrf_drv_radio802154_clock.h"
#include "platform/timer/nrf_drv_radio802154_timer.h"
#include "raal/nrf_raal_api.h"
#include <cmsis/core_cmFunc.h>
#if ENABLE_FEM
#include "fem/nrf_fem_control_api.h"
#endif
#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_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);
}
void nrf_drv_radio802154_extended_address_set(const uint8_t * p_extended_address)
{
nrf_drv_radio802154_pib_extended_address_set(p_extended_address);
}
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();
nrf_drv_radio802154_clock_init();
nrf_drv_radio802154_debug_init();
nrf_drv_radio802154_fsm_init();
nrf_drv_radio802154_notification_init();
nrf_drv_radio802154_pib_init();
nrf_drv_radio802154_priority_drop_init();
nrf_drv_radio802154_request_init();
nrf_drv_radio802154_revision_init();
nrf_drv_radio802154_rx_buffer_init();
nrf_drv_radio802154_timer_init();
nrf_raal_init();
}
void nrf_drv_radio802154_deinit(void)
{
nrf_drv_radio802154_timer_deinit();
nrf_drv_radio802154_fsm_deinit();
nrf_drv_radio802154_clock_deinit();
}
#if !NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
void nrf_drv_radio802154_irq_handler(void)
{
nrf_drv_radio802154_fsm_irq_handler();
}
#endif // !NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
#if ENABLE_FEM
void nrf_drv_radio802154_fem_control_cfg_set(const nrf_drv_radio802154_fem_control_cfg_t * p_cfg)
{
nrf_fem_control_cfg_set(p_cfg);
}
void nrf_drv_radio802154_fem_control_cfg_get(nrf_drv_radio802154_fem_control_cfg_t * p_cfg)
{
nrf_fem_control_cfg_get(p_cfg);
}
#endif
nrf_drv_radio802154_state_t nrf_drv_radio802154_state_get(void)
{
switch (nrf_drv_radio802154_fsm_state_get())
{
case RADIO_STATE_DISABLING:
case RADIO_STATE_SLEEP:
return NRF_DRV_RADIO802154_STATE_SLEEP;
case RADIO_STATE_WAITING_TIMESLOT:
case RADIO_STATE_WAITING_RX_FRAME:
case RADIO_STATE_RX_HEADER:
case RADIO_STATE_RX_FRAME:
case RADIO_STATE_TX_ACK:
return NRF_DRV_RADIO802154_STATE_RECEIVE;
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;
}
bool nrf_drv_radio802154_sleep(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_SLEEP);
bool result = true;
switch (nrf_drv_radio802154_fsm_state_get())
{
case RADIO_STATE_DISABLING:
case RADIO_STATE_SLEEP:
break;
case RADIO_STATE_WAITING_TIMESLOT:
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_BEFORE_TX:
case RADIO_STATE_TX_FRAME:
case RADIO_STATE_RX_ACK:
result = nrf_drv_radio802154_request_sleep();
break;
default:
assert(false);
}
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_SLEEP);
return result;
}
void nrf_drv_radio802154_receive(void)
{
bool result;
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RECEIVE);
result = nrf_drv_radio802154_request_receive();
assert(result == true);
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RECEIVE);
}
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, cca);
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_TRANSMIT);
return result;
}
bool nrf_drv_radio802154_transmit(const uint8_t * p_data, uint8_t length, bool cca)
{
static uint8_t tx_buffer[RAW_PAYLOAD_OFFSET + MAX_PACKET_SIZE];
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(time_us);
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_ENERGY_DETECTION);
return result;
}
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;
assert(p_buffer->free == false);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_BUFFER_FREE);
nrf_drv_radio802154_request_buffer_free(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();
return - (int8_t)minus_dbm;
}
int8_t nrf_drv_radio802154_rssi_corrected_get(int8_t rssi, int8_t temp)
{
if (temp <= -30)
{
return rssi + 3;
}
if (temp <= -10)
{
return rssi + 2;
}
if (temp <= 10)
{
return rssi + 1;
}
if (temp <= 30)
{
return rssi;
}
if (temp <= 50)
{
return rssi - 1;
}
if (temp <= 70)
{
return rssi - 2;
}
return rssi - 3;
}
bool nrf_drv_radio802154_promiscuous_get(void)
{
return nrf_drv_radio802154_pib_promiscuous_get();
}
void nrf_drv_radio802154_promiscuous_set(bool enabled)
{
nrf_drv_radio802154_pib_promiscuous_set(enabled);
}
void nrf_drv_radio802154_auto_ack_set(bool enabled)
{
nrf_drv_radio802154_pib_auto_ack_set(enabled);
}
bool nrf_drv_radio802154_auto_ack_get(void)
{
return nrf_drv_radio802154_pib_auto_ack_get();
}
void nrf_drv_radio802154_auto_pending_bit_set(bool enabled)
{
nrf_drv_radio802154_ack_pending_bit_set(enabled);
}
bool nrf_drv_radio802154_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended)
{
return nrf_drv_radio802154_ack_pending_bit_for_addr_set(p_addr, extended);
}
bool nrf_drv_radio802154_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended)
{
return nrf_drv_radio802154_ack_pending_bit_for_addr_clear(p_addr, extended);
}
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_tx_ack_started(void)
{
// Intentionally empty
}
__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_receive_failed(nrf_drv_radio802154_rx_error_t error)
{
(void) error;
}
__WEAK void nrf_drv_radio802154_tx_started(void)
{
// Intentionally empty
}
__WEAK void nrf_drv_radio802154_rx_ack_started(void)
{
// Intentionally empty
}
__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;
if (p_ack != NULL)
{
nrf_drv_radio802154_buffer_free(p_ack);
}
}
__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_transmit_failed(nrf_drv_radio802154_tx_error_t error)
{
(void) error;
}
__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;
}
@@ -1,768 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @brief This module contains generic 802.15.4 radio driver for nRF SoC devices.
*
*/
#ifndef NRF_DRV_RADIO802154_H_
#define NRF_DRV_RADIO802154_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154_config.h"
#include "hal/nrf_radio.h"
#if ENABLE_FEM
#include "fem/nrf_fem_control_api.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief States of the driver.
*/
typedef uint8_t nrf_drv_radio802154_state_t;
#define NRF_DRV_RADIO802154_STATE_INVALID 0x01 /**< Radio in an invalid state. */
#define NRF_DRV_RADIO802154_STATE_SLEEP 0x02 /**< Radio in Sleep state. */
#define NRF_DRV_RADIO802154_STATE_RECEIVE 0x03 /**< Radio in Receive state. */
#define NRF_DRV_RADIO802154_STATE_TRANSMIT 0x04 /**< Radio in Transmit state. */
#define NRF_DRV_RADIO802154_STATE_ENERGY_DETECTION 0x05 /**< Radio in Energy Detection state. */
#define NRF_DRV_RADIO802154_STATE_CCA 0x06 /**< Radio in CCA state. */
#define NRF_DRV_RADIO802154_STATE_CONTINUOUS_CARRIER 0x07 /**< Radio in Continuous Carrier state. */
/**
* @brief Errors reported during frame transmission.
*/
typedef uint8_t nrf_drv_radio802154_tx_error_t;
#define NRF_DRV_RADIO802154_TX_ERROR_BUSY_CHANNEL 0x01 /**< CCA reported busy channel prior to transmission. */
#define NRF_DRV_RADIO802154_TX_ERROR_INVALID_ACK 0x02 /**< Received ACK frame is other than expected. */
#define NRF_DRV_RADIO802154_TX_ERROR_NO_MEM 0x03 /**< No receive buffer are available to receive an ACK. */
#define NRF_DRV_RADIO802154_TX_ERROR_TIMESLOT_ENDED 0x04 /**< Radio timeslot ended during transmission procedure. */
/**
* @brief Possible errors during frame reception.
*/
typedef uint8_t nrf_drv_radio802154_rx_error_t;
#define NRF_DRV_RADIO802154_RX_ERROR_INVALID_FRAME 0x01 /**< Received a malformed frame */
#define NRF_DRV_RADIO802154_RX_ERROR_INVALID_FCS 0x02 /**< Received a frame with invalid checksum. */
#define NRF_DRV_RADIO802154_RX_ERROR_INVALID_DEST_ADDR 0x03 /**< Received a frame with mismatched destination address. */
#define NRF_DRV_RADIO802154_RX_ERROR_RUNTIME 0x04 /**< A runtime error occured (e.g. CPU was hold for too long.) */
#define NRF_DRV_RADIO802154_RX_ERROR_TIMESLOT_ENDED 0x05 /**< Radio timeslot ended during frame reception. */
/**
* @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.
*
* @note This function shall be called once, before any other function from this module.
*
* Initialize radio peripheral to Sleep state.
*/
void nrf_drv_radio802154_init(void);
/**
* @brief Deinitialize 802.15.4 driver.
*
* Deinitialize radio peripheral and reset it to the default state.
*/
void nrf_drv_radio802154_deinit(void);
#if !NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
/**
* @brief Handle interrupt request from the RADIO peripheral.
*
* @note When NRF_DRV_RADIO802154_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 // !NRF_DRV_RADIO802154_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.
*
* @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_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 Front-end module management.
*/
#if ENABLE_FEM
typedef nrf_fem_control_cfg_t nrf_drv_radio802154_fem_control_cfg_t;
#define NRF_DRV_RADIO802154_FEM_DEFAULT_SETTINGS \
((nrf_drv_radio802154_fem_control_cfg_t) { \
.pa_cfg = { \
.enable = 1, \
.active_high = 1, \
.gpio_pin = NRF_FEM_CONTROL_DEFAULT_PA_PIN, \
}, \
.lna_cfg = { \
.enable = 1, \
.active_high = 1, \
.gpio_pin = NRF_FEM_CONTROL_DEFAULT_LNA_PIN, \
}, \
.ppi_ch_id_clr = NRF_FEM_CONTROL_DEFAULT_CLR_PPI_CHANNEL, \
.ppi_ch_id_set = NRF_FEM_CONTROL_DEFAULT_SET_PPI_CHANNEL, \
.radio_ppi_grp = NRF_FEM_CONTROL_DEFAULT_TIMER_MATCH_PPI_GROUP, \
.timer_ppi_grp = NRF_FEM_CONTROL_DEFAULT_RADIO_DISABLED_PPI_GROUP, \
.gpiote_ch_id = NRF_FEM_CONTROL_DEFAULT_GPIOTE_CHANNEL, \
})
/**
* @brief Set PA & LNA GPIO toggle configuration.
*
* @note This function shall not be called when radio is in use.
*
* @param[in] p_cfg A pointer to the PA & LNA GPIO toggle configuration.
*
*/
void nrf_drv_radio802154_fem_control_cfg_set(const nrf_drv_radio802154_fem_control_cfg_t * p_cfg);
/**
* @brief Get PA & LNA GPIO toggle configuration.
*
* @param[out] p_cfg A pointer to the structure for the PA & LNA GPIO toggle configuration.
*
*/
void nrf_drv_radio802154_fem_control_cfg_get(nrf_drv_radio802154_fem_control_cfg_t * p_cfg);
#endif // ENABLE_FEM
/**
* @section Setting addresses and Pan Id of this device.
*/
/**
* @brief Set PAN Id used by this device.
*
* @param[in] p_pan_id Pointer to PAN Id (2 bytes, little-endian).
*
* This function makes copy of the PAN Id.
*/
void nrf_drv_radio802154_pan_id_set(const uint8_t *p_pan_id);
/**
* @brief Set Extended Address of this device.
*
* @param[in] p_extended_address Pointer to extended address (8 bytes, little-endian).
*
* This function makes copy of the address.
*/
void nrf_drv_radio802154_extended_address_set(const uint8_t *p_extended_address);
/**
* @brief Set Short Address of this device.
*
* @param[in] p_short_address Pointer to short address (2 bytes, little-endian).
*
* This function makes copy of the 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.
*/
/**
* @brief Get current state of the radio.
*/
nrf_drv_radio802154_state_t nrf_drv_radio802154_state_get(void);
/**
* @brief Change radio state to Sleep.
*
* @note This function should be called only if radio is in Receive state.
*
* Sleep state is the lowest power state. In this state radio cannot transmit or receive frames.
*
* @return true If the radio changes it's state to low power mode.
* @return false If the driver could not schedule changing state.
*/
bool nrf_drv_radio802154_sleep(void);
/**
* @brief Change radio state to Receive.
*
* @note This function should be called in Sleep or Transmit state.
*
* 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.
*/
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 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_transmit_failed() 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 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_transmit_failed() 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 (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_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_transmit_failed() 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_transmit_failed() 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.
*
* @note This function should be called in Receive state or Sleep state.
* @note If this function is called in Sleep state nrf_drv_radio802154_energy_detected() may be
* 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 @sa nrf_drv_radio802154_energy_detected() call.
*
* @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(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);
/**
* @section Calls to higher layer.
*/
/**
* @brief Notify that receiving frame has started.
*
* @note It is possible the frame is dropped during receive procedure and
* @sa nrf_drv_radio802154_received won't be called.
* @note This function should be very short to prevent dropping frames by the driver.
*/
extern void nrf_drv_radio802154_rx_started(void);
/**
* @brief Notify that transmitting ACK frame has started.
*
* @note This function should be very short to prevent dropping frames by the driver.
*/
extern void nrf_drv_radio802154_tx_ack_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_raw() 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_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.
*
* 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_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 reception of a frame failed.
*
* @param[in] error An error code that indicates reason of the failure.
*/
extern void nrf_drv_radio802154_receive_failed(nrf_drv_radio802154_rx_error_t error);
/**
* @brief Notify that transmitting frame has started.
*
* @note It is possible that transmit procedure is interrupted and
* @sa nrf_drv_radio802154_transmitted won't be called.
* @note This function should be very short to prevent dropping frames by the driver.
*/
extern void nrf_drv_radio802154_tx_started(void);
/**
* @brief Notify that receiving ACK frame has started.
*
* @note It is possible that the frame being received is not expected ACK and
* @sa nrf_drv_radio802154_transmitted won't be called.
* @note This function should be very short to prevent dropping frames by the driver.
*/
extern void nrf_drv_radio802154_rx_ack_started(void);
/**
* @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_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 (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_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.
*
* This function is called if transmission procedure fails.
*
* @param[in] error Reason of the failure.
*/
extern void nrf_drv_radio802154_transmit_failed(nrf_drv_radio802154_tx_error_t error);
/**
* @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(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);
/**
* @section Driver memory management
*/
/**
* @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.
*/
void nrf_drv_radio802154_buffer_free(uint8_t * p_data);
/**
* @section RSSI measurement function.
*/
/**
* @brief Begin RSSI measurement.
*
* @note This function should be called in Receive state.
*
* Begin RSSI measurement. The result will be available in 8 uS. The result can be read by
* nrf_radio802154_rssi_last_get() function.
*/
void nrf_drv_radio802154_rssi_measure(void);
/**
* @brief Get result of last RSSI measurement.
*
* @returns RSSI measurement result [dBm].
*/
int8_t nrf_drv_radio802154_rssi_last_get(void);
/**
* @brief Adjust given RSSI measurement using a temperature correction factor.
*
* @param[in] rssi Measured RSSI value [dBm].
* @param[in] temp Temperature value when RSSI sample took place [C].
*
* @returns RSSI [dBm] corrected by a temperature factor (Errata 153).
*/
int8_t nrf_drv_radio802154_rssi_corrected_get(int8_t rssi, int8_t temp);
/**
* @section Promiscuous mode.
*/
/**
* @brief Enable or disable promiscuous radio mode.
*
* @note Promiscuous mode is disabled by default.
*
* In promiscuous mode driver notifies higher layer that it received any frame (regardless
* frame type or destination address).
* In normal mode (not promiscuous) higher layer is not notified about ACK frames and frames with
* unknown type. Also frames with destination address not matching this device address are ignored.
*
* @param[in] enabled If promiscuous mode should be enabled.
*/
void nrf_drv_radio802154_promiscuous_set(bool enabled);
/**
* @brief Check if radio is in promiscuous mode.
*
* @retval True Radio is in promiscuous mode.
* @retval False Radio is not in promiscuous mode.
*/
bool nrf_drv_radio802154_promiscuous_get(void);
/**
* @section Auto ACK management.
*/
/**
* @brief Enable or disable auto ACK procedure.
*
* @note Auto ACK procedure is enabled by default.
*
* If auto ACK procedure is enabled the driver prepares and sends ACK frames automatically
* aTurnaroundTime (192 us) after proper frame is received. The driver sets sequence number in
* the ACK frame and pending bit according to auto pending bit feature settings. When auto ACK
* procedure is enabled the driver notifies the next higher layer about received frame after ACK
* frame is transmitted.
* If auto ACK procedure is disabled the driver does not transmit ACK frames. It notifies the next
* higher layer about received frame when a frame is received. In this mode the next higher layer
* is responsible for sending ACK frame. ACK frames should be sent using
* nrf_drv_radio802154_transmit() function.
*
* @param[in] enabled If auto ACK procedure should be enabled.
*/
void nrf_drv_radio802154_auto_ack_set(bool enabled);
/**
* @brief Check if auto ACK procedure is enabled.
*
* @retval True Auto ACK procedure is enabled.
* @retval False Auto ACK procedure is disabled.
*/
bool nrf_drv_radio802154_auto_ack_get(void);
/**
* @brief Enable or disable setting pending bit in automatically transmitted ACK frames.
*
* @note Setting pending bit in automatically transmitted ACK frames is enabled by default.
*
* Radio driver automatically sends ACK frames in response to unicast frames destined to this node.
* Pending bit in ACK frame can be set or cleared regarding data in pending buffer destined to ACK
* destination.
*
* If setting pending bit in ACK frames is disabled, pending bit in every ACK frame is set.
* If setting pending bit in ACK frames is enabled, radio driver checks if there is data
* in pending buffer destined to ACK destination. If there is no such data, pending bit is cleared.
*
* @note It is possible that if there is a lot of supported peers radio driver cannot verify
* if there is pending data before ACK is sent. In this case pending bit is set.
*
* @param[in] enabled If setting pending bit in ACK frames is enabled.
*/
void nrf_drv_radio802154_auto_pending_bit_set(bool enabled);
/**
* @brief Add address of peer node for which there is pending data in the buffer.
*
* @note This function makes a copy of given address.
*
* @param[in] p_addr Array of bytes containing address of the node (little-endian).
* @param[in] extended If given address is Extended MAC Address or Short MAC Address.
*
* @retval True Address successfully added to the list.
* @retval False There is not enough memory to store this address in the list.
*/
bool nrf_drv_radio802154_pending_bit_for_addr_set(const uint8_t *p_addr, bool extended);
/**
* @brief Remove address of peer node for which there is no more pending data in the buffer.
*
* @param[in] p_addr Array of bytes containing address of the node (little-endian).
* @param[in] extended If given address is Extended MAC Address or Short MAC Address.
*
* @retval True Address successfully removed from the list.
* @retval False There is no such address in the list.
*/
bool nrf_drv_radio802154_pending_bit_for_addr_clear(const uint8_t *p_addr, bool extended);
/**
* @brief Remove all addresses of given type from pending bit list.
*
* @param[in] extended If function should remove all Exnteded MAC Adresses of all Short Addresses.
*/
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
#endif /* NRF_DRV_RADIO802154_H_ */
@@ -1,238 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements procedures to set pending bit in nRF 802.15.4 radio driver.
*
*/
#include "nrf_drv_radio802154_ack_pending_bit.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_drv_radio802154_config.h"
#include "nrf_drv_radio802154_const.h"
#include "hal/nrf_radio.h"
/// Maximum number of Short Addresses of nodes for which there is pending data in buffer.
#define NUM_PENDING_SHORT_ADDRESSES NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES
/// Maximum number of Extended Addresses of nodes for which there is pending data in buffer.
#define NUM_PENDING_EXTENDED_ADDRESSES NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES
/// Value used to mark Short Address as unused.
#define UNUSED_PENDING_SHORT_ADDRESS ((uint8_t [SHORT_ADDRESS_SIZE]) {0xff, 0xff})
/// Value used to mark Extended Address as unused.
#define UNUSED_PENDING_EXTENDED_ADDRESS ((uint8_t [EXTENDED_ADDRESS_SIZE]) {0})
/// If pending bit in ACK frame should be set to valid or default value.
static bool m_setting_pending_bit_enabled;
/// Array of Short Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_pending_short[NUM_PENDING_SHORT_ADDRESSES][SHORT_ADDRESS_SIZE];
/// Array of Extended Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_pending_extended[NUM_PENDING_EXTENDED_ADDRESSES][EXTENDED_ADDRESS_SIZE];
void nrf_drv_radio802154_ack_pending_bit_init(void)
{
memset(m_pending_extended, 0, sizeof(m_pending_extended));
memset(m_pending_short, 0xff, sizeof(m_pending_short));
m_setting_pending_bit_enabled = true;
}
void nrf_drv_radio802154_ack_pending_bit_set(bool enabled)
{
m_setting_pending_bit_enabled = enabled;
}
bool nrf_drv_radio802154_ack_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended)
{
uint8_t * p_empty_slot = NULL;
if (extended)
{
for (uint32_t i = 0; i < NUM_PENDING_EXTENDED_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_extended[i], p_addr, sizeof(m_pending_extended[i])))
{
return true;
}
if (0 == memcmp(m_pending_extended[i], UNUSED_PENDING_EXTENDED_ADDRESS, sizeof(m_pending_extended[i])))
{
p_empty_slot = m_pending_extended[i];
}
}
if (p_empty_slot != NULL)
{
memcpy(p_empty_slot, p_addr, EXTENDED_ADDRESS_SIZE);
return true;
}
}
else
{
for (uint32_t i = 0; i < NUM_PENDING_SHORT_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_short[i], p_addr, sizeof(m_pending_short[i])))
{
return true;
}
if (0 == memcmp(m_pending_short[i], UNUSED_PENDING_SHORT_ADDRESS, sizeof(m_pending_short[i])))
{
p_empty_slot = m_pending_short[i];
}
}
if (p_empty_slot != NULL)
{
memcpy(p_empty_slot, p_addr, SHORT_ADDRESS_SIZE);
return true;
}
}
return false;
}
bool nrf_drv_radio802154_ack_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended)
{
bool result = false;
if (extended)
{
for (uint32_t i = 0; i < NUM_PENDING_EXTENDED_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_extended[i], p_addr, sizeof(m_pending_extended[i])))
{
memset(m_pending_extended[i], 0, sizeof(m_pending_extended[i]));
result = true;
}
}
}
else
{
for (uint32_t i = 0; i < NUM_PENDING_SHORT_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_short[i], p_addr, sizeof(m_pending_short[i])))
{
memset(m_pending_short[i], 0xff, sizeof(m_pending_short[i]));
result = true;
}
}
}
return result;
}
void nrf_drv_radio802154_ack_pending_bit_for_addr_reset(bool extended)
{
if (extended)
{
memset(m_pending_extended, 0, sizeof(m_pending_extended));
}
else
{
memset(m_pending_short, 0xff, sizeof(m_pending_short));
}
}
bool nrf_drv_radio802154_ack_pending_bit_should_be_set(const uint8_t * p_psdu)
{
const uint8_t * p_src_addr;
uint32_t i;
// If automatic setting of pending bit in ACK frames is disabled the pending bit is always set.
if (!m_setting_pending_bit_enabled)
{
return true;
}
switch (p_psdu[DEST_ADDR_TYPE_OFFSET] & DEST_ADDR_TYPE_MASK)
{
case DEST_ADDR_TYPE_SHORT:
p_src_addr = &p_psdu[SRC_ADDR_OFFSET_SHORT_DST];
break;
case DEST_ADDR_TYPE_EXTENDED:
p_src_addr = &p_psdu[SRC_ADDR_OFFSET_EXTENDED_DST];
break;
default:
return true;
}
if (0 == (p_psdu[PAN_ID_COMPR_OFFSET] & PAN_ID_COMPR_MASK))
{
p_src_addr += PAN_ID_SIZE;
}
switch (p_psdu[SRC_ADDR_TYPE_OFFSET] & SRC_ADDR_TYPE_MASK)
{
case SRC_ADDR_TYPE_SHORT:
for (i = 0; i < NUM_PENDING_SHORT_ADDRESSES; i++)
{
if (nrf_radio_state_get() != NRF_RADIO_STATE_TX_RU)
{
break;
}
if (0 == memcmp(p_src_addr, m_pending_short[i], sizeof(m_pending_short[i])))
{
return true;
}
}
break;
case SRC_ADDR_TYPE_EXTENDED:
for (i = 0; i < NUM_PENDING_EXTENDED_ADDRESSES; i++)
{
if (nrf_radio_state_get() != NRF_RADIO_STATE_TX_RU)
{
break;
}
if (0 == memcmp(p_src_addr, m_pending_extended[i], sizeof(m_pending_extended[i])))
{
return true;
}
}
break;
default:
return true;
}
return false;
}
@@ -1,199 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_DRIVER_RADIO802154_CONFIG_H__
#define NRF_DRIVER_RADIO802154_CONFIG_H__
#ifdef NRF_DRV_RADIO802154_PROJECT_CONFIG
#include NRF_DRV_RADIO802154_PROJECT_CONFIG
#endif
#include <nrf.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_driver_radio802154_config 802.15.4 driver configuration
* @{
* @ingroup nrf_driver_radio802154
* @brief Configuration of 802.15.4 radio driver for nRF SoC.
*/
/*******************************************************************************
* @section Radio Driver Configuration.
******************************************************************************/
/**
* @def NRF_DRV_RADIO802154_CCA_MODE
*
* CCA Mode used by the driver.
*
*/
#ifndef NRF_DRV_RADIO802154_CCA_MODE_DEFAULT
#define NRF_DRV_RADIO802154_CCA_MODE_DEFAULT NRF_RADIO_CCA_MODE_ED
#endif
/**
* @def NRF_DRV_RADIO802154_CCA_ED_THRESHOLD
*
* Energy Detection Threshold used in CCA procedure.
*
*/
#ifndef NRF_DRV_RADIO802154_CCA_ED_THRESHOLD_DEFAULT
#define NRF_DRV_RADIO802154_CCA_ED_THRESHOLD_DEFAULT 0x2D
#endif
/**
* @def NRF_DRV_RADIO802154_CCA_CORR_THRESHOLD
*
* Correlator Threshold used in CCA procedure.
*
*/
#ifndef NRF_DRV_RADIO802154_CCA_CORR_THRESHOLD_DEFAULT
#define NRF_DRV_RADIO802154_CCA_CORR_THRESHOLD_DEFAULT 0x2D
#endif
/**
* @def NRF_DRV_RADIO802154_CCA_CORR_LIMIT
*
* Correlator limit used in CCA procedure.
*
*/
#ifndef NRF_DRV_RADIO802154_CCA_CORR_LIMIT_DEFAULT
#define NRF_DRV_RADIO802154_CCA_CORR_LIMIT_DEFAULT 0x02
#endif
/**
* @def NRF_DRV_RADIO802154_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.
*/
#ifndef NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
#if RAAL_SOFTDEVICE
#define NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING 0
#else // RAAL_SOFTDEVICE
#define NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING 1
#endif // RAAL_SOFTDEVICE
#endif // NRF_DRV_RADIO802154_INTERNAL_IRQ_HANDLING
/**
* @def NRF_DRV_RADIO802154_IRQ_PRIORITY
*
* Interrupt priority for RADIO peripheral.
* It is recommended to keep IRQ priority high (low number) to prevent losing frames due to
* preemption.
*
*/
#ifndef NRF_DRV_RADIO802154_IRQ_PRIORITY
#define NRF_DRV_RADIO802154_IRQ_PRIORITY 0
#endif
/**
* @def NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES
*
* Number of slots containing short addresses of nodes for which pending data is stored.
*
*/
#ifndef NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES
#define NRF_DRV_RADIO802154_PENDING_SHORT_ADDRESSES 10
#endif
/**
* @def NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES
*
* Number of slots containing extended addresses of nodes for which pending data is stored.
*
*/
#ifndef NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES
#define NRF_DRV_RADIO802154_PENDING_EXTENDED_ADDRESSES 10
#endif
/**
* @def NRF_DRV_RADIO802154_RX_BUFFERS
*
* Number of buffers in receive queue.
*
*/
#ifndef NRF_DRV_RADIO802154_RX_BUFFERS
#define NRF_DRV_RADIO802154_RX_BUFFERS 16
#endif
/**
* @def NRF_DRV_RADIO802154_SHORT_CCAIDLE_TXEN
*
* RADIO peripheral can start transmission using short CCAIDLE->TXEN or interrupt handler.
* If NRF_DRV_RADIO802154_SHORT_CCAIDLE_TXEN is set to 0 interrupt handler is used, otherwise
* short is used.
*
*/
#ifndef NRF_DRV_RADIO802154_SHORT_CCAIDLE_TXEN
#define NRF_DRV_RADIO802154_SHORT_CCAIDLE_TXEN 1
#endif
/**
* @def NRF_DRV_RADIO802154_NOTIFICATION_SWI_PRIORITY
*
* Priority of software interrupt used to call notification from 802.15.4 driver.
*
*/
#ifndef NRF_DRV_RADIO802154_NOTIFICATION_SWI_PRIORITY
#define NRF_DRV_RADIO802154_NOTIFICATION_SWI_PRIORITY 5
#endif
/**
* @def NRF_DRV_RADIO802154_CLOCK_IRQ_PRIORITY
*
* Priority of clock interrupt used in standalone clock driver implementation.
*
* @note This configuration is only applicable for Clock Abstraction Layer implementation
* in nrf_drv_radio802154_clock_nodrv.c.
*
*/
#ifndef NRF_DRV_RADIO802154_CLOCK_IRQ_PRIORITY
#define NRF_DRV_RADIO802154_CLOCK_IRQ_PRIORITY 10
#endif
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif // NRF_DRIVER_RADIO802154_CONFIG_H__
@@ -1,123 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements critical sections used with requests by 802.15.4 driver.
*
*/
#include "nrf_drv_radio802154_critical_section.h"
#include <assert.h>
#include <stdint.h>
#include "nrf_drv_radio802154_debug.h"
#include "nrf_drv_radio802154_fsm.h"
#include "hal/nrf_radio.h"
#include "platform/timer/nrf_drv_radio802154_timer.h"
#include "raal/nrf_raal_api.h"
#include <cmsis/core_cmFunc.h>
#if RAAL_SOFTDEVICE
// When Softdevice is selected as arbiter critical sections should not be nested.
#define PREVENT_NESTED_CRIT_SECTIONS 1
#endif // RAAL_SOFTDEVICE
#if PREVENT_NESTED_CRIT_SECTIONS
/// Flag indicating if the driver entered critical section.
static volatile bool m_in_critical_section;
#endif // PREVENT_NESTED_CRIT_SECTIONS
void nrf_drv_radio802154_critical_section_enter(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_CRIT_SECT_ENTER);
radio_state_t state;
#if PREVENT_NESTED_CRIT_SECTIONS
__disable_irq();
__DSB();
__ISB();
assert(!m_in_critical_section);
m_in_critical_section = true;
#endif // PREVENT_NESTED_CRIT_SECTIONS
nrf_drv_radio802154_timer_critical_section_enter();
nrf_raal_critical_section_enter();
state = nrf_drv_radio802154_fsm_state_get();
if (state != RADIO_STATE_WAITING_TIMESLOT &&
state != RADIO_STATE_SLEEP)
{
NVIC_DisableIRQ(RADIO_IRQn);
#if !RAAL_SOFTDEVICE
__DSB();
__ISB();
#endif // !RAAL_SOFTDEVICE
}
#if PREVENT_NESTED_CRIT_SECTIONS
__enable_irq();
#endif // PREVENT_NESTED_CRIT_SECTIONS
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_CRIT_SECT_ENTER);
}
void nrf_drv_radio802154_critical_section_exit(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_CRIT_SECT_EXIT);
#if PREVENT_NESTED_CRIT_SECTIONS
assert(m_in_critical_section);
m_in_critical_section = false;
#endif // PREVENT_NESTED_CRIT_SECTIONS
radio_state_t state;
// RAAL critical section shall be exited before RADIO IRQ handler is enabled. In other case
// RADIO IRQ handler may be called out of timeslot.
nrf_raal_critical_section_exit();
state = nrf_drv_radio802154_fsm_state_get();
if (state != RADIO_STATE_WAITING_TIMESLOT &&
state != RADIO_STATE_SLEEP)
{
NVIC_EnableIRQ(RADIO_IRQn);
}
nrf_drv_radio802154_timer_critical_section_exit();
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_CRIT_SECT_EXIT);
}
File diff suppressed because it is too large Load Diff
@@ -1,78 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements notifications triggered directly by the nrf 802.15.4 radio driver.
*
*/
#include "nrf_drv_radio802154_notification.h"
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154.h"
void nrf_drv_radio802154_notification_init(void)
{
// Intentionally empty
}
void nrf_drv_radio802154_notify_received(uint8_t * p_data, int8_t power, int8_t lqi)
{
nrf_drv_radio802154_received_raw(p_data, power, lqi);
}
void nrf_drv_radio802154_notify_receive_failed(nrf_drv_radio802154_rx_error_t error)
{
nrf_drv_radio802154_receive_failed(error);
}
void nrf_drv_radio802154_notify_transmitted(uint8_t * p_ack, int8_t power, int8_t lqi)
{
nrf_drv_radio802154_transmitted_raw(p_ack, power, lqi);
}
void nrf_drv_radio802154_notify_transmit_failed(nrf_drv_radio802154_tx_error_t error)
{
nrf_drv_radio802154_transmit_failed(error);
}
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);
}
@@ -1,230 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements storage of PIB attributes in nRF 802.15.4 radio driver.
*
*/
#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.
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.
void nrf_drv_radio802154_pib_init(void)
{
m_data.promiscuous = false;
m_data.auto_ack = true;
m_data.channel = 11;
memset(m_data.pan_id, 0xff, sizeof(m_data.pan_id));
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 = NRF_DRV_RADIO802154_CCA_MODE_DEFAULT;
m_data.cca.ed_threshold = NRF_DRV_RADIO802154_CCA_ED_THRESHOLD_DEFAULT;
m_data.cca.corr_threshold = NRF_DRV_RADIO802154_CCA_CORR_THRESHOLD_DEFAULT;
m_data.cca.corr_limit = NRF_DRV_RADIO802154_CCA_CORR_LIMIT_DEFAULT;
}
bool nrf_drv_radio802154_pib_promiscuous_get(void)
{
return m_data.promiscuous;
}
void nrf_drv_radio802154_pib_promiscuous_set(bool enabled)
{
m_data.promiscuous = enabled;
}
bool nrf_drv_radio802154_pib_auto_ack_get(void)
{
return m_data.auto_ack;
}
void nrf_drv_radio802154_pib_auto_ack_set(bool enabled)
{
m_data.auto_ack = enabled;
}
uint8_t nrf_drv_radio802154_pib_channel_get(void)
{
return m_data.channel;
}
void nrf_drv_radio802154_pib_channel_set(uint8_t channel)
{
m_data.channel = channel;
}
int8_t nrf_drv_radio802154_pib_tx_power_get(void)
{
return m_data.tx_power;
}
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;
}
void nrf_drv_radio802154_pib_pan_id_set(const uint8_t * p_pan_id)
{
memcpy(m_data.pan_id, p_pan_id, PAN_ID_SIZE);
}
void nrf_drv_radio802154_pib_extended_address_set(const uint8_t * p_extended_address)
{
memcpy(m_data.extended_addr, p_extended_address, EXTENDED_ADDRESS_SIZE);
}
void nrf_drv_radio802154_pib_short_address_set(const uint8_t * p_short_address)
{
memcpy(m_data.short_addr, p_short_address, SHORT_ADDRESS_SIZE);
}
bool nrf_drv_radio802154_pib_dest_addr_matches(const uint8_t * p_psdu)
{
// Check destination PAN Id.
// Note that +1 in PSDU offset is added because first byte in PSDU is length.
if ((0 != memcmp(&p_psdu[PAN_ID_OFFSET + 1], m_data.pan_id, PAN_ID_SIZE)) &&
(0 != memcmp(&p_psdu[PAN_ID_OFFSET + 1], BROADCAST_ADDRESS, PAN_ID_SIZE)))
{
return false;
}
// Check destination address.
switch (p_psdu[DEST_ADDR_TYPE_OFFSET] & DEST_ADDR_TYPE_MASK)
{
case DEST_ADDR_TYPE_SHORT:
{
// Note that +1 in PSDU offset is added because first byte in PSDU is length.
if ((0 != memcmp(&p_psdu[DEST_ADDR_OFFSET + 1],
m_data.short_addr,
SHORT_ADDRESS_SIZE)) &&
(0 != memcmp(&p_psdu[DEST_ADDR_OFFSET + 1],
BROADCAST_ADDRESS,
SHORT_ADDRESS_SIZE)))
{
return false;
}
break;
}
case DEST_ADDR_TYPE_EXTENDED:
{
// Note that +1 in PSDU offset is added because first byte in PSDU is length.
if (0 != memcmp(&p_psdu[DEST_ADDR_OFFSET + 1],
m_data.extended_addr,
sizeof(m_data.extended_addr)))
{
return false;
}
break;
}
default:
return false;
}
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));
}
@@ -1,144 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements requests to the driver triggered directly by the MAC layer.
*
*/
#include "nrf_drv_radio802154_request.h"
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154_critical_section.h"
#include "nrf_drv_radio802154_fsm.h"
#include "hal/nrf_radio.h"
#include <cmsis/core_cmFunc.h>
void nrf_drv_radio802154_request_init(void)
{
// Intentionally empty
}
bool nrf_drv_radio802154_request_sleep(void)
{
bool result;
nrf_drv_radio802154_critical_section_enter();
result = nrf_drv_radio802154_fsm_sleep();
nrf_drv_radio802154_critical_section_exit();
return result;
}
bool nrf_drv_radio802154_request_receive(void)
{
bool result;
nrf_drv_radio802154_critical_section_enter();
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, bool cca)
{
bool result;
nrf_drv_radio802154_critical_section_enter();
result = nrf_drv_radio802154_fsm_transmit(p_data, cca);
nrf_drv_radio802154_critical_section_exit();
return result;
}
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(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;
}
void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data)
{
nrf_drv_radio802154_critical_section_enter();
nrf_drv_radio802154_fsm_notify_buffer_free((rx_buffer_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();
}
@@ -1,236 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements requests to the driver triggered by the MAC layer through SWI.
*
*/
#include "nrf_drv_radio802154_request.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154_config.h"
#include "nrf_drv_radio802154_critical_section.h"
#include "nrf_drv_radio802154_debug.h"
#include "nrf_drv_radio802154_fsm.h"
#include "nrf_drv_radio802154_rx_buffer.h"
#include "nrf_drv_radio802154_swi.h"
#include "hal/nrf_radio.h"
#include <cmsis/core_cmFunc.h>
#include <cmsis/core_cm4.h>
#define CMSIS_IRQ_NUM_VECTACTIVE_DIFF 16
/** Check if active vector priority is high enough to call requests directly.
*
* @retval true Active vector priority is greater or equal to SWI priority.
* @retval false Active vector priority is lower than SWI priority.
*/
static bool active_vector_priority_is_high(void)
{
uint32_t active_vector_id = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
IRQn_Type irq_number;
uint32_t active_priority;
// Check if this function is called from main thread.
if (active_vector_id == 0)
{
return false;
}
assert(active_vector_id >= CMSIS_IRQ_NUM_VECTACTIVE_DIFF);
irq_number = (IRQn_Type)(active_vector_id - CMSIS_IRQ_NUM_VECTACTIVE_DIFF);
active_priority = NVIC_GetPriority(irq_number);
return active_priority <= NRF_DRV_RADIO802154_NOTIFICATION_SWI_PRIORITY;
}
void nrf_drv_radio802154_request_init(void)
{
nrf_drv_radio802154_swi_init();
}
bool nrf_drv_radio802154_request_sleep(void)
{
bool result = false;
if (active_vector_priority_is_high())
{
nrf_drv_radio802154_critical_section_enter();
result = nrf_drv_radio802154_fsm_sleep();
nrf_drv_radio802154_critical_section_exit();
}
else
{
nrf_drv_radio802154_swi_sleep(&result);
}
return result;
}
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();
nrf_drv_radio802154_critical_section_exit();
}
else
{
nrf_drv_radio802154_swi_receive(&result);
}
return result;
}
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, cca);
nrf_drv_radio802154_critical_section_exit();
}
else
{
nrf_drv_radio802154_swi_transmit(p_data, cca, &result);
}
return result;
}
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(time_us);
nrf_drv_radio802154_critical_section_exit();
}
else
{
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;
}
void nrf_drv_radio802154_request_buffer_free(uint8_t * p_data)
{
if (active_vector_priority_is_high())
{
nrf_drv_radio802154_critical_section_enter();
nrf_drv_radio802154_fsm_notify_buffer_free((rx_buffer_t *)p_data);
nrf_drv_radio802154_critical_section_exit();
}
else
{
nrf_drv_radio802154_swi_buffer_free(p_data);
}
}
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();
}
}
@@ -1,673 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements SWI manager for nRF 802.15.4 driver.
*
*/
#include "nrf_drv_radio802154_swi.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154.h"
#include "nrf_drv_radio802154_config.h"
#include "nrf_drv_radio802154_critical_section.h"
#include "nrf_drv_radio802154_fsm.h"
#include "nrf_drv_radio802154_rx_buffer.h"
#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
* detection.
*/
#define NTF_QUEUE_SIZE (NRF_DRV_RADIO802154_RX_BUFFERS + 3)
/** Size of requests queue.
*
* Two is minimal queue size. It is not expected in current implementation to queue a few requests.
*/
#define REQ_QUEUE_SIZE 2
#define SWI_EGU NRF_EGU3 ///< Label of SWI peripheral.
#define SWI_IRQn SWI3_EGU3_IRQn ///< Symbol of SWI IRQ number.
#define SWI_IRQHandler SWI3_EGU3_IRQHandler ///< Symbol of SWI IRQ handler.
#define NTF_INT NRF_EGU_INT_TRIGGERED0 ///< Label of notification interrupt.
#define NTF_TASK NRF_EGU_TASK_TRIGGER0 ///< Label of notification task.
#define NTF_EVENT NRF_EGU_EVENT_TRIGGERED0 ///< Label of notification event.
#define TIMESLOT_EXIT_INT NRF_EGU_INT_TRIGGERED1 ///< Label of timeslot exit interrupt.
#define TIMESLOT_EXIT_TASK NRF_EGU_TASK_TRIGGER1 ///< Label of timeslot exit task.
#define TIMESLOT_EXIT_EVENT NRF_EGU_EVENT_TRIGGERED1 ///< Label of timeslot exit event.
#define REQ_INT NRF_EGU_INT_TRIGGERED2 ///< Label of request interrupt.
#define REQ_TASK NRF_EGU_TASK_TRIGGER2 ///< Label of request task.
#define REQ_EVENT NRF_EGU_EVENT_TRIGGERED2 ///< Label of request event.
/// Types of notifications in notification queue.
typedef enum
{
NTF_TYPE_RECEIVED, ///< Frame received
NTF_TYPE_RECEIVE_FAILED, ///< Frame reception failed
NTF_TYPE_TRANSMITTED, ///< Frame transmitted
NTF_TYPE_TRANSMIT_FAILED, ///< 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.
typedef struct
{
nrf_drv_radio802154_ntf_type_t type; ///< Notification type.
union
{
struct
{
uint8_t * p_psdu; ///< Pointer to received frame PSDU.
int8_t power; ///< RSSI of received frame.
int8_t lqi; ///< LQI of received frame.
} received; ///< Received frame details.
struct
{
uint8_t * p_psdu; ///< Pointer to received ACK PSDU or NULL.
int8_t power; ///< RSSI of received ACK or 0.
int8_t lqi; ///< LQI of received ACK or 0.
} transmitted; ///< Transmitted frame details.
struct
{
nrf_drv_radio802154_tx_error_t error; ///< An error code that indicates reason of the failure.
} transmit_failed;
struct
{
nrf_drv_radio802154_rx_error_t error; ///< An error code that indicates reason of the failure.
} receive_failed;
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;
/// Type of requests in request queue.
typedef enum
{
REQ_TYPE_SLEEP,
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.
typedef struct
{
nrf_drv_radio802154_req_type_t type; ///< Type of the request.
union
{
struct
{
bool * p_result; ///< Sleep request result.
} sleep; ///< Sleep request details.
struct
{
bool * p_result; ///< Receive request result.
} receive; ///< Receive request details.
struct
{
bool * p_result; ///< Transmit request result.
const uint8_t * p_data; ///< Pointer to PSDU to transmit.
bool cca; ///< If CCA was requested prior to transmission.
} transmit; ///< Transmit request details.
struct
{
bool * p_result; ///< Energy detection request result.
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.
} buffer_free; ///< Buffer free request details.
} data; ///< Request data depending on it's type.
} nrf_drv_radio802154_req_data_t;
static nrf_drv_radio802154_ntf_data_t m_ntf_queue[NTF_QUEUE_SIZE]; ///< Notification queue.
static uint8_t m_ntf_r_ptr; ///< Notification queue read index.
static uint8_t m_ntf_w_ptr; ///< Notification queue write index.
static nrf_drv_radio802154_req_data_t m_req_queue[REQ_QUEUE_SIZE]; ///< Request queue.
static uint8_t m_req_r_ptr; // Request queue read index.
static uint8_t m_req_w_ptr; // Request queue write index.
/**
* Increment given index for any queue.
*
* @param[inout] p_ptr Index to increment.
* @param[in] queue_size Number of elements in the queue.
*/
static void queue_ptr_increment(uint8_t * p_ptr, uint8_t queue_size)
{
if (++(*p_ptr) >= queue_size)
{
*p_ptr = 0;
}
}
/**
* Check if given queue is full.
*
* @param[in] r_ptr Read index associated with given queue.
* @param[in] w_ptr Write index associated with given queue.
* @param[in] queue_size Number of elements in the queue.
*
* @retval true Given queue is full.
* @retval false Given queue is not full.
*/
static bool queue_is_full(uint8_t r_ptr, uint8_t w_ptr, uint8_t queue_size)
{
if (w_ptr == (r_ptr - 1))
{
return true;
}
if ((r_ptr == 0) && (w_ptr == queue_size - 1))
{
return true;
}
return false;
}
/**
* Check if given queue is empty.
*
* @param[in] r_ptr Read index associated with given queue.
* @param[in] w_ptr Write index associated with given queue.
*
* @retval true Given queue is empty.
* @retval false Given queue is not empty.
*/
static bool queue_is_empty(uint8_t r_ptr, uint8_t w_ptr)
{
return (r_ptr == w_ptr);
}
/**
* Increment given index associated with notification queue.
*
* @param[inout] p_ptr Pointer to the index to increment.
*/
static void ntf_queue_ptr_increment(uint8_t * p_ptr)
{
queue_ptr_increment(p_ptr, NTF_QUEUE_SIZE);
}
/**
* Check if notification queue is full.
*
* @retval true Notification queue is full.
* @retval false Notification queue is not full.
*/
static bool ntf_queue_is_full(void)
{
return queue_is_full(m_ntf_r_ptr, m_ntf_w_ptr, NTF_QUEUE_SIZE);
}
/**
* Check if notification queue is empty.
*
* @retval true Notification queue is empty.
* @retval false Notification queue is not empty.
*/
static bool ntf_queue_is_empty(void)
{
return queue_is_empty(m_ntf_r_ptr, m_ntf_w_ptr);
}
/**
* Increment given index associated with request queue.
*
* @param[inout] p_ptr Pointer to the index to increment.
*/
static void req_queue_ptr_increment(uint8_t * p_ptr)
{
queue_ptr_increment(p_ptr, REQ_QUEUE_SIZE);
}
/**
* Check if request queue is full.
*
* @retval true Request queue is full.
* @retval false Request queue is not full.
*/
static bool req_queue_is_full(void)
{
return queue_is_full(m_req_r_ptr, m_req_w_ptr, REQ_QUEUE_SIZE);
}
/**
* Check if request queue is empty.
*
* @retval true Request queue is empty.
* @retval false Request queue is not empty.
*/
static bool req_queue_is_empty(void)
{
return queue_is_empty(m_req_r_ptr, m_req_w_ptr);
}
/**
* 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;
m_ntf_w_ptr = 0;
nrf_egu_int_enable(SWI_EGU,
NTF_INT |
TIMESLOT_EXIT_INT |
REQ_INT);
NVIC_SetPriority(SWI_IRQn, NRF_DRV_RADIO802154_NOTIFICATION_SWI_PRIORITY);
NVIC_ClearPendingIRQ(SWI_IRQn);
NVIC_EnableIRQ(SWI_IRQn);
}
void nrf_drv_radio802154_swi_notify_received(uint8_t * p_data, int8_t power, int8_t lqi)
{
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_RECEIVED;
p_slot->data.received.p_psdu = p_data;
p_slot->data.received.power = power;
p_slot->data.received.lqi = lqi;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_drv_radio802154_swi_notify_receive_failed(nrf_drv_radio802154_rx_error_t error)
{
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_RECEIVE_FAILED;
p_slot->data.receive_failed.error = error;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_drv_radio802154_swi_notify_transmitted(uint8_t * p_data, int8_t power, int8_t lqi)
{
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_TRANSMITTED;
p_slot->data.transmitted.p_psdu = p_data;
p_slot->data.transmitted.power = power;
p_slot->data.transmitted.lqi = lqi;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_drv_radio802154_swi_notify_transmit_failed(nrf_drv_radio802154_tx_error_t error)
{
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_TRANSMIT_FAILED;
p_slot->data.transmit_failed.error = error;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
nrf_egu_task_trigger(SWI_EGU, NTF_TASK);
}
void nrf_drv_radio802154_swi_notify_energy_detected(uint8_t result)
{
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_ENERGY_DETECTED;
p_slot->data.energy_detected.result = result;
ntf_queue_ptr_increment(&m_ntf_w_ptr);
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));
nrf_egu_task_trigger(SWI_EGU, TIMESLOT_EXIT_TASK);
}
void nrf_drv_radio802154_swi_sleep(bool * p_result)
{
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_exit();
}
void nrf_drv_radio802154_swi_receive(bool * p_result)
{
nrf_drv_radio802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_RECEIVE;
p_slot->data.receive.p_result = p_result;
req_exit();
}
void nrf_drv_radio802154_swi_transmit(const uint8_t * p_data, bool cca, bool * p_result)
{
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.cca = cca;
p_slot->data.transmit.p_result = p_result;
req_exit();
}
void nrf_drv_radio802154_swi_energy_detection(uint32_t time_us, bool * p_result)
{
nrf_drv_radio802154_req_data_t * p_slot = req_enter();
p_slot->type = REQ_TYPE_ENERGY_DETECTION;
p_slot->data.energy_detection.time_us = time_us;
p_slot->data.energy_detection.p_result = p_result;
req_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_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_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)
{
if (nrf_egu_event_check(SWI_EGU, NTF_EVENT))
{
nrf_egu_event_clear(SWI_EGU, NTF_EVENT);
while (!ntf_queue_is_empty())
{
nrf_drv_radio802154_ntf_data_t * p_slot = &m_ntf_queue[m_ntf_r_ptr];
switch (p_slot->type)
{
case NTF_TYPE_RECEIVED:
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_RECEIVE_FAILED:
nrf_drv_radio802154_receive_failed(p_slot->data.receive_failed.error);
break;
case NTF_TYPE_TRANSMITTED:
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_TRANSMIT_FAILED:
nrf_drv_radio802154_transmit_failed(p_slot->data.transmit_failed.error);
break;
case NTF_TYPE_ENERGY_DETECTED:
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);
}
ntf_queue_ptr_increment(&m_ntf_r_ptr);
}
}
if (nrf_egu_event_check(SWI_EGU, TIMESLOT_EXIT_EVENT))
{
nrf_raal_continuous_mode_exit();
nrf_egu_event_clear(SWI_EGU, TIMESLOT_EXIT_EVENT);
}
if (nrf_egu_event_check(SWI_EGU, REQ_EVENT))
{
nrf_egu_event_clear(SWI_EGU, REQ_EVENT);
while (!req_queue_is_empty())
{
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:
*(p_slot->data.sleep.p_result) = nrf_drv_radio802154_fsm_sleep();
break;
case REQ_TYPE_RECEIVE:
*(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.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.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);
}
}
}
@@ -1,178 +0,0 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_DRIVER_RADIO802154_SWI_H__
#define NRF_DRIVER_RADIO802154_SWI_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_drv_radio802154.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_driver_radio802154_swi 802.15.4 driver SWI management
* @{
* @ingroup nrf_driver_radio802154
* @brief SWI manager for 802.15.4 driver.
*/
/**
* @brief Initialize SWI module.
*/
void nrf_drv_radio802154_swi_init(void);
/**
* @brief Notify next higher layer that a frame was received from SWI priority level.
*
* @param[in] p_data Array of bytes containing PSDU. First byte contains frame length, other contain the frame itself.
* @param[in] power RSSI measured during the frame reception.
* @param[in] lqi LQI indicating measured link quality during the frame reception.
*/
void nrf_drv_radio802154_swi_notify_received(uint8_t * p_data, int8_t power, int8_t lqi);
/**
* @brief Notify next higher layer that reception of a frame failed.
*
* @param[in] error An error code that indicates reason of the failure.
*/
void nrf_drv_radio802154_swi_notify_receive_failed(nrf_drv_radio802154_rx_error_t error);
/**
* @brief Notify next higher layer that a frame was transmitted from SWI priority level.
*
* @param[in] p_ack Pointer to buffer containing PSDU of ACK frame. NULL if ACK was not requested.
* @param[in] power RSSI of received frame or 0 if ACK was not requested.
* @param[in] lqi LQI of received frame of 0 if ACK was not requested.
*/
void nrf_drv_radio802154_swi_notify_transmitted(uint8_t * p_data, int8_t power, int8_t lqi);
/**
* @brief Notify next higher layer that a frame was not transmitted from SWI priority level.
*
* @param[in] error Reason of the transmission failure.
*/
void nrf_drv_radio802154_swi_notify_transmit_failed(nrf_drv_radio802154_tx_error_t error);
/**
* @brief Notify next higher layer that energy detection procedure ended from SWI priority level.
*
* @param[in] result Detected energy level.
*/
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.
*
* @note This function should be called through notification module to prevent calling it from arbiter context.
*/
void nrf_drv_radio802154_swi_timeslot_exit(void);
/**
* @brief Request entering sleep state from SWI priority.
*
* @param[out] p_result Result of entering sleep state.
*/
void nrf_drv_radio802154_swi_sleep(bool * p_result);
/**
* @brief Request entering receive state from SWI priority.
*
* @param[out] p_result Result of entering receive state.
*/
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] 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, bool cca, bool * p_result);
/**
* @brief Request entering energy detection state from SWI priority.
*
* @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(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.
*
* @param[in] p_data Pointer to the buffer to free.
*/
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);
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif // NRF_DRIVER_RADIO802154_SWI_H__
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,8 +40,8 @@
*
*/
#ifndef NRF_DRV_RADIO802154_CLOCK_H_
#define NRF_DRV_RADIO802154_CLOCK_H_
#ifndef NRF_802154_CLOCK_H_
#define NRF_802154_CLOCK_H_
#include <stdbool.h>
@@ -50,9 +50,9 @@ extern "C" {
#endif
/**
* @defgroup nrf_drv_radio802154_clock Clock Abstraction Layer for the 802.15.4 driver
* @defgroup nrf_802154_clock Clock Abstraction Layer for the 802.15.4 driver
* @{
* @ingroup nrf_drv_radio802154_clock
* @ingroup nrf_802154_clock
* @brief Clock Abstraction Layer interface for the 802.15.4 driver.
*
*/
@@ -60,25 +60,25 @@ extern "C" {
/**
* @brief Initialize the clock driver.
*/
void nrf_drv_radio802154_clock_init(void);
void nrf_802154_clock_init(void);
/**
* @brief Deinitialize the clock driver.
*/
void nrf_drv_radio802154_clock_deinit(void);
void nrf_802154_clock_deinit(void);
/**
* @brief Start High Frequency Clock.
*
* This function is asynchronous. It should request ramping up of HF clock and exit. When HF clock
* is ready @sa nrf_drv_radio802154_hfclk_ready() should be called.
* is ready @sa nrf_802154_hfclk_ready() should be called.
*/
void nrf_drv_radio802154_clock_hfclk_start(void);
void nrf_802154_clock_hfclk_start(void);
/**
* @brief Stop High Frequency Clock.
*/
void nrf_drv_radio802154_clock_hfclk_stop(void);
void nrf_802154_clock_hfclk_stop(void);
/**
* @brief Check if High Frequency Clock is running.
@@ -86,20 +86,20 @@ void nrf_drv_radio802154_clock_hfclk_stop(void);
* @retval true If High Frequency Clock is running.
* @retval false If High Frequency Clock is not running.
*/
bool nrf_drv_radio802154_clock_hfclk_is_running(void);
bool nrf_802154_clock_hfclk_is_running(void);
/**
* @brief Start Low Frequency Clock.
*
* This function is asynchronous. It should request ramping up of LF clock and exit. When LF clock
* is ready @sa nrf_drv_radio802154_lfclk_ready() should be called.
* is ready @sa nrf_802154_lfclk_ready() should be called.
*/
void nrf_drv_radio802154_clock_lfclk_start(void);
void nrf_802154_clock_lfclk_start(void);
/**
* @brief Stop Low Frequency Clock.
*/
void nrf_drv_radio802154_clock_lfclk_stop(void);
void nrf_802154_clock_lfclk_stop(void);
/**
* @brief Check if Low Frequency Clock is running.
@@ -107,17 +107,17 @@ void nrf_drv_radio802154_clock_lfclk_stop(void);
* @retval true If Low Frequency Clock is running.
* @retval false If Low Frequency Clock is not running.
*/
bool nrf_drv_radio802154_clock_lfclk_is_running(void);
bool nrf_802154_clock_lfclk_is_running(void);
/**
* @brief Callback executed when High Frequency Clock is ready.
*/
extern void nrf_drv_radio802154_clock_hfclk_ready(void);
extern void nrf_802154_clock_hfclk_ready(void);
/**
* @brief Callback executed when Low Frequency Clock is ready.
*/
extern void nrf_drv_radio802154_clock_lfclk_ready(void);
extern void nrf_802154_clock_lfclk_ready(void);
/**
*@}
@@ -127,4 +127,4 @@ extern void nrf_drv_radio802154_clock_lfclk_ready(void);
}
#endif
#endif /* NRF_DRV_RADIO802154_CLOCK_H_ */
#endif /* NRF_802154_CLOCK_H_ */
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,16 +35,18 @@
* This implementation uses directly CLOCK hardware registers.
*/
#include "nrf_drv_radio802154_clock.h"
#include "nrf_802154_clock.h"
#include <nrf.h>
#include <hal/nrf_clock.h>
#include "nrf_drv_radio802154_config.h"
#include "nrf_802154_config.h"
void nrf_drv_radio802154_clock_init(void)
void nrf_802154_clock_init(void)
{
NVIC_SetPriority(POWER_CLOCK_IRQn, NRF_DRV_RADIO802154_CLOCK_IRQ_PRIORITY);
nrf_clock_lf_src_set(NRF_802154_CLOCK_LFCLK_SOURCE);
NVIC_SetPriority(POWER_CLOCK_IRQn, NRF_802154_CLOCK_IRQ_PRIORITY);
NVIC_ClearPendingIRQ(POWER_CLOCK_IRQn);
NVIC_EnableIRQ(POWER_CLOCK_IRQn);
@@ -52,7 +54,7 @@ void nrf_drv_radio802154_clock_init(void)
nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK);
}
void nrf_drv_radio802154_clock_deinit(void)
void nrf_802154_clock_deinit(void)
{
NVIC_DisableIRQ(POWER_CLOCK_IRQn);
NVIC_ClearPendingIRQ(POWER_CLOCK_IRQn);
@@ -61,34 +63,34 @@ void nrf_drv_radio802154_clock_deinit(void)
nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK);
}
void nrf_drv_radio802154_clock_hfclk_start(void)
void nrf_802154_clock_hfclk_start(void)
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
}
void nrf_drv_radio802154_clock_hfclk_stop(void)
void nrf_802154_clock_hfclk_stop(void)
{
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
}
bool nrf_drv_radio802154_clock_hfclk_is_running(void)
bool nrf_802154_clock_hfclk_is_running(void)
{
return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
}
void nrf_drv_radio802154_clock_lfclk_start(void)
void nrf_802154_clock_lfclk_start(void)
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
}
void nrf_drv_radio802154_clock_lfclk_stop(void)
void nrf_802154_clock_lfclk_stop(void)
{
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTOP);
}
bool nrf_drv_radio802154_clock_lfclk_is_running(void)
bool nrf_802154_clock_lfclk_is_running(void)
{
return nrf_clock_lf_is_running();
}
@@ -99,23 +101,23 @@ void POWER_CLOCK_IRQHandler(void)
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_drv_radio802154_clock_hfclk_ready();
nrf_802154_clock_hfclk_ready();
}
if (nrf_clock_event_check(NRF_CLOCK_EVENT_LFCLKSTARTED))
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
nrf_drv_radio802154_clock_lfclk_ready();
nrf_802154_clock_lfclk_ready();
}
}
__WEAK void nrf_drv_radio802154_clock_hfclk_ready(void)
__WEAK void nrf_802154_clock_hfclk_ready(void)
{
// Intentionally empty.
}
__WEAK void nrf_drv_radio802154_clock_lfclk_ready(void)
__WEAK void nrf_802154_clock_lfclk_ready(void)
{
// Intentionally empty.
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
* This implementation uses clock driver implementation from SDK.
*/
#include "nrf_drv_radio802154_clock.h"
#include "nrf_802154_clock.h"
#include <stddef.h>
@@ -54,61 +54,61 @@ static void clock_handler(nrf_drv_clock_evt_type_t event)
{
if (event == NRF_DRV_CLOCK_EVT_HFCLK_STARTED)
{
nrf_drv_radio802154_clock_hfclk_ready();
nrf_802154_clock_hfclk_ready();
}
if (event == NRF_DRV_CLOCK_EVT_LFCLK_STARTED)
{
nrf_drv_radio802154_clock_lfclk_ready();
nrf_802154_clock_lfclk_ready();
}
}
void nrf_drv_radio802154_clock_init(void)
void nrf_802154_clock_init(void)
{
nrf_drv_clock_init();
}
void nrf_drv_radio802154_clock_deinit(void)
void nrf_802154_clock_deinit(void)
{
nrf_drv_clock_uninit();
}
void nrf_drv_radio802154_clock_hfclk_start(void)
void nrf_802154_clock_hfclk_start(void)
{
nrf_drv_clock_hfclk_request(&m_clock_handler);
}
void nrf_drv_radio802154_clock_hfclk_stop(void)
void nrf_802154_clock_hfclk_stop(void)
{
nrf_drv_clock_hfclk_release();
}
bool nrf_drv_radio802154_clock_hfclk_is_running(void)
bool nrf_802154_clock_hfclk_is_running(void)
{
return nrf_drv_clock_hfclk_is_running();
}
void nrf_drv_radio802154_clock_lfclk_start(void)
void nrf_802154_clock_lfclk_start(void)
{
nrf_drv_clock_lfclk_request(&m_clock_handler);
}
void nrf_drv_radio802154_clock_lfclk_stop(void)
void nrf_802154_clock_lfclk_stop(void)
{
nrf_drv_clock_lfclk_release();
}
bool nrf_drv_radio802154_clock_lfclk_is_running(void)
bool nrf_802154_clock_lfclk_is_running(void)
{
return nrf_drv_clock_lfclk_is_running();
}
__WEAK void nrf_drv_radio802154_clock_hfclk_ready(void)
__WEAK void nrf_802154_clock_hfclk_ready(void)
{
// Intentionally empty.
}
__WEAK void nrf_drv_radio802154_clock_lfclk_ready(void)
__WEAK void nrf_802154_clock_lfclk_ready(void)
{
// Intentionally empty.
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
*
*/
#ifndef NRF_DRV_RADIO802154_TIMER_API_H_
#define NRF_DRV_RADIO802154_TIMER_API_H_
#ifndef NRF_802154_TIMER_API_H_
#define NRF_802154_TIMER_API_H_
#include <stdbool.h>
#include <stdint.h>
@@ -44,9 +44,9 @@ extern "C" {
#endif
/**
* @defgroup nrf_drv_radio802154_timer Timer Abstraction Layer for the 802.15.4 driver
* @defgroup nrf_802154_timer Timer Abstraction Layer for the 802.15.4 driver
* @{
* @ingroup nrf_drv_radio802154_timer
* @ingroup nrf_802154_timer
* @brief Timer Abstraction Layer interface for the 802.15.4 driver.
*
* Timer Abstraction Layer is an abstraction layer of timer that is meant to be used by
@@ -61,51 +61,51 @@ extern "C" {
* @note Most of Timer Abstraction Layer API should not be called directly by 802.15.4 driver
* modules. This API is used by the Timer Scheduler module included in the driver and other
* modules should use Timer Scheduler API. Exception from above rule are initialization and
* deinitialization functions @sa nrf_drv_radio802154_timer_init()
* @sa nrf_drv_radio802154_timer_deinit() and critical section management
* @sa nrf_drv_radio802154_timer_critical_section_enter()
* @sa nrf_drv_radio802154_timer_critical_section_exit() as these functions are called from
* nrf_drv_radio802154_critical_section module and from global initialization functions
* @sa nrf_drv_radio802154_init() @sa nrf_drv_radio802154_deinit().
* deinitialization functions @sa nrf_802154_timer_init()
* @sa nrf_802154_timer_deinit() and critical section management
* @sa nrf_802154_timer_critical_section_enter()
* @sa nrf_802154_timer_critical_section_exit() as these functions are called from
* nrf_802154_critical_section module and from global initialization functions
* @sa nrf_802154_init() @sa nrf_802154_deinit().
*/
/**
* @brief Initialize Timer.
*/
void nrf_drv_radio802154_timer_init(void);
void nrf_802154_timer_init(void);
/**
* @brief Uninitialize Timer.
*/
void nrf_drv_radio802154_timer_deinit(void);
void nrf_802154_timer_deinit(void);
/**
* @brief Enter critical section of the timer.
*
* In critical section timer cannot execute @sa nrf_drv_radio802154_timer_fired() function.
* In critical section timer cannot execute @sa nrf_802154_timer_fired() function.
*
* @note Critical section cannot be nested.
*/
void nrf_drv_radio802154_timer_critical_section_enter(void);
void nrf_802154_timer_critical_section_enter(void);
/**
* @brief Exit critical section of the timer.
*
* In critical section timer cannot execute @sa nrf_drv_radio802154_timer_fired() function.
* In critical section timer cannot execute @sa nrf_802154_timer_fired() function.
*
* @note Critical section cannot be nested.
*/
void nrf_drv_radio802154_timer_critical_section_exit(void);
void nrf_802154_timer_critical_section_exit(void);
/**
* @brief Get current time.
*
* Prior to getting current time, Timer must be initialized @sa nrf_drv_radio802154_timer_init().
* Prior to getting current time, Timer must be initialized @sa nrf_802154_timer_init().
* There are no other requirements that must be fulfilled before using this function.
*
* @return Current time in microseconds [us].
*/
uint32_t nrf_drv_radio802154_timer_time_get(void);
uint32_t nrf_802154_timer_time_get(void);
/**
* @brief Get granularity of currently used timer.
@@ -114,7 +114,7 @@ uint32_t nrf_drv_radio802154_timer_time_get(void);
*
* @return Timer granularity in microseconds [us].
*/
uint32_t nrf_drv_radio802154_timer_granularity_get(void);
uint32_t nrf_802154_timer_granularity_get(void);
/**
* @brief Start one-shot timer that expires at specified time.
@@ -123,18 +123,18 @@ uint32_t nrf_drv_radio802154_timer_granularity_get(void);
* If timer is running when this function is called, previously running timer will be stopped
* automatically.
*
* On timer expiration @sa nrf_drv_radio802154_timer_fired function will be called.
* On timer expiration @sa nrf_802154_timer_fired function will be called.
* Timer automatically stops after expiration.
*
* @param[in] t0 Number of microseconds representing timer start time.
* @param[in] dt Time of timer expiration as time elapsed from @p t0 [us].
*/
void nrf_drv_radio802154_timer_start(uint32_t t0, uint32_t dt);
void nrf_802154_timer_start(uint32_t t0, uint32_t dt);
/**
* @brief Stop currently running timer.
*/
void nrf_drv_radio802154_timer_stop(void);
void nrf_802154_timer_stop(void);
/**
* @brief Check if timer is currently running.
@@ -142,12 +142,12 @@ void nrf_drv_radio802154_timer_stop(void);
* @retval true Timer is running.
* @retval false Timer is not running.
*/
bool nrf_drv_radio802154_timer_is_running(void);
bool nrf_802154_timer_is_running(void);
/**
* @brief Callback executed when timer expires.
*/
extern void nrf_drv_radio802154_timer_fired(void);
extern void nrf_802154_timer_fired(void);
/**
*@}
@@ -157,4 +157,4 @@ extern void nrf_drv_radio802154_timer_fired(void);
}
#endif
#endif /* NRF_DRV_RADIO802154_TIMER_API_H_ */
#endif /* NRF_802154_TIMER_API_H_ */
@@ -0,0 +1,411 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file contains standalone implementation of the nRF 802.15.4 timer abstraction.
*
* This implementation is built on top of the RTC peripheral.
*
*/
#include "nrf_802154_timer.h"
#include <assert.h>
#include <hal/nrf_rtc.h>
#include <nrf.h>
#include "platform/clock/nrf_802154_clock.h"
#include "nrf_802154_config.h"
#define RTC_COMPARE_CHANNEL 0
#define RTC_COMPARE_INT_MASK NRF_RTC_INT_COMPARE0_MASK
#define RTC_COMPARE_EVENT NRF_RTC_EVENT_COMPARE_0
#define RTC_COMPARE_EVENT_MASK RTC_EVTEN_COMPARE0_Msk
#define RTC_FREQUENCY 32768ULL
#define US_PER_S 1000000ULL
#define US_PER_TICK CEIL_DIV(US_PER_S, RTC_FREQUENCY)
#define US_PER_OVERFLOW (512UL * US_PER_S) ///< Time that has passed between overflow events. On full RTC speed, it occurs every 512 s.
#define FREQUENCY_US_PER_S_GDD_BITS 6 ///< Number of bits to shift RTC_FREQUENCY and US_PER_S to achieve division by greatest common divisor.
#define CEIL_DIV(A, B) (((A) + (B) - 1) / (B))
static volatile uint32_t m_offset_counter; ///< Counter of RTC overflows, incremented by 2 on each OVERFLOW event.
static volatile uint8_t m_mutex; ///< Mutex for write access to @ref m_offset_counter.
static volatile bool m_clock_ready; ///< Information that LFCLK is ready.
static uint64_t m_target_time; ///< Timer fire time [us].
static uint32_t overflow_counter_get(void);
/** @brief Non-blocking mutex for mutual write access to @ref m_offset_counter variable.
*
* @retval true Mutex was acquired.
* @retval false Mutex could not be acquired.
*/
static inline bool mutex_get(void)
{
do
{
volatile uint8_t mutex_value = __LDREXB(&m_mutex);
if (mutex_value)
{
__CLREX();
return false;
}
}
while (__STREXB(1, &m_mutex));
// Disable OVERFLOW interrupt to prevent lock-up in interrupt context while mutex is locked from lower priority context
// and OVERFLOW event flag is stil up.
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
__DMB();
return true;
}
/** @brief Release mutex. */
static inline void mutex_release(void)
{
// Re-enable OVERFLOW interrupt.
nrf_rtc_int_enable(NRF_802154_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
__DMB();
m_mutex = 0;
}
/** @brief Check if timer shall strike.
*
* @param[in] now Current time.
*
* @retval true Timer shall strike now.
* @retval false Timer shall not strike now.
*/
static inline bool shall_strike(uint64_t now)
{
return now >= m_target_time;
}
/** @brief Convert time in [us] to RTC ticks.
*
* @param[in] time Time to convert.
*
* @return Time value in RTC ticks.
*/
static inline uint32_t time_to_ticks(uint64_t time)
{
// Divide the divider and the divident by the greatest common divisor to increase capacity of the multiplication.
return (uint32_t)CEIL_DIV((time * (RTC_FREQUENCY >> FREQUENCY_US_PER_S_GDD_BITS)),
(US_PER_S >> FREQUENCY_US_PER_S_GDD_BITS)) & RTC_CC_COMPARE_Msk;
}
/** @brief Convert RTC ticks to time in [us].
*
* @param[in] ticks RTC ticks to convert.
*
* @return Time value in [us].
*/
static inline uint64_t ticks_to_time(uint32_t ticks)
{
return CEIL_DIV((US_PER_S * (uint64_t)ticks), RTC_FREQUENCY);
}
/** @brief Get current time.
*
* @return Current time in [us].
*/
static uint64_t time_get(void)
{
uint32_t offset_1 = overflow_counter_get();
__DMB();
uint32_t rtc_value_1 = nrf_rtc_counter_get(NRF_802154_RTC_INSTANCE);
__DMB();
uint32_t offset_2 = overflow_counter_get();
__DMB();
uint32_t rtc_value_2 = nrf_rtc_counter_get(NRF_802154_RTC_INSTANCE);
if (offset_1 == offset_2)
{
return (uint64_t)offset_1 * US_PER_OVERFLOW + ticks_to_time(rtc_value_1);
}
else
{
return (uint64_t)offset_2 * US_PER_OVERFLOW + ticks_to_time(rtc_value_2);
}
}
/** @brief Get current time plus 2 RTC ticks to prevent RTC compare event miss.
*
* @return Current time with RTC protection in [us].
*/
static inline uint64_t rtc_protected_time_get(void)
{
return time_get() + 2 * US_PER_TICK;
}
/** @brief Get current overflow counter and handle OVERFLOW event if present.
*
* This function returns current value of m_overflow_counter variable. If OVERFLOW event is present
* while calling this function, it is handled within it.
*
* @return Current number of OVERFLOW events since platform start.
*/
static uint32_t overflow_counter_get(void)
{
uint32_t offset;
// Get mutual access for writing to m_offset_counter variable.
if (mutex_get())
{
bool increasing = false;
// Check if interrupt was handled already.
if (nrf_rtc_event_pending(NRF_802154_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW))
{
m_offset_counter++;
increasing = true;
__DMB();
// Mark that interrupt was handled.
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
// Result should be incremented. m_offset_counter will be incremented after mutex is released.
}
else
{
// Either overflow handling is not needed OR we acquired the mutex just after it was released.
// Overflow is handled after mutex is released, but it cannot be assured that m_offset_counter
// was incremented for the second time, so we increment the result here.
}
offset = (m_offset_counter + 1) / 2;
mutex_release();
if (increasing)
{
// It's virtually impossible that overflow event is pending again before next instruction is performed. It is an error condition.
assert(m_offset_counter & 0x01);
// Increment the counter for the second time, to alloww instructions from other context get correct value of the counter.
m_offset_counter++;
}
}
else
{
// Failed to acquire mutex.
if (nrf_rtc_event_pending(NRF_802154_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW) || (m_offset_counter & 0x01))
{
// Lower priority context is currently incrementing m_offset_counter variable.
offset = (m_offset_counter + 2) / 2;
}
else
{
// Lower priority context has already incremented m_offset_counter variable or incrementing is not needed now.
offset = m_offset_counter / 2;
}
}
return offset;
}
/** @brief Handle COMPARE event. */
static void handle_compare_match(bool skip_check)
{
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT);
// In case the target time was larger than single overflow,
// we should only strike the timer on final compare event.
if (skip_check || shall_strike(time_get()))
{
nrf_rtc_event_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT_MASK);
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
nrf_802154_timer_fired();
}
}
void nrf_802154_timer_init(void)
{
m_offset_counter = 0;
m_target_time = 0;
m_clock_ready = false;
// Setup low frequency clock.
nrf_802154_clock_lfclk_start();
while (!m_clock_ready) { }
// Setup RTC timer.
NVIC_SetPriority(NRF_802154_RTC_IRQN, NRF_802154_RTC_IRQ_PRIORITY);
NVIC_ClearPendingIRQ(NRF_802154_RTC_IRQN);
NVIC_EnableIRQ(NRF_802154_RTC_IRQN);
nrf_rtc_prescaler_set(NRF_802154_RTC_INSTANCE, 0);
// Setup RTC events.
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
nrf_rtc_event_enable(NRF_802154_RTC_INSTANCE, RTC_EVTEN_OVRFLW_Msk);
nrf_rtc_int_enable(NRF_802154_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
nrf_rtc_event_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT_MASK);
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT);
// Start RTC timer.
nrf_rtc_task_trigger(NRF_802154_RTC_INSTANCE, NRF_RTC_TASK_START);
}
void nrf_802154_timer_deinit(void)
{
nrf_rtc_task_trigger(NRF_802154_RTC_INSTANCE, NRF_RTC_TASK_STOP);
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
nrf_rtc_event_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT_MASK);
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT);
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
nrf_rtc_event_disable(NRF_802154_RTC_INSTANCE, RTC_EVTEN_OVRFLW_Msk);
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
NVIC_DisableIRQ(NRF_802154_RTC_IRQN);
NVIC_ClearPendingIRQ(NRF_802154_RTC_IRQN);
NVIC_SetPriority(NRF_802154_RTC_IRQN, 0);
nrf_802154_clock_lfclk_stop();
}
void nrf_802154_timer_critical_section_enter(void)
{
NVIC_DisableIRQ(NRF_802154_RTC_IRQN);
__DSB();
__ISB();
}
void nrf_802154_timer_critical_section_exit(void)
{
NVIC_EnableIRQ(NRF_802154_RTC_IRQN);
}
uint32_t nrf_802154_timer_time_get(void)
{
return (uint32_t)time_get();
}
uint32_t nrf_802154_timer_granularity_get(void)
{
return US_PER_TICK;
}
void nrf_802154_timer_start(uint32_t t0, uint32_t dt)
{
uint64_t now;
uint32_t target_counter;
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
nrf_rtc_event_enable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT_MASK);
now = time_get();
// Check if 32 LSB of `now` overflowed between getting t0 and loading `now` value.
if ((uint32_t)now < t0)
{
now -= 0x0000000100000000;
}
m_target_time = (now & 0xffffffff00000000) + t0 + dt;
target_counter = time_to_ticks(m_target_time);
nrf_rtc_cc_set(NRF_802154_RTC_INSTANCE, RTC_COMPARE_CHANNEL, target_counter);
now = rtc_protected_time_get();
if (shall_strike(now))
{
handle_compare_match(true);
}
else
{
nrf_rtc_int_enable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
}
}
bool nrf_802154_timer_is_running(void)
{
return nrf_rtc_int_is_enabled(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
}
void nrf_802154_timer_stop(void)
{
nrf_rtc_event_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT_MASK);
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK);
nrf_rtc_event_clear(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT);
}
void nrf_802154_clock_lfclk_ready(void)
{
m_clock_ready = true;
}
void NRF_802154_RTC_IRQ_HANDLER(void)
{
// Handle overflow.
if (nrf_rtc_event_pending(NRF_802154_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW))
{
// Disable OVERFLOW interrupt to prevent lock-up in interrupt context while mutex is locked from lower priority context
// and OVERFLOW event flag is stil up.
// OVERFLOW interrupt will be re-enabled when mutex is released - either from this handler, or from lower priority context,
// that locked the mutex.
nrf_rtc_int_disable(NRF_802154_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
// Handle OVERFLOW event by reading current value of overflow counter.
(void)overflow_counter_get();
}
// Handle compare match.
if (nrf_rtc_int_is_enabled(NRF_802154_RTC_INSTANCE, RTC_COMPARE_INT_MASK) &&
nrf_rtc_event_pending(NRF_802154_RTC_INSTANCE, RTC_COMPARE_EVENT))
{
handle_compare_match(false);
}
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,24 +36,24 @@
*
*/
#include "nrf_drv_radio802154_timer.h"
#include "nrf_802154_timer.h"
void nrf_drv_radio802154_timer_init(void)
void nrf_802154_timer_init(void)
{
// Intentionally empty
}
void nrf_drv_radio802154_timer_deinit(void)
void nrf_802154_timer_deinit(void)
{
// Intentionally empty
}
void nrf_drv_radio802154_timer_critical_section_enter(void)
void nrf_802154_timer_critical_section_enter(void)
{
// Intentionally empty
}
void nrf_drv_radio802154_timer_critical_section_exit(void)
void nrf_802154_timer_critical_section_exit(void)
{
// Intentionally empty
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@ extern "C" {
/**
* @defgroup nrf_raal Radio Arbiter Abstraction Layer
* @{
* @ingroup nrf_driver_radio802154
* @ingroup nrf_802154
* @brief Radio Arbiter Abstraction Layer interface.
*/
@@ -107,6 +107,14 @@ void nrf_raal_continuous_mode_exit(void);
*/
bool nrf_raal_timeslot_request(uint32_t length_us);
/**
* @brief Check if the 802.15.4 driver is currently in timeslot.
*
* @retval TRUE Timeslot is currently granted.
* @retval FALSE Timeslot is not currently granted.
*/
bool nrf_raal_timeslot_is_granted(void);
/**
* @brief Get left time of currently granted timeslot [us].
*
@@ -117,7 +125,11 @@ uint32_t nrf_raal_timeslot_us_left_get(void);
/**
* @brief Enter critical section of the module.
*
* When this method is called, the execution of the @nrf_raal_timeslot_ended function is blocked.
* When this method is called, the execution of the @sa nrf_raal_timeslot_started and
* @sa nrf_raal_timeslot_ended function is blocked.
*
* @note This function may be called when RAAL is already in critical section. Ongoing call may
* be interrupted by another call from IRQ with higher priority.
*
*/
void nrf_raal_critical_section_enter(void);
@@ -125,9 +137,12 @@ void nrf_raal_critical_section_enter(void);
/**
* @brief Exit critical section of the module.
*
* When this method is called driver has to expect the execution of the @nrf_raal_timeslot_ended
* When this method is called driver has to expect the execution of the
* @sa nrf_raal_timeslot_started or @sa nrf_raal_timeslot_ended
* function.
*
* @note This function may be called when RAAL has already exited critical section. Ongoing call
* may NOT be interrupted by another call from IRQ with higher priority.
*/
void nrf_raal_critical_section_exit(void);
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
#ifndef NRF_RAAL_CONFIG_H__
#define NRF_RAAL_CONFIG_H__
#ifdef NRF_DRV_RADIO802154_PROJECT_CONFIG
#include NRF_DRV_RADIO802154_PROJECT_CONFIG
#ifdef NRF_802154_PROJECT_CONFIG
#include NRF_802154_PROJECT_CONFIG
#endif
#include <nrf.h>
@@ -44,7 +44,7 @@ extern "C" {
/**
* @defgroup nrf_raal_config RAAL configuration
* @{
* @ingroup nrf_driver_radio802154
* @ingroup nrf_802154
* @brief Configuration of Radio Arbiter Abstraction Layer.
*/
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "platform/clock/nrf_drv_radio802154_clock.h"
#include "platform/clock/nrf_802154_clock.h"
static bool m_continuous;
@@ -60,7 +60,7 @@ void nrf_raal_continuous_mode_enter(void)
{
assert(!m_continuous);
nrf_drv_radio802154_clock_hfclk_start();
nrf_802154_clock_hfclk_start();
m_continuous = true;
}
@@ -69,7 +69,7 @@ void nrf_raal_continuous_mode_exit(void)
assert(m_continuous);
m_continuous = false;
nrf_drv_radio802154_clock_hfclk_stop();
nrf_802154_clock_hfclk_stop();
}
bool nrf_raal_timeslot_request(uint32_t length_us)
@@ -81,6 +81,11 @@ bool nrf_raal_timeslot_request(uint32_t length_us)
return true;
}
bool nrf_raal_timeslot_is_granted(void)
{
return true;
}
uint32_t nrf_raal_timeslot_us_left_get(void)
{
return UINT32_MAX;
@@ -96,7 +101,7 @@ void nrf_raal_critical_section_exit(void)
// Intentionally empty.
}
void nrf_drv_radio802154_clock_hfclk_ready(void)
void nrf_802154_clock_hfclk_ready(void)
{
nrf_raal_timeslot_started();
}
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,9 +44,9 @@
#include <hal/nrf_timer.h>
#include <nrf_raal_api.h>
#include <nrf_drv_radio802154.h>
#include <nrf_drv_radio802154_debug.h>
#include <platform/clock/nrf_drv_radio802154_clock.h>
#include <nrf_802154.h>
#include <nrf_802154_debug.h>
#include <platform/clock/nrf_802154_clock.h>
#if defined(__GNUC__)
_Pragma("GCC diagnostic push")
@@ -311,7 +311,7 @@ static void timeslot_extend(void)
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND;
m_ret_param.params.extend.length_us = m_timeslot_length;
nrf_drv_radio802154_pin_set(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_802154_pin_set(PIN_DBG_TIMESLOT_EXTEND_REQ);
}
else
{
@@ -324,8 +324,8 @@ static void timer_irq_handle(void)
// Safe margin exceeded.
if (RAAL_TIMER->EVENTS_COMPARE[TIMER_CC_MARGIN])
{
nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_MARGIN);
nrf_802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_MARGIN);
m_in_timeslot = false;
@@ -360,13 +360,13 @@ static void timer_irq_handle(void)
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
#endif
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_MARGIN);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_MARGIN);
}
// Extension margin exceeded.
else if (RAAL_TIMER->EVENTS_COMPARE[TIMER_CC_EXTEND])
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXTEND);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXTEND);
nrf_timer_int_disable(RAAL_TIMER, TIMER_CC_EXTEND_INT);
nrf_timer_event_clear(RAAL_TIMER, TIMER_CC_EXTEND_EVENT);
@@ -375,7 +375,7 @@ static void timer_irq_handle(void)
(nrf_timer_cc_read(RAAL_TIMER, TIMER_CC_EXTEND) +
m_config.timeslot_length < m_config.timeslot_max_length))
{
nrf_drv_radio802154_pin_set(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_802154_pin_set(PIN_DBG_TIMESLOT_EXTEND_REQ);
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND;
m_ret_param.params.extend.length_us = m_config.timeslot_length;
@@ -387,7 +387,7 @@ static void timer_irq_handle(void)
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
}
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXTEND);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXTEND);
}
else
{
@@ -399,15 +399,15 @@ static void timer_irq_handle(void)
/**@brief Signal handler. */
static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_type)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_HANDLER);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_HANDLER);
// Default response.
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
if (!m_continuous)
{
nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_ENDED);
nrf_802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_ENDED);
m_pending_event = PENDING_EVENT_NONE;
m_in_timeslot = false;
@@ -416,8 +416,8 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
timer_reset();
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_ENDED);
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_HANDLER);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_ENDED);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_HANDLER);
return &m_ret_param;
}
@@ -425,8 +425,8 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t
{
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START: /**< This signal indicates the start of the radio timeslot. */
{
nrf_drv_radio802154_pin_set(PIN_DBG_TIMESLOT_ACTIVE);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_START);
nrf_802154_pin_set(PIN_DBG_TIMESLOT_ACTIVE);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_START);
// Ensure HFCLK is running before start is issued.
assert(NRF_CLOCK->HFCLKSTAT == (CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk));
@@ -460,8 +460,8 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t
m_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND;
m_ret_param.params.extend.length_us = m_timeslot_length;
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_START);
nrf_drv_radio802154_pin_set(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_START);
nrf_802154_pin_set(PIN_DBG_TIMESLOT_EXTEND_REQ);
break;
}
@@ -470,14 +470,14 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO: /**< This signal indicates the NRF_RADIO interrupt. */
nrf_drv_radio802154_pin_set(PIN_DBG_TIMESLOT_RADIO_IRQ);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_RADIO);
nrf_802154_pin_set(PIN_DBG_TIMESLOT_RADIO_IRQ);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_RADIO);
if (m_in_timeslot)
{
if (!timer_is_margin_reached())
{
nrf_drv_radio802154_irq_handler();
nrf_802154_radio_irq_handler();
}
else
{
@@ -486,23 +486,23 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t
}
}
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_RADIO);
nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_RADIO_IRQ);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_RADIO);
nrf_802154_pin_clr(PIN_DBG_TIMESLOT_RADIO_IRQ);
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED: /**< This signal indicates extend action failed. */
nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_drv_radio802154_pin_tgl(PIN_DBG_TIMESLOT_FAILED);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL);
nrf_802154_pin_clr(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_802154_pin_tgl(PIN_DBG_TIMESLOT_FAILED);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL);
timeslot_extend();
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXCEED_FAIL);
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED: /**< This signal indicates extend action succeeded. */
nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS);
nrf_802154_pin_clr(PIN_DBG_TIMESLOT_EXTEND_REQ);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS);
timer_extend();
@@ -511,14 +511,14 @@ static nrf_radio_signal_callback_return_param_t *signal_handler(uint8_t signal_t
timeslot_extend();
}
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_EVENT_EXCEED_SUCCESS);
break;
default:
break;
}
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_HANDLER);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_SIG_HANDLER);
return &m_ret_param;
}
@@ -530,7 +530,7 @@ void nrf_raal_softdevice_soc_evt_handler(uint32_t evt_id)
case NRF_EVT_RADIO_BLOCKED:
case NRF_EVT_RADIO_CANCELED:
{
nrf_drv_radio802154_pin_tgl(PIN_DBG_TIMESLOT_BLOCKED);
nrf_802154_pin_tgl(PIN_DBG_TIMESLOT_BLOCKED);
assert(!m_in_timeslot);
@@ -554,7 +554,7 @@ void nrf_raal_softdevice_soc_evt_handler(uint32_t evt_id)
case NRF_EVT_RADIO_SESSION_IDLE:
if (m_continuous)
{
nrf_drv_radio802154_pin_tgl(PIN_DBG_TIMESLOT_SESSION_IDLE);
nrf_802154_pin_tgl(PIN_DBG_TIMESLOT_SESSION_IDLE);
timeslot_data_init();
timeslot_request();
@@ -609,12 +609,12 @@ void nrf_raal_uninit(void)
m_continuous = false;
m_in_timeslot = false;
nrf_drv_radio802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE);
nrf_802154_pin_clr(PIN_DBG_TIMESLOT_ACTIVE);
}
void nrf_raal_continuous_mode_enter(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CONTINUOUS_ENTER);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CONTINUOUS_ENTER);
assert(m_initialize);
assert(!m_continuous);
@@ -623,14 +623,14 @@ void nrf_raal_continuous_mode_enter(void)
m_timeslot_length = m_config.timeslot_length;
m_continuous = true;
nrf_drv_radio802154_clock_hfclk_start();
nrf_802154_clock_hfclk_start();
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CONTINUOUS_ENTER);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CONTINUOUS_ENTER);
}
void nrf_raal_continuous_mode_exit(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CONTINUOUS_EXIT);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CONTINUOUS_EXIT);
assert(m_initialize);
assert(m_continuous);
@@ -643,9 +643,9 @@ void nrf_raal_continuous_mode_exit(void)
NVIC_SetPendingIRQ(RAAL_TIMER_IRQn);
}
nrf_drv_radio802154_clock_hfclk_stop();
nrf_802154_clock_hfclk_stop();
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CONTINUOUS_EXIT);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CONTINUOUS_EXIT);
}
bool nrf_raal_timeslot_request(uint32_t length_us)
@@ -658,6 +658,11 @@ bool nrf_raal_timeslot_request(uint32_t length_us)
return timer_time_get() + length_us < nrf_timer_cc_read(RAAL_TIMER, TIMER_CC_MARGIN);
}
bool nrf_raal_timeslot_is_granted(void)
{
return (m_continuous && m_in_timeslot);
}
uint32_t nrf_raal_timeslot_us_left_get(void)
{
if (!m_continuous || !m_in_timeslot)
@@ -670,21 +675,19 @@ uint32_t nrf_raal_timeslot_us_left_get(void)
void nrf_raal_critical_section_enter(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CRIT_SECT_ENTER);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CRIT_SECT_ENTER);
assert(!m_in_critical_section);
m_in_critical_section = true;
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CRIT_SECT_ENTER);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CRIT_SECT_ENTER);
}
void nrf_raal_critical_section_exit(void)
{
nrf_drv_radio802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CRIT_SECT_EXIT);
nrf_802154_log(EVENT_TRACE_ENTER, FUNCTION_RAAL_CRIT_SECT_EXIT);
timeslot_critical_section_enter();
assert(m_in_critical_section);
m_in_critical_section = false;
switch (m_pending_event)
@@ -705,10 +708,10 @@ void nrf_raal_critical_section_exit(void)
timeslot_critical_section_exit();
nrf_drv_radio802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CRIT_SECT_EXIT);
nrf_802154_log(EVENT_TRACE_EXIT, FUNCTION_RAAL_CRIT_SECT_EXIT);
}
void nrf_drv_radio802154_clock_hfclk_ready(void)
void nrf_802154_clock_hfclk_ready(void)
{
if (m_continuous && !m_in_timeslot)
{
@@ -1,4 +1,4 @@
/* Copyright (c) 2017, Nordic Semiconductor ASA
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -0,0 +1,405 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* This file implements timer scheduler for the nRF 802.15.4 driver.
*
* This implementation supports scheduling of multiple timer instances and can be used from different contexts.
*
* @note Timer scheduler is secured against preemption and adding/removing different timers from different contexts,
* it shall not be used for adding/removing the same timer instance from two contexts at the same time.
*
*/
#include "nrf_802154_timer_sched.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <nrf.h>
#include "platform/timer/nrf_802154_timer.h"
static volatile uint8_t m_mutex; ///< Mutex for starting the timer.
static volatile uint8_t m_queue_changed_cntr; ///< Information that scheduler queue was modified.
static volatile nrf_802154_timer_t * mp_head; ///< Head of the running timers list.
/** @brief Non-blocking mutex for starting the timer.
*
* @retval true Mutex was acquired.
* @retval false Mutex could not be acquired.
*/
static inline bool mutex_trylock(void)
{
do
{
volatile uint8_t mutex_value = __LDREXB(&m_mutex);
if (mutex_value)
{
__CLREX();
return false;
}
} while (__STREXB(1, &m_mutex));
__DMB();
return true;
}
/** @brief Release mutex. */
static inline void mutex_unlock(void)
{
__DMB();
m_mutex = 0;
}
/** @brief Increment queue counter value to detect changes in the queue. */
static inline void queue_cntr_bump(void)
{
volatile uint8_t cntr;
do
{
cntr = __LDREXB(&m_queue_changed_cntr);
} while (__STREXB(cntr + 1, &m_queue_changed_cntr));
__DMB();
}
/**
* @brief Check if @p time_1 is before @p time_2.
*
* @param[in] time_1 First time to compare.
* @param[in] time_2 Second time to compare.
*
* @return True if @p time_1 is before @p time_2, false otherwise.
*/
static inline bool is_time_before(uint32_t time_1, uint32_t time_2)
{
int32_t diff = time_1 - time_2;
return diff < 0;
}
/**
* @brief Check if @p p_timer_1 shall strike earlier than @p p_timer_2.
*
* @param[in] p_timer_1 A pointer to first timer to compare.
* @param[in] p_timer_2 A pointer to second timer to compare.
*
* @return True if @p p_timer_1 shall strike earlier than @p p_timer_2, false otherwise.
*/
static inline bool is_timer_prior(const nrf_802154_timer_t * p_timer_1,
const nrf_802154_timer_t * p_timer_2)
{
return is_time_before(p_timer_1->t0 + p_timer_1->dt, p_timer_2->t0 + p_timer_2->dt);
}
/**
* @brief Handle operation on timer with mutex protection.
*/
static inline void handle_timer(void)
{
volatile nrf_802154_timer_t * p_head;
uint8_t queue_cntr;
do
{
queue_cntr = m_queue_changed_cntr;
p_head = mp_head;
if (mutex_trylock())
{
if (p_head == NULL)
{
nrf_802154_timer_stop();
}
else
{
uint32_t t0 = p_head->t0;
uint32_t dt = p_head->dt;
// Set the timer only if current HEAD wasn't removed - otherwise t0 and dt might've been modified
// between reading t0 and dt and not be a valid combination.
if (p_head == mp_head)
{
nrf_802154_timer_start(t0, dt);
}
}
mutex_unlock();
}
} while (queue_cntr != m_queue_changed_cntr);
}
/**
* @brief Remove timer from the queue
*
* @param [inout] p_timer Pointer to timer to remove from the queue.
*
* @retval true @sa handle_timer() shall be called by caller of this function.
* @retval false @sa handle_timer() shall not be called by the caller.
*/
static bool timer_remove(nrf_802154_timer_t * p_timer)
{
assert(p_timer != NULL);
nrf_802154_timer_t ** pp_item;
nrf_802154_timer_t * volatile p_next; // Volatile pointer to prevent compiler from removing any code related to this variable during optimization (IAR).
nrf_802154_timer_t * p_cur;
uint8_t queue_cntr;
bool timer_start;
bool timer_stop;
while (true)
{
queue_cntr = m_queue_changed_cntr;
pp_item = (nrf_802154_timer_t **)&mp_head;
p_next = NULL;
p_cur = NULL;
timer_start = false;
timer_stop = false;
// Find entry to remove
while (true)
{
p_cur = (nrf_802154_timer_t *)__LDREXW((uint32_t *)pp_item);
if ((p_cur == NULL) || (p_cur == p_timer))
{
break;
}
pp_item = &(p_cur->p_next);
}
if (queue_cntr != m_queue_changed_cntr)
{
// Higher priority modified the queue while iterating, try again.
continue;
}
if (p_cur == p_timer)
{
// Entry found.
p_next = p_cur->p_next;
// Restart timer when removing HEAD and other timer instance is pending.
if (p_cur == mp_head)
{
if (p_next != NULL)
{
timer_start = true;
}
else
{
timer_stop = true;
}
}
}
else
{
// Entry not found
__CLREX();
break;
}
if (!__STREXW((uint32_t)p_next, (uint32_t *)pp_item))
{
// Exit, if exclusive access succeeds.
queue_cntr_bump();
break;
}
}
// Write to the pointer next on removal to ensure that node removal is detected by
// lower pritority context in case it was going to be used.
if (p_cur != NULL)
{
do
{
// This assignment is used to prevent compiler from removing exclusive load during optimization (IAR).
p_next = (nrf_802154_timer_t *)__LDREXW((uint32_t *)&p_cur->p_next);
} while (__STREXW((uint32_t)NULL, (uint32_t *)&p_cur->p_next));
}
return (timer_start || timer_stop);
}
void nrf_802154_timer_sched_init(void)
{
mp_head = NULL;
m_mutex = 0;
m_queue_changed_cntr = 0;
}
void nrf_802154_timer_sched_deinit(void)
{
nrf_802154_timer_stop();
mp_head = NULL;
}
uint32_t nrf_802154_timer_sched_time_get(void)
{
return nrf_802154_timer_time_get();
}
bool nrf_802154_timer_sched_time_is_in_future(uint32_t now, uint32_t t0, uint32_t dt)
{
uint32_t target_time = t0 + dt;
int32_t difference = target_time - now;
return difference > 0;
}
void nrf_802154_timer_sched_add(nrf_802154_timer_t * p_timer, bool round_up)
{
assert(p_timer != NULL);
assert(p_timer->callback != NULL);
if (round_up)
{
p_timer->dt += nrf_802154_timer_granularity_get() - 1;
}
if (timer_remove(p_timer))
{
handle_timer();
}
nrf_802154_timer_t ** pp_item;
nrf_802154_timer_t * p_next;
uint8_t queue_cntr;
while (true)
{
queue_cntr = m_queue_changed_cntr;
pp_item = (nrf_802154_timer_t **)&mp_head;
p_next = NULL;
// Search the current queue to find appropriate position to insert timer.
while (true)
{
nrf_802154_timer_t * p_cur = (nrf_802154_timer_t *)__LDREXW((uint32_t *)pp_item);
if (p_cur == NULL)
{
// No HEAD or insert at the end.
p_next = NULL;
break;
}
if (is_timer_prior(p_timer, p_cur))
{
// Insert at the beginning with existing HEAD or somewhere in the middle.
p_next = p_cur;
break;
}
pp_item = &(p_cur->p_next);
}
if (queue_cntr != m_queue_changed_cntr)
{
// Higher priority modified the queue while iterating, try again.
continue;
}
p_timer->p_next = p_next;
if (!__STREXW((uint32_t)p_timer, (uint32_t *)pp_item))
{
// Exit, if exclusive access succeeds.
queue_cntr_bump();
break;
}
}
if (mp_head == p_timer)
{
handle_timer();
}
}
void nrf_802154_timer_sched_remove(nrf_802154_timer_t * p_timer)
{
if (timer_remove(p_timer))
{
handle_timer();
}
}
bool nrf_802154_timer_sched_is_running(nrf_802154_timer_t * p_timer)
{
uint8_t queue_cntr;
bool result;
do
{
result = false;
queue_cntr = m_queue_changed_cntr;
for (volatile nrf_802154_timer_t * p_cur = mp_head;
p_cur != NULL;
p_cur = p_cur->p_next)
{
if (p_cur == p_timer)
{
result = true;
break;
}
}
} while (queue_cntr != m_queue_changed_cntr);
return result;
}
void nrf_802154_timer_fired(void)
{
nrf_802154_timer_t * p_timer = (nrf_802154_timer_t *) mp_head;
nrf_802154_timer_callback_t callback = p_timer->callback;
void * p_context = p_timer->p_context;
if ((p_timer != NULL) && (callback != NULL))
{
bool timer_shall_be_handled = timer_remove(p_timer);
callback(p_context);
if (timer_shall_be_handled)
{
handle_timer();
}
}
}
@@ -0,0 +1,158 @@
/* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @brief This module provides timer scheduling functionality for the 802.15.4 driver.
*
* Timer module should be used to implement strict timing features specified in IEEE 802.15.4 like:
* * CSL,
* * Timing out waiting for ACK frames,
* * CSMA/CA,
* * Inter-frame spacing: SIFS, LIFS (note that AIFS is implemented without using timer module).
*
* @note Current implementation supports only single one-shot timer. It may be extended to support
* timer scheduling and repetitive timers if needed.
*/
#ifndef NRF_802154_TIMER_SCHED_H_
#define NRF_802154_TIMER_SCHED_H_
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_802154_timer_sched Timer Scheduler module for the 802.15.4 driver
* @{
* @ingroup nrf_802154_timer_sched
* @brief Timer Scheduler module for the 802.15.4 driver.
*
*/
/**
* @brief Type of function called when timer fires.
*
* @param[inout] p_context Pointer to user-defined memory location. May be NULL.
*/
typedef void (* nrf_802154_timer_callback_t)(void * p_context);
/**
* @brief Type for driver instance.
*/
typedef struct nrf_802154_timer_s nrf_802154_timer_t;
/**
* @brief Structure containing timer data used by timer module.
*/
struct nrf_802154_timer_s
{
uint32_t t0; ///< Base time of the timer [us]
uint32_t dt; ///< Timer expiration delta from @p t0 [us]
nrf_802154_timer_callback_t callback; ///< Callback function called when timer expires
void * p_context; ///< User-defined context passed to callback function
nrf_802154_timer_t * p_next; ///< A pointer to the next running timer
};
/**
* @brief Initialize the timer scheduler.
*/
void nrf_802154_timer_sched_init(void);
/**
* @brief Deinitialize the timer scheduler.
*/
void nrf_802154_timer_sched_deinit(void);
/**
* @brief Get current time.
*
* This function is useful to set base time in @sa nrf_802154_timer_t structure.
*
* @return Current time in microseconds [us].
*/
uint32_t nrf_802154_timer_sched_time_get(void);
/**
* @brief Check if given time is in future.
*
* @param[in] now Current time. @sa nrf_802154_timer_sched_time_get()
* @param[in] t0 Base of time compared with @p now.
* @param[in] dt Time delta from @p t0 compared with @p now.
*
* @retval true Given time @p t0 @p dt is in future (compared to given @p now).
* @retval false Given time @p t0 @p dt is not in future (compared to given @p now).
*/
bool nrf_802154_timer_sched_time_is_in_future(uint32_t now, uint32_t t0, uint32_t dt);
/**
* @brief Start given timer and add it to the scheduler.
*
* @note Fields t0, dt, callback and p_context should be filled in @p p_timer prior to calling this
* function; callback field cannot be NULL.
*
* @note Due to timer granularity the callback function cannot be called exactly at specified time.
* Use @p round_up to specify if given timer should be expired before or after time given in
* the @p p_timer structure. The dt field of the @p p_timer is updated with the rounded up value.
*
* @param[inout] p_timer Pointer to the timer to start and add to the scheduler.
* @param[in] round_up True if timer should expire after specified time, false if it should
* expire before.
*/
void nrf_802154_timer_sched_add(nrf_802154_timer_t * p_timer, bool round_up);
/**
* @brief Stop given timer and remove it from the scheduler.
*
* @param[inout] p_timer Pointer to the timer to stop and remove from the scheduler.
*/
void nrf_802154_timer_sched_remove(nrf_802154_timer_t * p_timer);
/**
* @brief Check if given timer is already scheduled.
*
* @param[in] p_timer Pointer to the timer to check.
*
* @retval true Given timer is already scheduled.
* @retval false Given timer is not scheduled.
*/
bool nrf_802154_timer_sched_is_running(nrf_802154_timer_t * p_timer);
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif /* NRF_802154_TIMER_SCHED_H_ */