Merge 8fc5a80819
into fc2bab706f
This commit is contained in:
commit
6ca45c3a08
|
@ -41,11 +41,14 @@
|
|||
#include "nrf_802154_assert.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "hal/nrf_ecb.h"
|
||||
#include "nrf_802154_const.h"
|
||||
#include "nrf_802154_config.h"
|
||||
#include "nrf_802154_tx_work_buffer.h"
|
||||
#include "platform/nrf_802154_irq.h"
|
||||
#if defined(CONFIG_MPSL)
|
||||
#include "mpsl_ecb.h"
|
||||
#else
|
||||
#include "hal/nrf_ecb.h"
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b)) ///< Leaves the minimum of the two arguments
|
||||
|
@ -90,56 +93,117 @@ static uint8_t m_m[NRF_802154_AES_CCM_BLOCK_SIZE];
|
|||
static uint8_t m_a[NRF_802154_AES_CCM_BLOCK_SIZE]; ///< A[i] octet for Encryption Transformation - Annex B4.1.3 b)
|
||||
static ccm_state_t m_state; ///< State of AES-CCM* transformation
|
||||
static uint8_t m_auth_tag[MIC_128_SIZE]; ///< Authorization Tag
|
||||
static bool m_initialized; ///< Flag that indicates whether the module has been initialized.
|
||||
static uint8_t * mp_ciphertext; ///< Pointer to ciphertext destination buffer.
|
||||
static uint8_t * mp_work_buffer; ///< Pointer to work buffer that stores the frame being transformed.
|
||||
|
||||
static const uint8_t m_mic_size[] = { 0, MIC_32_SIZE, MIC_64_SIZE, MIC_128_SIZE }; ///< Security level - 802.15.4-2015 Standard Table 9.6
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
static uint8_t m_ecb_data[48]; ///< ECB data structure for RNG peripheral to access.
|
||||
static uint8_t * mp_ecb_key; ///< Key: Starts at ecb_data
|
||||
static uint8_t * mp_ecb_cleartext; ///< Cleartext: Starts at ecb_data + 16 bytes.
|
||||
static uint8_t * mp_ecb_ciphertext; ///< Ciphertext: Starts at ecb_data + 32 bytes.
|
||||
|
||||
static void nrf_ecb_init(void)
|
||||
typedef struct
|
||||
{
|
||||
mp_ecb_key = m_ecb_data;
|
||||
mp_ecb_cleartext = m_ecb_data + 16;
|
||||
mp_ecb_ciphertext = m_ecb_data + 32;
|
||||
uint32_t key[NRF_802154_AES_CCM_BLOCK_SIZE / sizeof(uint32_t)];
|
||||
uint8_t cleartext[NRF_802154_AES_CCM_BLOCK_SIZE];
|
||||
uint8_t ciphertext[NRF_802154_AES_CCM_BLOCK_SIZE];
|
||||
} nrf_802154_hal_ecb_data_t;
|
||||
|
||||
nrf_ecb_data_pointer_set(NRF_ECB, m_ecb_data);
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
static nrf_802154_hal_ecb_data_t m_ecb_hal_data;
|
||||
static bool m_ecb_hal_req_run;
|
||||
|
||||
#if defined(CONFIG_MPSL)
|
||||
static inline void ecb_block_encrypt(nrf_802154_hal_ecb_data_t * p_ecb_data)
|
||||
{
|
||||
/* Note: nrf_802154_hal_ecb_data_t and mpsl_ecb_hal_data_t are equivalent
|
||||
* and pointers to them can be safely cast.
|
||||
*/
|
||||
mpsl_ecb_block_encrypt((mpsl_ecb_hal_data_t *)p_ecb_data);
|
||||
}
|
||||
|
||||
static void nrf_ecb_set_key(const uint8_t * p_key)
|
||||
#else
|
||||
|
||||
#define ECB_INST NRF_ECB
|
||||
|
||||
static inline void sleep_wfe(void)
|
||||
{
|
||||
memcpy(mp_ecb_key, p_key, 16);
|
||||
#if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
|
||||
void z_impl_k_busy_wait();
|
||||
z_impl_k_busy_wait(10);
|
||||
#elif defined(CONFIG_SOC_COMPATIBLE_NRF52X)
|
||||
__WFE();
|
||||
#else
|
||||
/* Do-nothing. This includes nRF5340 series due multiple sleep-related anomalies (160, 165, 168) */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ecb_irq_handler(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes the ECB peripheral.
|
||||
*/
|
||||
static void ecb_init(void)
|
||||
static void wait_for_ecb_end(void)
|
||||
{
|
||||
if (!m_initialized)
|
||||
while (!nrf_ecb_event_check(ECB_INST, NRF_ECB_EVENT_ENDECB) &&
|
||||
!nrf_ecb_event_check(ECB_INST, NRF_ECB_EVENT_ERRORECB))
|
||||
{
|
||||
nrf_802154_irq_init(nrfx_get_irq_number(NRF_ECB), NRF_802154_ECB_PRIORITY, ecb_irq_handler);
|
||||
m_initialized = true;
|
||||
#if !defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
|
||||
if ((SCB->SCR & SCB_SCR_SEVONPEND_Msk) == SCB_SCR_SEVONPEND_Msk)
|
||||
#endif
|
||||
{
|
||||
NVIC_ClearPendingIRQ(ECB_IRQn);
|
||||
|
||||
uint32_t irq_was_masked = __get_PRIMASK();
|
||||
|
||||
__disable_irq();
|
||||
|
||||
nrf_ecb_int_enable(ECB_INST, NRF_ECB_INT_ENDECB_MASK | NRF_ECB_INT_ERRORECB_MASK);
|
||||
if (!nrf_ecb_event_check(ECB_INST, NRF_ECB_EVENT_ENDECB) &&
|
||||
!nrf_ecb_event_check(ECB_INST, NRF_ECB_EVENT_ERRORECB))
|
||||
{
|
||||
sleep_wfe();
|
||||
}
|
||||
|
||||
if (!irq_was_masked)
|
||||
{
|
||||
__enable_irq();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ensure ECB initialization is handled by zephyr
|
||||
// TODO: what about ECB initialization in baremetal scenario?
|
||||
nrf_ecb_init();
|
||||
static void ecb_block_encrypt(nrf_802154_hal_ecb_data_t * p_ecb_data)
|
||||
{
|
||||
nrf_ecb_int_disable(ECB_INST, NRF_ECB_INT_ENDECB_MASK | NRF_ECB_INT_ERRORECB_MASK);
|
||||
|
||||
nrf_802154_irq_clear_pending(nrfx_get_irq_number(NRF_ECB));
|
||||
nrf_802154_irq_enable(nrfx_get_irq_number(NRF_ECB));
|
||||
nrf_ecb_int_enable(NRF_ECB, NRF_ECB_INT_ENDECB_MASK);
|
||||
nrf_ecb_int_enable(NRF_ECB, NRF_ECB_INT_ERRORECB_MASK);
|
||||
do
|
||||
{
|
||||
nrf_ecb_task_trigger(ECB_INST, NRF_ECB_TASK_STOPECB);
|
||||
nrf_ecb_event_clear(ECB_INST, NRF_ECB_EVENT_ENDECB);
|
||||
nrf_ecb_event_clear(ECB_INST, NRF_ECB_EVENT_ERRORECB);
|
||||
nrf_ecb_data_pointer_set(ECB_INST, p_ecb_data);
|
||||
|
||||
nrf_ecb_task_trigger(ECB_INST, NRF_ECB_TASK_STARTECB);
|
||||
wait_for_ecb_end();
|
||||
}
|
||||
while (nrf_ecb_event_check(ECB_INST, NRF_ECB_EVENT_ERRORECB));
|
||||
|
||||
nrf_ecb_int_disable(ECB_INST, NRF_ECB_INT_ENDECB_MASK | NRF_ECB_INT_ERRORECB_MASK);
|
||||
nrf_ecb_event_clear(ECB_INST, NRF_ECB_EVENT_ERRORECB);
|
||||
nrf_ecb_event_clear(ECB_INST, NRF_ECB_EVENT_ENDECB);
|
||||
NVIC_ClearPendingIRQ(ECB_IRQn);
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_MPSL) */
|
||||
|
||||
static inline uint8_t * ecb_hal_cleartext_ptr_get(void)
|
||||
{
|
||||
return (uint8_t *)m_ecb_hal_data.cleartext;
|
||||
}
|
||||
|
||||
static inline uint8_t * ecb_hal_ciphertext_ptr_get(void)
|
||||
{
|
||||
return (uint8_t *)m_ecb_hal_data.ciphertext;
|
||||
}
|
||||
|
||||
static void ecb_hal_key_set(const uint8_t * p_key)
|
||||
{
|
||||
memcpy(m_ecb_hal_data.key, p_key, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -316,9 +380,11 @@ static bool plain_text_data_get(const nrf_802154_aes_ccm_data_t * p_frame,
|
|||
static inline void process_ecb_auth_iteration(void)
|
||||
{
|
||||
m_state.iteration++;
|
||||
two_blocks_xor(mp_ecb_ciphertext, m_b, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
memcpy(mp_ecb_cleartext, mp_ecb_ciphertext, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
|
||||
two_blocks_xor(ecb_hal_ciphertext_ptr_get(), m_b, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
memcpy(ecb_hal_cleartext_ptr_get(),
|
||||
ecb_hal_ciphertext_ptr_get(),
|
||||
NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
m_ecb_hal_req_run = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,8 +393,8 @@ static inline void process_ecb_auth_iteration(void)
|
|||
static inline void process_ecb_encrypt_iteration(void)
|
||||
{
|
||||
ai_format(&m_aes_ccm_data, m_state.iteration, m_a);
|
||||
memcpy(mp_ecb_cleartext, m_a, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
|
||||
memcpy(ecb_hal_cleartext_ptr_get(), m_a, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
m_ecb_hal_req_run = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,7 +402,7 @@ static inline void process_ecb_encrypt_iteration(void)
|
|||
*/
|
||||
static void perform_plain_text_encryption(void)
|
||||
{
|
||||
memcpy(m_auth_tag, mp_ecb_ciphertext, m_mic_size[m_aes_ccm_data.mic_level]);
|
||||
memcpy(m_auth_tag, ecb_hal_ciphertext_ptr_get(), m_mic_size[m_aes_ccm_data.mic_level]);
|
||||
|
||||
m_state.iteration = 0;
|
||||
m_state.transformation = PLAIN_TEXT_ENCRYPT;
|
||||
|
@ -377,99 +443,72 @@ static void transformation_finished(void)
|
|||
m_aes_ccm_data.raw_frame = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handler to ECB Interrupt Routine
|
||||
* Performs AES-CCM* calculation in pipeline
|
||||
*/
|
||||
static void ecb_irq_handler(void)
|
||||
static void ecb_hal_block_encrypted_handler(void)
|
||||
{
|
||||
uint8_t len = 0;
|
||||
uint8_t offset;
|
||||
|
||||
if (nrf_ecb_int_enable_check(NRF_ECB, NRF_ECB_INT_ENDECB_MASK) &&
|
||||
nrf_ecb_event_check(NRF_ECB, NRF_ECB_EVENT_ENDECB))
|
||||
switch (m_state.transformation)
|
||||
{
|
||||
nrf_ecb_event_clear(NRF_ECB, NRF_ECB_EVENT_ENDECB);
|
||||
case ADD_AUTH_DATA_AUTH:
|
||||
if (add_auth_data_get(&m_aes_ccm_data, m_state.iteration, m_b))
|
||||
{
|
||||
process_ecb_auth_iteration();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state.iteration = 0;
|
||||
m_state.transformation = PLAIN_TEXT_AUTH;
|
||||
perform_plain_text_authorization();
|
||||
}
|
||||
break;
|
||||
|
||||
switch (m_state.transformation)
|
||||
{
|
||||
case ADD_AUTH_DATA_AUTH:
|
||||
if (add_auth_data_get(&m_aes_ccm_data, m_state.iteration, m_b))
|
||||
{
|
||||
process_ecb_auth_iteration();
|
||||
}
|
||||
else
|
||||
case PLAIN_TEXT_AUTH:
|
||||
perform_plain_text_authorization();
|
||||
break;
|
||||
|
||||
case PLAIN_TEXT_ENCRYPT:
|
||||
two_blocks_xor(m_m, ecb_hal_ciphertext_ptr_get(), NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
|
||||
offset = (m_state.iteration - 1) * NRF_802154_AES_CCM_BLOCK_SIZE;
|
||||
len = MIN(m_aes_ccm_data.plain_text_data_len - offset,
|
||||
NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
memcpy(mp_ciphertext + offset, m_m, len);
|
||||
if (plain_text_data_get(&m_aes_ccm_data, m_state.iteration, m_m))
|
||||
{
|
||||
m_state.iteration++;
|
||||
process_ecb_encrypt_iteration();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_mic_size[m_aes_ccm_data.mic_level] != 0)
|
||||
{
|
||||
m_state.iteration = 0;
|
||||
m_state.transformation = PLAIN_TEXT_AUTH;
|
||||
perform_plain_text_authorization();
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAIN_TEXT_AUTH:
|
||||
perform_plain_text_authorization();
|
||||
break;
|
||||
|
||||
case PLAIN_TEXT_ENCRYPT:
|
||||
two_blocks_xor(m_m, mp_ecb_ciphertext, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
|
||||
offset = (m_state.iteration - 1) * NRF_802154_AES_CCM_BLOCK_SIZE;
|
||||
len = MIN(m_aes_ccm_data.plain_text_data_len - offset,
|
||||
NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
memcpy(mp_ciphertext + offset, m_m, len);
|
||||
if (plain_text_data_get(&m_aes_ccm_data, m_state.iteration, m_m))
|
||||
{
|
||||
m_state.iteration++;
|
||||
m_state.transformation = CALCULATE_ENCRYPTED_TAG;
|
||||
process_ecb_encrypt_iteration();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_mic_size[m_aes_ccm_data.mic_level] != 0)
|
||||
{
|
||||
m_state.iteration = 0;
|
||||
m_state.transformation = CALCULATE_ENCRYPTED_TAG;
|
||||
process_ecb_encrypt_iteration();
|
||||
}
|
||||
else
|
||||
{
|
||||
transformation_finished();
|
||||
}
|
||||
transformation_finished();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CALCULATE_ENCRYPTED_TAG:
|
||||
two_blocks_xor(m_auth_tag,
|
||||
mp_ecb_ciphertext,
|
||||
m_mic_size[m_aes_ccm_data.mic_level]);
|
||||
memcpy(mp_work_buffer +
|
||||
(mp_work_buffer[PHR_OFFSET] - FCS_SIZE -
|
||||
m_mic_size[m_aes_ccm_data.mic_level] +
|
||||
PHR_SIZE),
|
||||
m_auth_tag,
|
||||
m_mic_size[m_aes_ccm_data.mic_level]);
|
||||
transformation_finished();
|
||||
break;
|
||||
case CALCULATE_ENCRYPTED_TAG:
|
||||
two_blocks_xor(m_auth_tag,
|
||||
ecb_hal_ciphertext_ptr_get(),
|
||||
m_mic_size[m_aes_ccm_data.mic_level]);
|
||||
memcpy(mp_work_buffer +
|
||||
(mp_work_buffer[PHR_OFFSET] - FCS_SIZE -
|
||||
m_mic_size[m_aes_ccm_data.mic_level] +
|
||||
PHR_SIZE),
|
||||
m_auth_tag,
|
||||
m_mic_size[m_aes_ccm_data.mic_level]);
|
||||
transformation_finished();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nrf_ecb_int_enable_check(NRF_ECB, NRF_ECB_INT_ERRORECB_MASK) &&
|
||||
nrf_ecb_event_check(NRF_ECB, NRF_ECB_EVENT_ERRORECB))
|
||||
{
|
||||
/*
|
||||
* It is possible that the ERRORECB event is caused by the
|
||||
* AAR and CCM peripherals, which share the same hardware resources.
|
||||
* At this point it is assumed, that ECB, AAR and CCM peripherals
|
||||
* are not used by anything, except the 802.15.4 driver and
|
||||
* other MPSL clients and thus it is impossible that ECB was aborted
|
||||
* for any other reason, than the TX failed event caused by a terminated
|
||||
* 802.15.4 transmit operation or end of timeslot.
|
||||
*
|
||||
* Therefore no action is taken in this handler.
|
||||
*/
|
||||
nrf_ecb_event_clear(NRF_ECB, NRF_ECB_EVENT_ERRORECB);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,11 +517,18 @@ static void ecb_irq_handler(void)
|
|||
*/
|
||||
static void start_ecb_auth_transformation(void)
|
||||
{
|
||||
memcpy((uint8_t *)nrf_ecb_data_pointer_get(NRF_ECB) + 16, m_x, 16);
|
||||
ecb_hal_key_set(m_aes_ccm_data.key);
|
||||
memcpy(ecb_hal_cleartext_ptr_get(), m_x, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
m_state.iteration = 0;
|
||||
m_state.transformation = ADD_AUTH_DATA_AUTH;
|
||||
nrf_ecb_event_clear(NRF_ECB, NRF_ECB_EVENT_ENDECB);
|
||||
nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
|
||||
m_ecb_hal_req_run = true;
|
||||
|
||||
while (m_ecb_hal_req_run)
|
||||
{
|
||||
m_ecb_hal_req_run = false;
|
||||
ecb_block_encrypt(&m_ecb_hal_data);
|
||||
ecb_hal_block_encrypted_handler();
|
||||
}
|
||||
}
|
||||
|
||||
void nrf_802154_aes_ccm_transform_reset(void)
|
||||
|
@ -554,9 +600,6 @@ void nrf_802154_aes_ccm_transform_start(uint8_t * p_frame)
|
|||
b0_format(&m_aes_ccm_data, auth_flags, p_b);
|
||||
|
||||
two_blocks_xor(p_x, p_b, NRF_802154_AES_CCM_BLOCK_SIZE);
|
||||
ecb_init();
|
||||
memset(mp_ecb_key, 0, 48);
|
||||
nrf_ecb_set_key(m_aes_ccm_data.key);
|
||||
start_ecb_auth_transformation();
|
||||
}
|
||||
|
||||
|
@ -568,16 +611,6 @@ void nrf_802154_aes_ccm_transform_abort(uint8_t * p_frame)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporarily disable ENDECB interrupt, trigger STOPECB task
|
||||
* to stop encryption in case it is still running and clear
|
||||
* the ENDECB event in case the encryption has completed.
|
||||
*/
|
||||
nrf_ecb_int_disable(NRF_ECB, NRF_ECB_INT_ENDECB_MASK);
|
||||
nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB);
|
||||
nrf_ecb_event_clear(NRF_ECB, NRF_ECB_EVENT_ENDECB);
|
||||
nrf_ecb_int_enable(NRF_ECB, NRF_ECB_INT_ENDECB_MASK);
|
||||
|
||||
m_aes_ccm_data.raw_frame = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -758,7 +758,7 @@ static void operation_terminated_notify(radio_state_t state, bool receiving_psdu
|
|||
nrf_802154_transmit_done_metadata_t metadata = {};
|
||||
|
||||
nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
|
||||
transmit_failed_notify(mp_tx_data, NRF_802154_TX_ERROR_ABORTED, &metadata);
|
||||
transmit_failed_notify(mp_tx_data, NRF_802154_TX_ERROR_NO_ACK, &metadata);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -843,16 +843,6 @@ static bool current_operation_terminate(nrf_802154_term_t term_lvl,
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Enter Sleep state. */
|
||||
static void sleep_init(void)
|
||||
{
|
||||
// This function is always executed from a critical section, so this check is safe.
|
||||
if (timeslot_is_granted())
|
||||
{
|
||||
nrf_802154_timer_coord_stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize Falling Asleep operation. */
|
||||
static void falling_asleep_init(void)
|
||||
{
|
||||
|
@ -862,7 +852,6 @@ static void falling_asleep_init(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
sleep_init();
|
||||
state_set(RADIO_STATE_SLEEP);
|
||||
}
|
||||
}
|
||||
|
@ -1212,7 +1201,6 @@ static void switch_to_idle(void)
|
|||
{
|
||||
if (!nrf_802154_pib_rx_on_when_idle_get())
|
||||
{
|
||||
sleep_init();
|
||||
state_set(RADIO_STATE_SLEEP);
|
||||
}
|
||||
else
|
||||
|
@ -1884,7 +1872,6 @@ void nrf_802154_trx_go_idle_finished(void)
|
|||
{
|
||||
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
|
||||
sleep_init();
|
||||
state_set(RADIO_STATE_SLEEP);
|
||||
|
||||
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
|
@ -2093,12 +2080,43 @@ void nrf_802154_trx_receive_frame_received(void)
|
|||
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
}
|
||||
|
||||
static bool fcf_is_security_enabled(const uint8_t * p_frame)
|
||||
{
|
||||
return p_frame[SECURITY_ENABLED_OFFSET] & SECURITY_ENABLED_BIT;
|
||||
}
|
||||
|
||||
static inline bool tx_started_core_hooks_will_fit_within_timeslot(const uint8_t * p_frame)
|
||||
{
|
||||
if (!fcf_is_security_enabled(p_frame))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t estimated_max_hook_time = nrf_802154_frame_duration_get(p_frame[0], false, true) / 2U;
|
||||
|
||||
return nrf_802154_rsch_timeslot_us_left_get() >= estimated_max_hook_time;
|
||||
}
|
||||
|
||||
void nrf_802154_trx_transmit_frame_started(void)
|
||||
{
|
||||
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
|
||||
NRF_802154_ASSERT((m_state == RADIO_STATE_TX) || (m_state == RADIO_STATE_CCA_TX));
|
||||
transmit_started_notify();
|
||||
if (tx_started_core_hooks_will_fit_within_timeslot(mp_tx_data))
|
||||
{
|
||||
transmit_started_notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_802154_trx_abort();
|
||||
switch_to_idle();
|
||||
|
||||
nrf_802154_transmit_done_metadata_t metadata = {};
|
||||
|
||||
nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
|
||||
|
||||
transmit_failed_notify(mp_tx_data, NRF_802154_TX_ERROR_TIMESLOT_ENDED, &metadata);
|
||||
}
|
||||
|
||||
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
}
|
||||
|
@ -2108,7 +2126,21 @@ void nrf_802154_trx_transmit_ack_started(void)
|
|||
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
|
||||
NRF_802154_ASSERT(m_state == RADIO_STATE_TX_ACK);
|
||||
transmit_ack_started_notify();
|
||||
if (tx_started_core_hooks_will_fit_within_timeslot(mp_ack))
|
||||
{
|
||||
transmit_ack_started_notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t * p_received_data = mp_current_rx_buffer->data;
|
||||
|
||||
nrf_802154_trx_abort();
|
||||
mp_current_rx_buffer->free = false;
|
||||
|
||||
nrf_802154_core_hooks_tx_ack_failed(mp_ack, NRF_802154_RX_ERROR_TIMESLOT_ENDED);
|
||||
switch_to_idle();
|
||||
received_frame_notify_and_nesting_allow(p_received_data);
|
||||
}
|
||||
|
||||
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
||||
}
|
||||
|
@ -2523,7 +2555,6 @@ static bool core_sleep(nrf_802154_term_t term_lvl, req_originator_t req_orig, bo
|
|||
}
|
||||
else
|
||||
{
|
||||
sleep_init();
|
||||
state_set(RADIO_STATE_SLEEP);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "nrf_802154_config.h"
|
||||
#include "nrf_802154_core.h"
|
||||
#include "nrf_802154_critical_section.h"
|
||||
#include "nrf_802154_debug.h"
|
||||
#include "nrf_802154_queue.h"
|
||||
#include "nrf_802154_rx_buffer.h"
|
||||
#include "nrf_802154_swi.h"
|
||||
|
|
|
@ -612,9 +612,9 @@ static void fem_for_lna_reset(void)
|
|||
*
|
||||
* @note This function must be called before ramp up PPIs are configured.
|
||||
*/
|
||||
static void fem_for_pa_set(const mpsl_fem_gain_t * p_fem_gain_data)
|
||||
static void fem_for_pa_set(mpsl_fem_pa_power_control_t pa_power_control)
|
||||
{
|
||||
(void)mpsl_fem_pa_gain_set(p_fem_gain_data);
|
||||
(void)mpsl_fem_pa_power_control_set(pa_power_control);
|
||||
if (mpsl_fem_pa_configuration_set(&m_activate_tx_cc0, NULL) == 0)
|
||||
{
|
||||
nrf_timer_shorts_enable(m_activate_tx_cc0.event.timer.p_timer_instance,
|
||||
|
@ -641,11 +641,11 @@ static void fem_for_pa_reset(void)
|
|||
*
|
||||
* @note This function must be called before ramp up PPIs are configured.
|
||||
*/
|
||||
static void fem_for_tx_set(bool cca, const mpsl_fem_gain_t * p_fem_gain_data)
|
||||
static void fem_for_tx_set(bool cca, mpsl_fem_pa_power_control_t pa_power_control)
|
||||
{
|
||||
bool success;
|
||||
|
||||
(void)mpsl_fem_pa_gain_set(p_fem_gain_data);
|
||||
(void)mpsl_fem_pa_power_control_set(pa_power_control);
|
||||
|
||||
if (cca)
|
||||
{
|
||||
|
@ -764,11 +764,11 @@ static void pa_modulation_fix_apply(bool enable)
|
|||
|
||||
if (enable)
|
||||
{
|
||||
int8_t pa_gain = 0;
|
||||
mpsl_fem_caps_t fem_caps = {};
|
||||
|
||||
mpsl_fem_pa_is_configured(&pa_gain);
|
||||
mpsl_fem_caps_get(&fem_caps);
|
||||
|
||||
if (pa_gain > 0)
|
||||
if ((fem_caps.flags & MPSL_FEM_CAPS_FLAG_PA_SETUP_REQUIRED) != 0)
|
||||
{
|
||||
m_pa_mod_filter_latched = *(p_radio_reg);
|
||||
m_pa_mod_filter_is_latched = true;
|
||||
|
@ -1401,7 +1401,7 @@ void nrf_802154_trx_receive_frame(uint8_t bcc,
|
|||
}
|
||||
|
||||
// Set FEM PA gain for ACK transmission
|
||||
mpsl_fem_pa_gain_set(&p_ack_tx_power->fem);
|
||||
mpsl_fem_pa_power_control_set(p_ack_tx_power->fem_pa_power_control);
|
||||
|
||||
m_timer_value_on_radio_end_event = delta_time;
|
||||
|
||||
|
@ -1607,7 +1607,7 @@ void nrf_802154_trx_transmit_frame(const void * p_tra
|
|||
|
||||
nrf_radio_int_enable(NRF_RADIO, ints_to_enable);
|
||||
|
||||
fem_for_tx_set(cca, &p_tx_power->fem);
|
||||
fem_for_tx_set(cca, p_tx_power->fem_pa_power_control);
|
||||
nrf_802154_trx_antenna_update();
|
||||
nrf_802154_trx_ppi_for_ramp_up_set(cca ? NRF_RADIO_TASK_RXEN : NRF_RADIO_TASK_TXEN,
|
||||
rampup_trigg_mode,
|
||||
|
@ -2180,7 +2180,7 @@ void nrf_802154_trx_continuous_carrier(const nrf_802154_fal_tx_power_split_t * p
|
|||
txpower_set(p_tx_power->radio_tx_power);
|
||||
|
||||
// Set FEM
|
||||
fem_for_pa_set(&p_tx_power->fem);
|
||||
fem_for_pa_set(p_tx_power->fem_pa_power_control);
|
||||
|
||||
// Select antenna
|
||||
nrf_802154_trx_antenna_update();
|
||||
|
@ -2242,7 +2242,7 @@ void nrf_802154_trx_modulated_carrier(const void * p_
|
|||
nrf_radio_shorts_set(NRF_RADIO, SHORTS_MOD_CARRIER);
|
||||
|
||||
// Set FEM
|
||||
fem_for_pa_set(&p_tx_power->fem);
|
||||
fem_for_pa_set(p_tx_power->fem_pa_power_control);
|
||||
|
||||
// Select antenna
|
||||
nrf_802154_trx_antenna_update();
|
||||
|
|
|
@ -161,7 +161,7 @@ void nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait(void);
|
|||
* @brief Detect if PPIs configured to start radio operation were triggered.
|
||||
*
|
||||
* In TRX_RAMP_UP_SW_TRIGGER mode, radio ramp up starts by design from RADIO DISABLED event.
|
||||
* This functions verifies occurrence of this event and PPIs status.
|
||||
* This function verifies occurrence of this event and PPIs status.
|
||||
*
|
||||
* The function is intended to be used only when all of the following conditions apply:
|
||||
* - the connections are already made with @ref nrf_802154_trx_ppi_for_ramp_up_set
|
||||
|
|
|
@ -2339,7 +2339,7 @@ enum
|
|||
*
|
||||
* Specifies the preferred Router Id. Upon becoming a router/leader the node
|
||||
* attempts to use this Router Id. If the preferred Router Id is not set or
|
||||
* if it can not be used, a randomly generated router id is picked. This
|
||||
* if it cannot be used, a randomly generated router id is picked. This
|
||||
* property can be set only when the device role is either detached or
|
||||
* disabled.
|
||||
*
|
||||
|
|
|
@ -47,24 +47,26 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Represents components of tx_power to be applied for stages on transmit path.
|
||||
*/
|
||||
/** @brief Represents components of tx_power to be applied for stages on transmit path. */
|
||||
typedef struct
|
||||
{
|
||||
int8_t radio_tx_power; // !< TX power in dBm to be applied to the RADIO peripheral.
|
||||
mpsl_fem_gain_t fem; // !< Data needed to set the FEM gain
|
||||
/** TX power to be applied to the RADIO peripheral. */
|
||||
int8_t radio_tx_power;
|
||||
|
||||
/** PA power control to be applied to Front-End Module. */
|
||||
mpsl_fem_pa_power_control_t fem_pa_power_control;
|
||||
} nrf_802154_fal_tx_power_split_t;
|
||||
|
||||
/** @brief Splits transmit power value into components to be applied on each stage on the transmit path.
|
||||
/** @brief Splits transmit power value into components to be applied on each stage on transmit path.
|
||||
*
|
||||
* @note This is a stub implementation used when MPSL is not linked.
|
||||
* @note If the exact value of @p power cannot be achieved this function attempts to use less
|
||||
* power to not exceed constraint.
|
||||
*
|
||||
* @param[in] channel Ignored.
|
||||
* @param[in] channel 802.15.4 channel.
|
||||
* @param[in] power TX power in dBm requested for transmission on air.
|
||||
* @param[out] p_tx_power_split Components of tx_power to be applied for stages on transmit path.
|
||||
*
|
||||
* @returns The real achieved total transmission power in dBm.
|
||||
* @return Actually achieved power in dBm.
|
||||
*/
|
||||
int8_t nrf_802154_fal_tx_power_split(const uint8_t channel,
|
||||
const int8_t power,
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
#define NRF_802154_EGU_INSTANCE_NO 0
|
||||
#elif defined(NRF54L_SERIES)
|
||||
#define NRF_802154_EGU_INSTANCE_NO 10
|
||||
#elif defined(NRF54H_SERIES)
|
||||
#define NRF_802154_EGU_INSTANCE_NO 020
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -222,4 +224,26 @@
|
|||
|
||||
#endif // defined(NRF54L_SERIES)
|
||||
|
||||
#if defined(NRF54H_SERIES)
|
||||
|
||||
/**
|
||||
* @def NRF_802154_SL_DPPIC_INSTANCE_NO
|
||||
*
|
||||
* Id of the DPPIC instance used by the driver to connect peripherals to radio.
|
||||
*
|
||||
*/
|
||||
#ifndef NRF_802154_SL_DPPIC_INSTANCE_NO
|
||||
#define NRF_802154_SL_DPPIC_INSTANCE_NO 020
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def NRF_802154_SL_DPPIC_INSTANCE
|
||||
*
|
||||
* The DPPIC instance used by the driver to connect peripherals to radio.
|
||||
*
|
||||
*/
|
||||
#define NRF_802154_SL_DPPIC_INSTANCE NRFX_CONCAT_2(NRF_DPPIC, NRF_802154_SL_DPPIC_INSTANCE_NO)
|
||||
|
||||
#endif // defined(NRF54H_SERIES)
|
||||
|
||||
#endif // NRF_802154_SL_PERIPHS_H__
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Nordic Semiconductor ASA
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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 Abstraction layer for peripheral-to-peripheral hardware connections needed for timestamping.
|
||||
*/
|
||||
|
||||
#ifndef NRF_802154_PLATFORM_TIMESTAMPER_H_
|
||||
#define NRF_802154_PLATFORM_TIMESTAMPER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initializes the timestamper platform.
|
||||
*/
|
||||
void nrf_802154_platform_timestamper_init(void);
|
||||
|
||||
/**
|
||||
* @brief Sets up cross-domain hardware connections necessary to capture a timestamp.
|
||||
*
|
||||
* This function configures cross-domain hardware connections necessary to capture a timestamp of
|
||||
* an event from the local domain. These connections are identical for all local domain events.
|
||||
*
|
||||
* @note Every call to this function must be paired with a call to @ref
|
||||
* nrf_802154_platform_timestamper_cross_domain_connections_clear.
|
||||
*/
|
||||
void nrf_802154_platform_timestamper_cross_domain_connections_setup(void);
|
||||
|
||||
/**
|
||||
* @brief Clears cross-domain hardware connections necessary to capture a timestamp.
|
||||
*/
|
||||
void nrf_802154_platform_timestamper_cross_domain_connections_clear(void);
|
||||
|
||||
/**
|
||||
* @brief Sets up local domain hardware connections necessary to capture a timestamp.
|
||||
*
|
||||
* This function configures local domain hardware connections necessary to capture a timestamp of
|
||||
* an event from the local domain. These connections must be setup separately for every local domain
|
||||
* event.
|
||||
*
|
||||
* @param[in] dppi_ch Local domain DPPI channel that the event to be timestamped publishes to.
|
||||
*/
|
||||
void nrf_802154_platform_timestamper_local_domain_connections_setup(uint32_t dppi_ch);
|
||||
|
||||
/**
|
||||
* @brief Clears local domain hardware connections necessary to capture a timestamp.
|
||||
*
|
||||
* @param[in] dppi_ch Local domain DPPI channel that the event to be timestamped publishes to.
|
||||
*/
|
||||
void nrf_802154_platform_timestamper_local_domain_connections_clear(uint32_t dppi_ch);
|
||||
|
||||
/**
|
||||
* @brief Reads timestamp captured using the configured hardware connections.
|
||||
*
|
||||
* @param[out] p_timestamp Captured timestamp. Only valid if @c true is returned, undefined otherwise.
|
||||
*
|
||||
* @retval true The timestamp was captured and read successfully.
|
||||
* @retval false The timestamp could not be retrieved.
|
||||
*/
|
||||
bool nrf_802154_platform_timestamper_captured_timestamp_read(uint64_t * p_captured);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_802154_PLATFORM_TIMESTAMPER_H_
|
|
@ -32,7 +32,7 @@ typedef int8_t mpsl_tx_power_t;
|
|||
* @param[in] req_radio_power Requested TX power desired for RADIO peripheral.
|
||||
* The power value in dBm must be supported by the RADIO peripheral.
|
||||
*
|
||||
* @return RADIO.TXPOWER register code corrensponding to a radio power in dBm.
|
||||
* @return RADIO.TXPOWER register code corresponding to radio power in dBm.
|
||||
*/
|
||||
uint32_t mpsl_tx_power_dbm_to_radio_register_convert(mpsl_tx_power_t req_radio_power);
|
||||
|
||||
|
|
|
@ -49,13 +49,17 @@ typedef enum
|
|||
* published to multiple PPI channels by hardware design, which makes it possible
|
||||
* for multiple tasks to subscribe to it.
|
||||
*
|
||||
* For nRF53 series this is a number of a DPPI channel which is configured
|
||||
* For nRF53 series, this is a number of a DPPI channel which is configured
|
||||
* in such a way that certain event publishes to the DPPI channel and the
|
||||
* DPPI channel is enabled. Ensuring above is responsibility of an user
|
||||
* DPPI channel is enabled. Ensuring above is responsibility of a user
|
||||
* of the provided API. Multiple tasks can then subscribe to the DPPI channel
|
||||
* (by hardware design) thus indirectly to the event.
|
||||
* (by hardware design), thus indirectly to the event.
|
||||
*/
|
||||
#ifdef PPI_PRESENT
|
||||
typedef uint32_t mpsl_subscribable_hw_event_t;
|
||||
#else
|
||||
typedef uint8_t mpsl_subscribable_hw_event_t;
|
||||
#endif
|
||||
|
||||
/** @brief MPSL Front End Module event. */
|
||||
typedef struct
|
||||
|
@ -83,15 +87,15 @@ typedef struct
|
|||
|
||||
/** Mask of the compare channels that can be used by the Front End Module to schedule its own tasks. */
|
||||
uint8_t compare_channel_mask;
|
||||
/** Event generated by the timer, used in case of type equal to @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_TIMER. */
|
||||
/** Event generated by the timer, used in case of type equal to @ref MPSL_FEM_EVENT_TYPE_TIMER. */
|
||||
} timer;
|
||||
|
||||
/** Parameters when type is @ref MPSL_FEM_EVENT_TYPE_GENERIC. */
|
||||
struct
|
||||
{
|
||||
/** Event triggerring required FEM operation. */
|
||||
/** Event triggering required FEM operation. */
|
||||
mpsl_subscribable_hw_event_t event;
|
||||
/** Generic event, used in case of type equal to @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_GENERIC. */
|
||||
/** Generic event, used in case of type equal to @ref MPSL_FEM_EVENT_TYPE_GENERIC. */
|
||||
} generic;
|
||||
} event;
|
||||
|
||||
|
@ -106,15 +110,12 @@ typedef struct
|
|||
/** TX power, dBm. */
|
||||
typedef int8_t mpsl_tx_power_t;
|
||||
|
||||
/**
|
||||
* @brief Represents data needed to set the FEM gain.
|
||||
/** Type for PA power control to be applied to Front-End Module, depending on its type.
|
||||
*
|
||||
* The meaning of this type is FEM type-specific.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int8_t gain_db; // !< Gain in dB.
|
||||
uint8_t private_setting; // !< Setting of the Front-End Module. The interpretation of this field is specific
|
||||
// for a given Front-End Module implementation.
|
||||
} mpsl_fem_gain_t;
|
||||
typedef uint8_t mpsl_fem_pa_power_control_t;
|
||||
|
||||
|
||||
/** @brief Represents components of tx_power to be applied for stages on transmit path. */
|
||||
typedef struct
|
||||
|
@ -122,10 +123,43 @@ typedef struct
|
|||
/** TX power to be applied to the RADIO peripheral. */
|
||||
mpsl_tx_power_t radio_tx_power;
|
||||
|
||||
/** Data needed to set the FEM gain. */
|
||||
mpsl_fem_gain_t fem;
|
||||
/** FEM PA power control.*/
|
||||
mpsl_fem_pa_power_control_t fem_pa_power_control;
|
||||
} mpsl_tx_power_split_t;
|
||||
|
||||
/** @brief PA setup is required before starting a transmission.
|
||||
*
|
||||
* This flag applies to @ref mpsl_fem_caps_t::flags.
|
||||
*
|
||||
* If it is set, then @ref mpsl_fem_pa_configuration_set must be called before transmission starts.
|
||||
*/
|
||||
#define MPSL_FEM_CAPS_FLAG_PA_SETUP_REQUIRED (1U << 0)
|
||||
|
||||
/** @brief LNA setup is required before starting a reception.
|
||||
*
|
||||
* This flag applies to @ref mpsl_fem_caps_t::flags.
|
||||
*
|
||||
* If it is set, then @ref mpsl_fem_lna_configuration_set must be called before reception starts.
|
||||
*/
|
||||
#define MPSL_FEM_CAPS_FLAG_LNA_SETUP_REQUIRED (1U << 1)
|
||||
|
||||
/** @brief Structure representing capabilities and characteristics of the FEM in use. */
|
||||
typedef struct
|
||||
{
|
||||
/** Flags informing about the FEM in use.
|
||||
*
|
||||
* The following flags apply:
|
||||
* @ref MPSL_FEM_CAPS_FLAG_PA_SETUP_REQUIRED, @ref MPSL_FEM_CAPS_FLAG_LNA_SETUP_REQUIRED
|
||||
*/
|
||||
uint32_t flags;
|
||||
} mpsl_fem_caps_t;
|
||||
|
||||
/** @brief Gets the capabilities of the FEM in use.
|
||||
*
|
||||
* @param[out] p_caps Pointer to the capabilities structure to be filled in.
|
||||
*/
|
||||
void mpsl_fem_caps_get(mpsl_fem_caps_t * p_caps);
|
||||
|
||||
/** @brief Disable Front End Module.
|
||||
*
|
||||
* Some Front End Module devices can be explicitly disabled after PA and LNA activities are
|
||||
|
@ -153,13 +187,13 @@ int32_t mpsl_fem_disable(void);
|
|||
* I.e. if you want to listen first and then send the frame, you need first to
|
||||
* issue @ref mpsl_fem_lna_configuration_set and only after @ref mpsl_fem_pa_configuration_set.
|
||||
*
|
||||
* If a @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_TIMER timer event is
|
||||
* If a @ref MPSL_FEM_EVENT_TYPE_TIMER timer event is
|
||||
* provided, the PA will be configured to activate or deactivate at the
|
||||
* application-configured time gap before the timer instance reaches the given
|
||||
* register_value. The time gap is set via the corresponding configuration setter
|
||||
* of the selected Front End Module.
|
||||
*
|
||||
* If a @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_GENERIC event is provided,
|
||||
* If a @ref MPSL_FEM_EVENT_TYPE_GENERIC event is provided,
|
||||
* the PA will be configured to activate or deactivate when an event occurs.
|
||||
*
|
||||
* The function sets up the PPIs and the GPIOTE channel to activate PA for the
|
||||
|
@ -179,7 +213,7 @@ int32_t mpsl_fem_disable(void);
|
|||
* the compare channel of the lowest ID among the provided ones does expire.
|
||||
*
|
||||
* @note The activation event can be only of type
|
||||
* @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_TIMER.
|
||||
* @ref MPSL_FEM_EVENT_TYPE_TIMER.
|
||||
* Using other activation event type leads to undefined module behavior.
|
||||
*
|
||||
* @retval 0 PA activation setup is successful.
|
||||
|
@ -209,13 +243,13 @@ int32_t mpsl_fem_pa_configuration_clear(void);
|
|||
* frame, you need first to issue @ref mpsl_fem_lna_configuration_set and only
|
||||
* after @ref mpsl_fem_pa_configuration_set.
|
||||
*
|
||||
* If a @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_TIMER timer event is
|
||||
* If a @ref MPSL_FEM_EVENT_TYPE_TIMER timer event is
|
||||
* provided, the LNA will be configured to activate or deactivate at the
|
||||
* application-configured time gap before the timer instance reaches the given
|
||||
* register_value. The time gap is set via the corresponding configuration setter
|
||||
* of the selected Front End Module.
|
||||
*
|
||||
* If a @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_GENERIC event is provided,
|
||||
* If a @ref MPSL_FEM_EVENT_TYPE_GENERIC event is provided,
|
||||
* the LNA will be configured to activate or deactivate when an event occurs.
|
||||
*
|
||||
* The function sets up the PPIs and the GPIOTE channel to activate LNA for the
|
||||
|
@ -235,7 +269,7 @@ int32_t mpsl_fem_pa_configuration_clear(void);
|
|||
* the compare channel of the lowest ID among the provided ones does expire.
|
||||
*
|
||||
* @note The activation event can be only of type
|
||||
* @ref mpsl_fem_event_type_t::MPSL_FEM_EVENT_TYPE_TIMER. Using other activation
|
||||
* @ref MPSL_FEM_EVENT_TYPE_TIMER. Using other activation
|
||||
* event type leads to undefined module behavior.
|
||||
*
|
||||
* @retval 0 LNA activation setup is successful.
|
||||
|
@ -317,40 +351,51 @@ void mpsl_fem_cleanup(void);
|
|||
|
||||
/** @brief Splits transmit power value into components to be applied on each stage on transmit path.
|
||||
*
|
||||
* @note If the exact value of @p power cannot be achieved, this function attempts to use less
|
||||
* power to not exceed constraint.
|
||||
* @note If the exact value of @p power cannot be achieved, this function attempts to either use
|
||||
* available level lower than the requested level to not exceed constraint, or use the lowest
|
||||
* available level greater than the requested level, depending on @p tx_power_ceiling.
|
||||
*
|
||||
* @param[in] power TX power requested for transmission on air.
|
||||
* @param[out] p_tx_power_split Components of tx_power to be applied for stages on transmit path.
|
||||
* If requested @p power is too high, the split will be set to
|
||||
* a value representing maximum achievable power. If the requested
|
||||
* @p power is too low, the split will be set to a value representing
|
||||
* minimum achievable power.
|
||||
* @param[in] power TX power requested for transmission on air.
|
||||
* @param[out] p_tx_power_split Components of tx_power to be applied for stages on transmit path.
|
||||
* If requested @p power is too high, the split will be set to
|
||||
* a value representing maximum achievable power. If the requested
|
||||
* @p power is too low, the split will be set to a value representing
|
||||
* minimum achievable power.
|
||||
* @param[in] freq_mhz Frequency in MHz to calculate the split for.
|
||||
* @param[in] tx_power_ceiling Flag to get ceiling or floor of requested transmit power level.
|
||||
*
|
||||
* @return The power in dBm that will be achieved if values returned through @p p_tx_power_split
|
||||
* are applied.
|
||||
*/
|
||||
void mpsl_fem_tx_power_split(const mpsl_tx_power_t power,
|
||||
mpsl_tx_power_split_t *const p_tx_power_split);
|
||||
int8_t mpsl_fem_tx_power_split(const mpsl_tx_power_t power,
|
||||
mpsl_tx_power_split_t * const p_tx_power_split,
|
||||
uint16_t freq_mhz,
|
||||
bool tx_power_ceiling);
|
||||
|
||||
/** @brief Sets PA gain.
|
||||
/** @brief Sets the PA power control.
|
||||
*
|
||||
* Setting the PA power control informs the FEM implementation how the PA is to be controlled
|
||||
* before the next transmission.
|
||||
*
|
||||
* The PA power control set by this function is to be applied to control signals or
|
||||
* parameters. What signals and parameters are controlled and how does it happen depends on
|
||||
* implementation of given FEM. The meaning of @p pa_power_control parameter is
|
||||
* fully FEM type-dependent. For FEM type-independent protocol implementation please
|
||||
* use the function @ref mpsl_fem_tx_power_split and provide outcome of this function
|
||||
* returned by the parameter @c p_tx_power_split to the call to @ref mpsl_fem_pa_power_control_set.
|
||||
* For applications intended for testing the FEM itself when @ref mpsl_fem_tx_power_split is not used
|
||||
* you must make the @p pa_power_control parameter on your own.
|
||||
*
|
||||
* @note The gain set by this function will be applied to radio transmissions
|
||||
* @note The PA power control set by this function will be applied to radio transmissions
|
||||
* following the call. If the function is called during radio transmission
|
||||
* or during ramp-up for transmission it is unspecified if the gain is applied.
|
||||
* or during ramp-up for transmission it is unspecified if the control is applied.
|
||||
*
|
||||
* @param[in] gain Gain in dB to be set.
|
||||
* @param[in] pa_power_control PA power control to be applied to the FEM.
|
||||
*
|
||||
* @retval 0 Gain has been set successfully.
|
||||
* @retval -NRF_EINVAL Gain could not be set. Provided @p gain is invalid.
|
||||
* @retval 0 PA power control has been applied successfully.
|
||||
* @retval -NRF_EINVAL PA power control could not be applied. Provided @p pa_power_control is invalid.
|
||||
*/
|
||||
int32_t mpsl_fem_pa_gain_set(const mpsl_fem_gain_t * p_gain);
|
||||
|
||||
/** @brief Checks if the PA signaling is configured and enabled, and gets
|
||||
* the configured gain in dB.
|
||||
*
|
||||
* @param[out] p_gain The configured gain in dB if PA is configured and enabled.
|
||||
* If there is no PA present or the PA does not affect
|
||||
* the signal gain, returns 0 dB.
|
||||
*/
|
||||
void mpsl_fem_pa_is_configured(int8_t * const p_gain);
|
||||
int32_t mpsl_fem_pa_power_control_set(mpsl_fem_pa_power_control_t pa_power_control);
|
||||
|
||||
/** @brief Prepares the Front End Module to switch to the Power Down state.
|
||||
*
|
||||
|
|
|
@ -118,6 +118,11 @@ static radio_tx_power_t to_radio_tx_power_convert(int8_t integer_tx_power)
|
|||
return allowed_values[0];
|
||||
}
|
||||
|
||||
void mpsl_fem_caps_get(mpsl_fem_caps_t * p_caps)
|
||||
{
|
||||
*p_caps = (mpsl_fem_caps_t){};
|
||||
}
|
||||
|
||||
int32_t mpsl_fem_disable(void)
|
||||
{
|
||||
return 0;
|
||||
|
@ -156,7 +161,7 @@ void mpsl_fem_deactivate_now(mpsl_fem_functionality_t type)
|
|||
(void)type;
|
||||
}
|
||||
|
||||
int32_t mpsl_fem_abort_set(uint32_t event, uint32_t group)
|
||||
int32_t mpsl_fem_abort_set(mpsl_subscribable_hw_event_t event, uint32_t group)
|
||||
{
|
||||
return -NRF_EPERM;
|
||||
}
|
||||
|
@ -185,26 +190,27 @@ void mpsl_fem_cleanup(void)
|
|||
// Intentionally empty
|
||||
}
|
||||
|
||||
void mpsl_fem_tx_power_split(const mpsl_tx_power_t power,
|
||||
mpsl_tx_power_split_t * const p_tx_power_split)
|
||||
int8_t mpsl_fem_tx_power_split(const mpsl_tx_power_t power,
|
||||
mpsl_tx_power_split_t * const p_tx_power_split,
|
||||
uint16_t freq_mhz,
|
||||
bool tx_power_ceiling)
|
||||
{
|
||||
p_tx_power_split->radio_tx_power = to_radio_tx_power_convert(power).dbm;
|
||||
p_tx_power_split->fem.gain_db = 0;
|
||||
p_tx_power_split->fem.private_setting = 0;
|
||||
(void)freq_mhz;
|
||||
(void)tx_power_ceiling;
|
||||
|
||||
p_tx_power_split->radio_tx_power = to_radio_tx_power_convert(power).dbm;
|
||||
p_tx_power_split->fem_pa_power_control = 0;
|
||||
|
||||
return p_tx_power_split->radio_tx_power;
|
||||
}
|
||||
|
||||
int32_t mpsl_fem_pa_gain_set(const mpsl_fem_gain_t * p_gain)
|
||||
int32_t mpsl_fem_pa_power_control_set(mpsl_fem_pa_power_control_t pa_power_control)
|
||||
{
|
||||
(void)p_gain;
|
||||
(void)pa_power_control;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mpsl_fem_pa_is_configured(int8_t * const p_gain)
|
||||
{
|
||||
(void)p_gain;
|
||||
}
|
||||
|
||||
bool mpsl_fem_prepare_powerdown(NRF_TIMER_Type * p_instance,
|
||||
uint32_t compare_channel,
|
||||
uint32_t ppi_id,
|
||||
|
@ -228,9 +234,8 @@ int8_t nrf_802154_fal_tx_power_split(const uint8_t cha
|
|||
{
|
||||
(void)channel;
|
||||
|
||||
p_tx_power_split->radio_tx_power = to_radio_tx_power_convert(power).dbm;
|
||||
p_tx_power_split->fem.gain_db = 0;
|
||||
p_tx_power_split->fem.private_setting = 0;
|
||||
p_tx_power_split->radio_tx_power = to_radio_tx_power_convert(power).dbm;
|
||||
p_tx_power_split->fem_pa_power_control = 0;
|
||||
|
||||
return p_tx_power_split->radio_tx_power;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue