diff --git a/drivers/nrf_802154/driver/CMakeLists.txt b/drivers/nrf_802154/driver/CMakeLists.txt index 461c22a..7f43632 100644 --- a/drivers/nrf_802154/driver/CMakeLists.txt +++ b/drivers/nrf_802154/driver/CMakeLists.txt @@ -101,6 +101,8 @@ if (SL_OPENSOURCE) NRF_802154_DELAYED_TRX_ENABLED=0 # Disable IFS NRF_802154_IFS_ENABLED=0 + # Disable CSMA-CA + NRF_802154_CSMA_CA_ENABLED=0 ) endif() diff --git a/drivers/nrf_802154/driver/include/nrf_802154.h b/drivers/nrf_802154/driver/include/nrf_802154.h index 8c972b3..6fd4b3e 100644 --- a/drivers/nrf_802154/driver/include/nrf_802154.h +++ b/drivers/nrf_802154/driver/include/nrf_802154.h @@ -404,6 +404,17 @@ uint8_t nrf_802154_ccaedthres_from_dbm_calculate(int8_t dbm); */ uint64_t nrf_802154_first_symbol_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length); +/** + * @brief Calculates the timestamp of the MAC Header in a received frame. + * + * @param[in] end_timestamp Timestamp of the end of the last symbol in the frame, + * in microseconds. + * @param[in] psdu_length Number of bytes in the frame PSDU. + * + * @return Timestamp of the MHR of a given frame, in microseconds. + */ +uint64_t nrf_802154_mhr_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length); + /** * @} * @defgroup nrf_802154_transitions Functions to request FSM transitions and check current state @@ -971,7 +982,9 @@ extern void nrf_802154_transmit_failed(uint8_t * @brief Notifies that the energy detection procedure finished. * * @note This function passes the EnergyLevel defined in the 802.15.4-2006 specification: - * 0x00 - 0xff, proportionally to the detected energy level (dBm above receiver sensitivity). + * 0x00 - 0xff, where 0x00 represents -75dBm (10dBm above the worst allowed sensitivity level, + * which is -85dBm) and 0xff is the highest possible energy detection level, for which + * the measurements are guaranteed map linearly to the real energy level in dBm. * To calculate the result in dBm, use @ref nrf_802154_dbm_from_energy_level_calculate. * * @param[in] result Maximum energy detected during the energy detection procedure. diff --git a/drivers/nrf_802154/driver/include/nrf_802154_const.h b/drivers/nrf_802154/driver/include/nrf_802154_const.h index 6203121..9155ba2 100644 --- a/drivers/nrf_802154/driver/include/nrf_802154_const.h +++ b/drivers/nrf_802154/driver/include/nrf_802154_const.h @@ -180,6 +180,8 @@ #define PHY_SYMBOLS_PER_OCTET 2 ///< Number of symbols in a single byte (octet). #define PHY_SHR_SYMBOLS 10 ///< Number of symbols in the Synchronization Header (SHR). +#define PHY_MIN_RECEIVER_SENSITIVITY -85 ///< Lowest receiver sensitivity level in dBm according to 802.15.4-2020 specification, chapter 12.3.4 + #define ED_RESULT_MAX 0xff ///< Maximal ED result. #define BROADCAST_ADDRESS ((uint8_t[SHORT_ADDRESS_SIZE]) {0xff, 0xff}) ///< Broadcast short address. diff --git a/drivers/nrf_802154/driver/include/nrf_802154_types.h b/drivers/nrf_802154/driver/include/nrf_802154_types.h index cd7332e..076f8f4 100644 --- a/drivers/nrf_802154/driver/include/nrf_802154_types.h +++ b/drivers/nrf_802154/driver/include/nrf_802154_types.h @@ -481,13 +481,22 @@ typedef struct } data; // !< Result values that are valid only for successful operations. } nrf_802154_transmit_done_metadata_t; +/** + * @brief Represents components of tx_power to be applied for stages on transmit path. + */ +typedef struct +{ + nrf_radio_txpower_t radio_tx_power; // !< TX power to be applied to the RADIO peripheral. + int8_t fem_gain; // !< Gain of the Front-End Module in dB. +} nrf_802154_tx_power_split_t; + /** * @brief Structure that holds transmission parameters. */ typedef struct { nrf_802154_transmitted_frame_props_t frame_props; // !< Properties of the frame to be transmitted. - int8_t tx_power; // !< Power to be used when transmitting the frame. + nrf_802154_tx_power_split_t tx_power; // !< Power to be used when transmitting the frame, split into components to be applied on each stage on transmit path. bool cca; // !< If the driver is to perform CCA procedure before transmission. bool immediate; // !< If true, the driver schedules transmission immediately or never. If false, the transmission may be postponed // until its preconditions are met. diff --git a/drivers/nrf_802154/driver/src/fal/nrf_802154_fal.c b/drivers/nrf_802154/driver/src/fal/nrf_802154_fal.c deleted file mode 100644 index c057ab4..0000000 --- a/drivers/nrf_802154/driver/src/fal/nrf_802154_fal.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2017 - 2022, 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. - * - */ - -/** - * @file - * This file contains implementation of the nRF 802.15.4 FEM abstraction layer. - * - */ - -#include - -#include "nrf_802154_fal.h" - -int8_t nrf_802154_fal_tx_power_get(const uint8_t channel, const int8_t power) -{ - (void)channel; - - return power; -} diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c index a5d6a79..452a817 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_csma_ca.c @@ -77,7 +77,7 @@ static uint8_t m_be; ///< Backoff exponent, static uint8_t * mp_data; ///< Pointer to a buffer containing PHR and PSDU of the frame being transmitted. static nrf_802154_transmitted_frame_props_t m_data_props; ///< Structure containing detailed properties of data in buffer. -static int8_t m_tx_power; ///< Power in dBm to be used when transmitting the frame. +static nrf_802154_tx_power_split_t m_tx_power; ///< Power to be used when transmitting the frame split into components. static csma_ca_state_t m_state; ///< The current state of the CSMA-CA procedure. /** @@ -363,9 +363,9 @@ bool nrf_802154_csma_ca_start(uint8_t * p_d m_data_props = p_metadata->frame_props; m_nb = 0; m_be = nrf_802154_pib_csmaca_min_be_get(); - m_tx_power = - nrf_802154_tx_power_convert_metadata_to_raw_value(nrf_802154_pib_channel_get(), - p_metadata->tx_power); + (void)nrf_802154_tx_power_convert_metadata_to_tx_power_split(nrf_802154_pib_channel_get(), + p_metadata->tx_power, + &m_tx_power); random_backoff_start(); diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c index 3f86a68..53fef25 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_delayed_trx.c @@ -772,9 +772,9 @@ bool nrf_802154_delayed_trx_transmit(uint8_t * p p_dly_tx_data->tx.p_data = p_data; p_dly_tx_data->tx.params.frame_props = p_metadata->frame_props; - p_dly_tx_data->tx.params.tx_power = nrf_802154_tx_power_convert_metadata_to_raw_value( - p_metadata->channel, - p_metadata->tx_power); + (void)nrf_802154_tx_power_convert_metadata_to_tx_power_split(p_metadata->channel, + p_metadata->tx_power, + &p_dly_tx_data->tx.params.tx_power); p_dly_tx_data->tx.params.cca = p_metadata->cca; p_dly_tx_data->tx.params.immediate = true; p_dly_tx_data->tx.channel = p_metadata->channel; @@ -939,6 +939,8 @@ bool nrf_802154_delayed_trx_nearest_drx_time_to_midpoint_get(uint32_t * p_drx_ti result = nrf_802154_rsch_delayed_timeslot_time_to_start_get(m_dly_rx_data[i].id, &drx_time_to_start); + drx_time_to_start += RX_SETUP_TIME + RX_RAMP_UP_TIME; + if (result) { min_time_to_start = drx_time_to_start < min_time_to_start ? diff --git a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ie_writer.c b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ie_writer.c index 7da2204..e0dfa4f 100644 --- a/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ie_writer.c +++ b/drivers/nrf_802154/driver/src/mac_features/nrf_802154_ie_writer.c @@ -243,7 +243,7 @@ static void link_metrics_ie_write_commit(bool * p_written) if (mp_lm_margin_addr != NULL) { - *mp_lm_margin_addr = margin_scale((int16_t)rssi - ED_MIN_DBM); + *mp_lm_margin_addr = margin_scale((int16_t)rssi - ED_RSSIOFFS); *p_written = true; } } diff --git a/drivers/nrf_802154/driver/src/nrf_802154.c b/drivers/nrf_802154/driver/src/nrf_802154.c index 2ced051..33a49d3 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154.c +++ b/drivers/nrf_802154/driver/src/nrf_802154.c @@ -59,6 +59,7 @@ #include "nrf_802154_request.h" #include "nrf_802154_rx_buffer.h" #include "nrf_802154_tx_power.h" +#include "nrf_802154_rssi.h" #include "nrf_802154_stats.h" #include "hal/nrf_radio.h" #include "platform/nrf_802154_clock.h" @@ -156,7 +157,11 @@ void nrf_802154_tx_power_set(int8_t power) int8_t nrf_802154_tx_power_get(void) { - return nrf_802154_tx_power_constrained_pib_power_get(); + nrf_802154_tx_power_split_t split_power = {0}; + + (void)nrf_802154_tx_power_split_pib_power_get(&split_power); + + return split_power.fem_gain + split_power.radio_tx_power; } bool nrf_802154_coex_rx_request_mode_set(nrf_802154_coex_rx_request_mode_t mode) @@ -201,12 +206,12 @@ void nrf_802154_short_address_set(const uint8_t * 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); + return nrf_802154_addons_dbm_from_energy_level_calculate(energy_level); } uint8_t nrf_802154_ccaedthres_from_dbm_calculate(int8_t dbm) { - return dbm - ED_MIN_DBM; + return dbm - ED_RSSIOFFS; } uint64_t nrf_802154_first_symbol_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length) @@ -218,6 +223,11 @@ uint64_t nrf_802154_first_symbol_timestamp_get(uint64_t end_timestamp, uint8_t p return end_timestamp - (frame_symbols * PHY_US_PER_SYMBOL); } +uint64_t nrf_802154_mhr_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length) +{ + return end_timestamp - (psdu_length * PHY_SYMBOLS_PER_OCTET * PHY_US_PER_SYMBOL); +} + void nrf_802154_init(void) { static const nrf_802154_sl_crit_sect_interface_t crit_sect_int = @@ -490,13 +500,15 @@ bool nrf_802154_transmit_raw(uint8_t * p_data, nrf_802154_transmit_params_t params = { .frame_props = p_metadata->frame_props, - .tx_power = nrf_802154_tx_power_convert_metadata_to_raw_value( - nrf_802154_pib_channel_get(), - p_metadata->tx_power), - .cca = p_metadata->cca, - .immediate = false + .tx_power = {0}, + .cca = p_metadata->cca, + .immediate = false }; + (void)nrf_802154_tx_power_convert_metadata_to_tx_power_split(nrf_802154_pib_channel_get(), + p_metadata->tx_power, + ¶ms.tx_power); + result = are_frame_properties_valid(¶ms.frame_props); if (result) { @@ -536,13 +548,15 @@ bool nrf_802154_transmit(const uint8_t * p_data, nrf_802154_transmit_params_t params = { .frame_props = p_metadata->frame_props, - .tx_power = nrf_802154_tx_power_convert_metadata_to_raw_value( - nrf_802154_pib_channel_get(), - p_metadata->tx_power), - .cca = p_metadata->cca, - .immediate = false + .tx_power = {0}, + .cca = p_metadata->cca, + .immediate = false }; + (void)nrf_802154_tx_power_convert_metadata_to_tx_power_split(nrf_802154_pib_channel_get(), + p_metadata->tx_power, + ¶ms.tx_power); + result = are_frame_properties_valid(¶ms.frame_props); if (result) { diff --git a/drivers/nrf_802154/driver/src/nrf_802154_core.c b/drivers/nrf_802154/driver/src/nrf_802154_core.c index 535b762..7b94257 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_core.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_core.c @@ -115,13 +115,13 @@ static rx_buffer_t * const mp_current_rx_buffer = &nrf_802154_rx_buffers[0]; #endif -static uint8_t * mp_ack; ///< Pointer to Ack frame buffer. -static uint8_t * mp_tx_data; ///< Pointer to the data to transmit. -static uint32_t m_ed_time_left; ///< Remaining time of the current energy detection procedure [us]. -static uint8_t m_ed_result; ///< Result of the current energy detection procedure. -static uint8_t m_last_lqi; ///< LQI of the last received non-ACK frame, corrected for the temperature. -static int8_t m_last_rssi; ///< RSSI of the last received non-ACK frame, corrected for the temperature. -static int8_t m_tx_power; ///< Power in dBm to be used to transmit the current frame. +static uint8_t * mp_ack; ///< Pointer to Ack frame buffer. +static uint8_t * mp_tx_data; ///< Pointer to the data to transmit. +static uint32_t m_ed_time_left; ///< Remaining time of the current energy detection procedure [us]. +static uint8_t m_ed_result; ///< Result of the current energy detection procedure. +static uint8_t m_last_lqi; ///< LQI of the last received non-ACK frame, corrected for the temperature. +static nrf_802154_tx_power_split_t m_tx_power; ///< Power to be used to transmit the current frame split into components. +static int8_t m_last_rssi; ///< RSSI of the last received non-ACK frame, corrected for the temperature. static nrf_802154_frame_parser_data_t m_current_rx_frame_data; ///< RX frame parser data. @@ -499,26 +499,6 @@ static bool ack_is_requested(const uint8_t * p_frame) * @section Energy detection management **************************************************************************************************/ -/** Get ED result value. - * - * @param[in] ed_sample Energy Detection sample gathered from TRX module - * @returns ED result based on data collected during Energy Detection procedure. - */ -static uint8_t ed_result_get(uint8_t ed_sample) -{ - uint32_t result; - - result = nrf_802154_rssi_ed_corrected_get(ed_sample); - result *= ED_RESULT_FACTOR; - - if (result > ED_RESULT_MAX) - { - result = ED_RESULT_MAX; - } - - return (uint8_t)result; -} - /** Setup next iteration of energy detection procedure. * * Energy detection procedure is performed in iterations to make sure it is performed for requested @@ -1045,9 +1025,13 @@ static void rx_init(void) nrf_802154_trx_receive_buffer_set(rx_buffer_get()); + nrf_802154_tx_power_split_t split_power = {0}; + + (void)nrf_802154_tx_power_split_pib_power_get(&split_power); + nrf_802154_trx_receive_frame(BCC_INIT / 8U, m_trx_receive_frame_notifications_mask, - nrf_802154_tx_power_constrained_pib_power_get()); + &split_power); #if NRF_802154_TOTAL_TIMES_MEASUREMENT_ENABLED m_listening_start_hp_timestamp = nrf_802154_hp_timer_current_time_get(); @@ -1109,7 +1093,7 @@ static bool tx_init(const uint8_t * p_data, bool cca) m_flags.tx_with_cca = cca; nrf_802154_trx_transmit_frame(nrf_802154_tx_work_buffer_get(p_data), cca, - m_tx_power, + &m_tx_power, m_trx_transmit_frame_notifications_mask); return true; @@ -1173,8 +1157,11 @@ static void continuous_carrier_init(void) { return; } + nrf_802154_tx_power_split_t split_power = {0}; - nrf_802154_trx_continuous_carrier(nrf_802154_tx_power_constrained_pib_power_get()); + (void)nrf_802154_tx_power_split_pib_power_get(&split_power); + + nrf_802154_trx_continuous_carrier(&split_power); } /** Initialize Modulated Carrier operation. */ @@ -1190,7 +1177,11 @@ static void modulated_carrier_init(const uint8_t * p_data) return; } - nrf_802154_trx_modulated_carrier(p_data, nrf_802154_tx_power_constrained_pib_power_get()); + nrf_802154_tx_power_split_t split_power = {0}; + + (void)nrf_802154_tx_power_split_pib_power_get(&split_power); + + nrf_802154_trx_modulated_carrier(p_data, &split_power); } #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED @@ -1917,9 +1908,14 @@ void nrf_802154_trx_receive_frame_crcerror(void) // We don't change receive buffer, receive will go to the same that was already used #if !NRF_802154_DISABLE_BCC_MATCHING request_preconditions_for_state(m_state); + + nrf_802154_tx_power_split_t split_power = {0}; + + (void)nrf_802154_tx_power_split_pib_power_get(&split_power); + nrf_802154_trx_receive_frame(BCC_INIT / 8U, m_trx_receive_frame_notifications_mask, - nrf_802154_tx_power_constrained_pib_power_get()); + &split_power); #if NRF_802154_TOTAL_TIMES_MEASUREMENT_ENABLED m_listening_start_hp_timestamp = nrf_802154_hp_timer_current_time_get(); @@ -2550,7 +2546,7 @@ void nrf_802154_trx_energy_detection_finished(uint8_t ed_sample) state_set(RADIO_STATE_RX); rx_init(); - energy_detected_notify(ed_result_get(m_ed_result)); + energy_detected_notify(nrf_802154_rssi_ed_sample_convert(m_ed_result)); } diff --git a/drivers/nrf_802154/driver/src/nrf_802154_nrfx_addons.h b/drivers/nrf_802154/driver/src/nrf_802154_nrfx_addons.h index 2229b04..89d53e8 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_nrfx_addons.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_nrfx_addons.h @@ -32,14 +32,43 @@ * */ -#include "nrf.h" +#ifndef NRF_802154_NRFX_ADDONS_H__ +#define NRF_802154_NRFX_ADDONS_H__ -#if defined (NRF52840_XXAA) || defined(NRF52811_XXAA) || defined(NRF5340_XXAA_NETWORK) -#define ED_MIN_DBM (-92) ///< dBm value corresponding to value 0 in the EDSAMPLE register. -#define ED_RESULT_FACTOR 4 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. -#elif defined (NRF52833_XXAA) || defined(NRF52820_XXAA) -#define ED_MIN_DBM (-93) ///< dBm value corresponding to value 0 in the EDSAMPLE register. -#define ED_RESULT_FACTOR 5 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. +#include "nrf.h" +#include "nrf_802154_const.h" + +/* The usage of ED_RSSISCALE is described inprecisely in the nRF product specifications. The meaning of + this constant is the following: If we calculate ed_scaled = EDSAMPLE * ED_RSSISCALE, then + it is guaranteed that in the range 0-255 ed_scaled maps linearly to the ED power in dBm. This means, + that the maximum value in EDSAMPLE which can be reported in compliance with the 802.15.4 specification is + 255/ED_RSSISCALE. */ + +#if defined (NRF52840_XXAA) || defined(NRF52811_XXAA) +#define ED_RSSIOFFS (-92) ///< dBm value corresponding to value 0 in the EDSAMPLE register. +#define ED_RSSISCALE 4 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. +#elif defined (NRF52833_XXAA) || defined(NRF52820_XXAA) || defined(NRF5340_XXAA) +#define ED_RSSIOFFS (-93) ///< dBm value corresponding to value 0 in the EDSAMPLE register. +#define ED_RSSISCALE 5 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. #else #error "Selected chip is not supported." #endif + +#define EDSAMPLE_MIN_REPORTED_VALUE (PHY_MIN_RECEIVER_SENSITIVITY - ED_RSSIOFFS + 10) ///< Minimal reported EDSAMPLE value (reported as 0) +#define EDSAMPLE_MAX_REPORTED_VALUE (ED_RESULT_MAX / ED_RSSISCALE) ///< Maximal reported EDSAMPLE value (reported as 255) + +/** + * @brief Converts the energy level received during the energy detection procedure to a dBm value. + * + * @param[in] energy_level Energy level value compliant with the 802.15.4 specification (0-255) + * + * @return Result of the energy detection procedure in dBm. + */ +static inline int8_t nrf_802154_addons_dbm_from_energy_level_calculate(uint8_t energy_level) +{ + return ((int16_t)(EDSAMPLE_MAX_REPORTED_VALUE - EDSAMPLE_MIN_REPORTED_VALUE) * + ((int16_t)energy_level)) / + ED_RESULT_MAX + EDSAMPLE_MIN_REPORTED_VALUE + ED_RSSIOFFS; +} + +#endif // NRF_802154_NRFX_ADDONS_H__ diff --git a/drivers/nrf_802154/driver/src/nrf_802154_rssi.c b/drivers/nrf_802154/driver/src/nrf_802154_rssi.c index 438313f..9dafbc4 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_rssi.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_rssi.c @@ -38,6 +38,8 @@ * */ #include "nrf_802154_rssi.h" +#include "nrf_802154_nrfx_addons.h" +#include "nrf_802154_const.h" #include "nrf.h" #include @@ -86,6 +88,8 @@ int8_t nrf_802154_rssi_sample_temp_corr_value_get(uint8_t rssi_sample) } else { + // nRF52840 cannot work for a temperature above 85 degrees Celsius, so this part won't affect its operation, + // even if it isn't present in its errata. result = -4; } #else @@ -107,10 +111,10 @@ int8_t nrf_802154_rssi_sample_temp_corr_value_get(uint8_t rssi_sample) * * Coefficients were calculated as round(x * RSSI_COEFF_BASE) based on Errata 87. */ -#define RSSI_COEFF_A0 30198989L /* Initial value: 7.2 */ -#define RSSI_COEFF_A1 6543114L /* Initial value: 1.56 */ -#define RSSI_COEFF_A2 41524L /* Initial value: 9.9e-3 */ -#define RSSI_COEFF_A3 205L /* Initial value: 4.9e-5 */ +#define RSSI_COEFF_A0 30198989L /* Initial value: 7.2 */ +#define RSSI_COEFF_A1 6543114L /* Initial value: 1.56 */ +#define RSSI_COEFF_A2 41524L /* Initial value: 9.9e-3 */ +#define RSSI_COEFF_A3 205L /* Initial value: 4.9e-5 */ #define RSSI_COEFF_TEMP 209715L /* Initial value: 0.05 */ /** @brief Value used to increase precision of calculations. */ #define RSSI_COEFF_BASE (1UL << 22U) @@ -164,7 +168,7 @@ uint8_t nrf_802154_rssi_lqi_corrected_get(uint8_t lqi) return lqi - nrf_802154_rssi_sample_temp_corr_value_get(lqi); } -uint8_t nrf_802154_rssi_ed_corrected_get(uint8_t ed) +int16_t nrf_802154_rssi_ed_corrected_get(int16_t ed) { return ed - nrf_802154_rssi_sample_temp_corr_value_get(ed); } @@ -173,3 +177,31 @@ uint8_t nrf_802154_rssi_cca_ed_threshold_corrected_get(uint8_t cca_ed) { return cca_ed - nrf_802154_rssi_sample_temp_corr_value_get(cca_ed); } + +uint8_t nrf_802154_rssi_ed_sample_convert(uint8_t ed_sample) +{ + int16_t result; + + result = nrf_802154_rssi_ed_corrected_get(ed_sample); + result = ED_RESULT_MAX * (result - EDSAMPLE_MIN_REPORTED_VALUE) / + (EDSAMPLE_MAX_REPORTED_VALUE - EDSAMPLE_MIN_REPORTED_VALUE); + + if (result < 0) + { + result = 0; + } + + if (result > ED_RESULT_MAX) + { + result = ED_RESULT_MAX; + } + + return (uint8_t)result; +} + +int8_t nrf_802154_rssi_dbm_from_energy_level_calculate(uint8_t energy_level) +{ + return ((int16_t)(EDSAMPLE_MAX_REPORTED_VALUE - EDSAMPLE_MIN_REPORTED_VALUE) * + ((int16_t)energy_level)) / + ED_RESULT_MAX + EDSAMPLE_MIN_REPORTED_VALUE + ED_RSSIOFFS; +} diff --git a/drivers/nrf_802154/driver/src/nrf_802154_rssi.h b/drivers/nrf_802154/driver/src/nrf_802154_rssi.h index 107e709..7604c8c 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_rssi.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_rssi.h @@ -80,7 +80,7 @@ uint8_t nrf_802154_rssi_lqi_corrected_get(uint8_t lqi); * * @returns EDSAMPLE value corrected by a temperature factor. */ -uint8_t nrf_802154_rssi_ed_corrected_get(uint8_t ed); +int16_t nrf_802154_rssi_ed_corrected_get(int16_t ed); /** * @brief Adjusts the CCA ED threshold value using a temperature correction factor. @@ -91,6 +91,24 @@ uint8_t nrf_802154_rssi_ed_corrected_get(uint8_t ed); */ uint8_t nrf_802154_rssi_cca_ed_threshold_corrected_get(uint8_t cca_ed); +/** + * @brief Convert the hardware reported energy detection value to a value compliant with the 802.15.4 specification. + * + * @param[in] edsample The hardware reported value + * + * @returns 802.15.4 compliant energy detection value. + */ +uint8_t nrf_802154_rssi_ed_sample_convert(uint8_t ed_sample); + +/** + * @brief Converts the energy level received during the energy detection procedure to a dBm value. + * + * @param[in] energy_level Energy level passed by @ref nrf_802154_energy_detected. + * + * @return Result of the energy detection procedure in dBm. + */ +int8_t nrf_802154_rssi_dbm_from_energy_level_calculate(uint8_t energy_level); + /** *@} **/ diff --git a/drivers/nrf_802154/driver/src/nrf_802154_trx.c b/drivers/nrf_802154/driver/src/nrf_802154_trx.c index 167eec2..e2d12af 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_trx.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_trx.c @@ -41,7 +41,6 @@ #include "nrf_802154_config.h" #include "nrf_802154_const.h" -#include "nrf_802154_types.h" #include "nrf_802154_peripherals.h" #include "nrf_802154_pib.h" #include "nrf_802154_rssi.h" @@ -198,6 +197,7 @@ static nrf_802154_flags_t m_flags; ///< Flags used to store the current driver s /** @brief Value of TIMER internal counter from which the counting is resumed on RADIO.EVENTS_END event. */ static volatile uint32_t m_timer_value_on_radio_end_event; static volatile bool m_transmit_with_cca; +static int8_t m_fem_gain_in_disabled; static void rxframe_finish_disable_ppis(void); static void rxack_finish_disable_ppis(void); @@ -321,8 +321,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(void) +static void fem_for_pa_set(int8_t gain) { + (void)mpsl_fem_pa_gain_set(gain); 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, @@ -347,10 +348,12 @@ 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) +static void fem_for_tx_set(bool cca, int8_t gain) { bool success; + (void)mpsl_fem_pa_gain_set(gain); + if (cca) { bool pa_set = false; @@ -461,6 +464,7 @@ void nrf_802154_trx_module_reset(void) m_trx_state = TRX_STATE_DISABLED; m_timer_value_on_radio_end_event = 0; m_transmit_with_cca = false; + m_fem_gain_in_disabled = 0; mp_receive_buffer = NULL; memset(&m_flags, 0, sizeof(m_flags)); @@ -535,6 +539,8 @@ void nrf_802154_trx_enable(void) assert(nrf_radio_shorts_get(NRF_RADIO) == SHORTS_IDLE); + mpsl_fem_pa_is_configured(&m_fem_gain_in_disabled); + #if defined(NRF52840_XXAA) || \ defined(NRF52833_XXAA) || \ defined(NRF52820_XXAA) || \ @@ -647,6 +653,9 @@ void nrf_802154_trx_disable(void) mpsl_fem_pa_configuration_clear(); mpsl_fem_abort_clear(); + /* Restore gain of the FEM to the state latched in nrf_802154_trx_enable */ + (void)mpsl_fem_pa_gain_set(m_fem_gain_in_disabled); + if (m_trx_state != TRX_STATE_IDLE) { fem_power_down_now(); @@ -909,7 +918,7 @@ bool nrf_802154_trx_receive_buffer_set(void * p_receive_buffer) void nrf_802154_trx_receive_frame(uint8_t bcc, nrf_802154_trx_receive_notifications_t notifications_mask, - int8_t ack_tx_power) + const nrf_802154_tx_power_split_t * p_ack_tx_power) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -928,7 +937,7 @@ void nrf_802154_trx_receive_frame(uint8_t bcc, m_flags.rssi_settled = false; - nrf_radio_txpower_set(NRF_RADIO, (nrf_radio_txpower_t)ack_tx_power); + nrf_radio_txpower_set(NRF_RADIO, p_ack_tx_power->radio_tx_power); if (mp_receive_buffer != NULL) { @@ -1014,6 +1023,9 @@ void nrf_802154_trx_receive_frame(uint8_t bcc, nrf_timer_cc_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_CC_CHANNEL0, delta_time); } + // Set FEM PA gain for ACK transmission + mpsl_fem_pa_gain_set(p_ack_tx_power->fem_gain); + m_timer_value_on_radio_end_event = delta_time; // Select antenna @@ -1140,7 +1152,7 @@ bool nrf_802154_trx_rssi_sample_is_available(void) void nrf_802154_trx_transmit_frame(const void * p_transmit_buffer, bool cca, - int8_t tx_power, + const nrf_802154_tx_power_split_t * p_tx_power, nrf_802154_trx_transmit_notifications_t notifications_mask) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -1153,7 +1165,8 @@ void nrf_802154_trx_transmit_frame(const void * p_tra m_trx_state = TRX_STATE_TXFRAME; m_transmit_with_cca = cca; - nrf_radio_txpower_set(NRF_RADIO, (nrf_radio_txpower_t)tx_power); + nrf_radio_txpower_set(NRF_RADIO, p_tx_power->radio_tx_power); + nrf_radio_packetptr_set(NRF_RADIO, p_transmit_buffer); // Set shorts @@ -1197,7 +1210,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); + fem_for_tx_set(cca, p_tx_power->fem_gain); nrf_802154_trx_antenna_update(); nrf_802154_trx_ppi_for_ramp_up_set(cca ? NRF_RADIO_TASK_RXEN : NRF_RADIO_TASK_TXEN, false); @@ -1769,7 +1782,7 @@ static void standalone_cca_abort(void) #if NRF_802154_CARRIER_FUNCTIONS_ENABLED -void nrf_802154_trx_continuous_carrier(int8_t tx_power) +void nrf_802154_trx_continuous_carrier(const nrf_802154_tx_power_split_t * p_tx_power) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -1778,10 +1791,10 @@ void nrf_802154_trx_continuous_carrier(int8_t tx_power) m_trx_state = TRX_STATE_CONTINUOUS_CARRIER; // Set Tx Power - nrf_radio_txpower_set(NRF_RADIO, (nrf_radio_txpower_t)tx_power); + nrf_radio_txpower_set(NRF_RADIO, p_tx_power->radio_tx_power); // Set FEM - fem_for_pa_set(); + fem_for_pa_set(p_tx_power->fem_gain); // Select antenna nrf_802154_trx_antenna_update(); @@ -1824,7 +1837,8 @@ static void continuous_carrier_abort(void) nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH); } -void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer, int8_t tx_power) +void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer, + const nrf_802154_tx_power_split_t * p_tx_power) { nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW); @@ -1834,7 +1848,7 @@ void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer, int8_t tx_ m_trx_state = TRX_STATE_MODULATED_CARRIER; // Set Tx Power - nrf_radio_txpower_set(NRF_RADIO, (nrf_radio_txpower_t)tx_power); + nrf_radio_txpower_set(NRF_RADIO, p_tx_power->radio_tx_power); // Set Tx buffer nrf_radio_packetptr_set(NRF_RADIO, p_transmit_buffer); @@ -1843,7 +1857,7 @@ void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer, int8_t tx_ nrf_radio_shorts_set(NRF_RADIO, SHORTS_MOD_CARRIER); // Set FEM - fem_for_pa_set(); + fem_for_pa_set(p_tx_power->fem_gain); // Select antenna nrf_802154_trx_antenna_update(); diff --git a/drivers/nrf_802154/driver/src/nrf_802154_trx.h b/drivers/nrf_802154/driver/src/nrf_802154_trx.h index 235309c..10a212b 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_trx.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_trx.h @@ -47,6 +47,7 @@ #include "nrf_802154_config.h" #include "nrf_802154_sl_types.h" +#include "nrf_802154_types.h" #ifdef __cplusplus extern "C" { @@ -208,11 +209,11 @@ void nrf_802154_trx_cca_configuration_update(void); * @param[in] notifications_mask Selects additional notifications generated during a frame reception. * It is bitwise combination of @ref nrf_802154_trx_receive_notifications_t values. * When NRF_802154_DISABLE_BCC_MATCHING != 0, flag @ref TRX_RECEIVE_NOTIFICATION_PRESTARTED is forbidden. - * @param[in] ack_tx_power Selects the power which should be used to transmitted an ACK if required. + * @param[in] p_ack_tx_power Selects the power which should be used to transmitted an ACK if required. */ void nrf_802154_trx_receive_frame(uint8_t bcc, nrf_802154_trx_receive_notifications_t notifications_mask, - int8_t ack_tx_power); + const nrf_802154_tx_power_split_t * p_ack_tx_power); /**@brief Puts the trx module into receive ACK mode. * @@ -340,14 +341,14 @@ bool nrf_802154_trx_receive_buffer_set(void * p_receive_buffer); * @param cca Selects if CCA procedure should be performed prior to * real transmission. If false no cca will be performed. * If true, cca will be performed. - * @param tx_power Transmit power in dBm. + * @param p_tx_power Transmit power in dBm. * @param notifications_mask Selects additional notifications generated during a frame transmission. * It is bitwise combination of @ref nrf_802154_trx_transmit_notifications_t values. * @note To transmit ack after frame is received use @ref nrf_802154_trx_transmit_ack. */ void nrf_802154_trx_transmit_frame(const void * p_transmit_buffer, bool cca, - int8_t tx_power, + const nrf_802154_tx_power_split_t * p_tx_power, nrf_802154_trx_transmit_notifications_t notifications_mask); /**@brief Puts the trx module into transmit ACK mode. @@ -390,12 +391,12 @@ void nrf_802154_trx_standalone_cca(void); /**@brief Starts generating continuous carrier. * - * @param[in] tx_power Transmit power in dBm. + * @param[in] p_tx_power Transmit power in dBm. * * Generation of a continuous carrier generates no handlers. It may be terminated by a call to * @ref nrf_802154_trx_abort or @ref nrf_802154_trx_disable. */ -void nrf_802154_trx_continuous_carrier(int8_t tx_power); +void nrf_802154_trx_continuous_carrier(const nrf_802154_tx_power_split_t * p_tx_power); /**@brief Restarts generating continuous carrier * @@ -410,9 +411,10 @@ void nrf_802154_trx_continuous_carrier_restart(void); /**@brief Starts generating modulated carrier with given buffer. * * @param[in] p_transmit_buffer Pointer to a buffer used for modulating the carrier wave. - * @param[in] tx_power Transmit power in dBm. + * @param[in] p_tx_power Transmit power in dBm. */ -void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer, int8_t tx_power); +void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer, + const nrf_802154_tx_power_split_t * p_tx_power); /** @brief Restarts generating modulated carrier.*/ void nrf_802154_trx_modulated_carrier_restart(void); diff --git a/drivers/nrf_802154/driver/src/nrf_802154_tx_power.c b/drivers/nrf_802154/driver/src/nrf_802154_tx_power.c index e1881f6..971543a 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_tx_power.c +++ b/drivers/nrf_802154/driver/src/nrf_802154_tx_power.c @@ -35,7 +35,7 @@ #include "nrf_802154_tx_power.h" #include "nrf_802154_pib.h" #include "nrf_802154_utils.h" -#include "fal/nrf_802154_fal.h" +#include "nrf_802154_fal.h" /** * Converts TX power integer values to RADIO TX power allowed values. @@ -98,38 +98,60 @@ static nrf_radio_txpower_t to_radio_tx_power_convert(int8_t integer_tx_power) } /** - * Converts TX power integer values to RADIO TX power allowed values, constrained by the allowed TX power allowed for - * a specific channel. + * Constrains the TX power by the maximum allowed TX power allowed for a specific channel, splits it into + * components to be applied on each stage of the transmit path and for the TX power applied to the RADIO peripheral + * converts the integer value to a RADIO TX power allowed value. * - * @param[in] channel The channel based on which the power should be constrained - * @param[in] tx_power Unconstrained TX power integer value. + * @param[in] channel The channel based on which the power should be constrained + * @param[in] tx_power Unconstrained TX power integer value. + * @param[out] split_power Pointer to the structure holding TX power split into constrained and converted components. * - * @retval RADIO TX power allowed and constrained value. + * @retval true Calculation performed successfully. + * @retval false Given @p power cannot be achieved. If requested value is too high + * the @p p_tx_power_split will be set to a value representing maximum + * achievable power. If the requested value is too low, the + * @p p_tx_power_split will be set to a value representing minimum + * achievable power. */ -static nrf_radio_txpower_t constrain_and_convert_tx_power(uint8_t channel, int8_t tx_power) +static bool constrain_split_and_convert_tx_power( + uint8_t channel, + int8_t tx_power, + nrf_802154_tx_power_split_t * const split_power) { - int8_t constrained_power = nrf_802154_fal_tx_power_get(channel, tx_power); + int32_t ret = 0; + nrf_802154_fal_tx_power_split_t fal_split_power = {0}; - return to_radio_tx_power_convert(constrained_power); + ret = nrf_802154_fal_tx_power_split(channel, tx_power, &fal_split_power); + + split_power->fem_gain = fal_split_power.fem_gain; + split_power->radio_tx_power = to_radio_tx_power_convert(fal_split_power.radio_tx_power); + + return (0 == ret); } -nrf_radio_txpower_t nrf_802154_tx_power_convert_metadata_to_raw_value( - uint8_t channel, - nrf_802154_tx_power_metadata_t tx_power) +bool nrf_802154_tx_power_convert_metadata_to_tx_power_split( + uint8_t channel, + nrf_802154_tx_power_metadata_t tx_power, + nrf_802154_tx_power_split_t * const p_tx_power_split) { int8_t power_unconstrained = tx_power.use_metadata_value ? tx_power.power : nrf_802154_pib_tx_power_get(); - return constrain_and_convert_tx_power(channel, power_unconstrained); + return constrain_split_and_convert_tx_power(channel, power_unconstrained, p_tx_power_split); } -nrf_radio_txpower_t nrf_802154_tx_power_constrained_pib_power_get(void) +bool nrf_802154_tx_power_split_pib_power_get(nrf_802154_tx_power_split_t * const p_split_power) { - return constrain_and_convert_tx_power(nrf_802154_pib_channel_get(), - nrf_802154_pib_tx_power_get()); + return constrain_split_and_convert_tx_power(nrf_802154_pib_channel_get(), + nrf_802154_pib_tx_power_get(), + p_split_power); } -nrf_radio_txpower_t nrf_802154_tx_power_constrained_pib_power_for_channel_get(uint8_t channel) +bool nrf_802154_tx_power_split_pib_power_for_channel_get( + uint8_t channel, + nrf_802154_tx_power_split_t * const p_split_power) { - return constrain_and_convert_tx_power(channel, nrf_802154_pib_tx_power_get()); + return constrain_split_and_convert_tx_power(channel, + nrf_802154_pib_tx_power_get(), + p_split_power); } diff --git a/drivers/nrf_802154/driver/src/nrf_802154_tx_power.h b/drivers/nrf_802154/driver/src/nrf_802154_tx_power.h index b175e86..1116c1a 100644 --- a/drivers/nrf_802154/driver/src/nrf_802154_tx_power.h +++ b/drivers/nrf_802154/driver/src/nrf_802154_tx_power.h @@ -39,37 +39,63 @@ #include "nrf_802154.h" -/**@brief Convert tx_power value passed through metadata to a raw value in dBm used by the core module. +/**@brief Convert tx_power value passed through metadata to raw components in dBms to be applied + * on each stage of the transmit path. - * This function also ensures that the value meets the constraints for the current channel. + * This function also ensures that the values meet the constraints for the given channel. * - * @param[in] channel The channel to be used for transmission - * @param[in] tx_power The value passed to the transmit metadata. + * @param[in] channel The channel to be used for transmission + * @param[in] tx_power The value passed to the transmit metadata. + * @param[out] p_tx_power_split Pointer to the structure holding TX power split into raw components in dBm. * - * @retval Returns the power in dBm which will be used to transmit the frame. + * @retval true Calculation performed successfully. + * @retval false Given @p tx_power cannot be achieved. If requested value is too high + * the @p p_tx_power_split will be set to a value representing maximum + * achievable power. If the requested value is too low, the + * @p p_tx_power_split will be set to a value representing minimum + * achievable power. * */ -nrf_radio_txpower_t nrf_802154_tx_power_convert_metadata_to_raw_value( - uint8_t channel, - nrf_802154_tx_power_metadata_t tx_power); +bool nrf_802154_tx_power_convert_metadata_to_tx_power_split( + uint8_t channel, + nrf_802154_tx_power_metadata_t tx_power, + nrf_802154_tx_power_split_t * const p_tx_power_split); -/**@brief Get the transmit power stored in PIB after applying the power constraints for the current channel. +/**@brief Get the transmit power stored in PIB after applying the power constraints for the current channel and splitting + * into components to be applied on each stage of the transmit path. * * The current channel is acquired from PIB. * - * @retval Returns the constrained power in dBm which will be used to transmit the frame. + * @param[out] p_split_power Pointer to the structure holding TX power split into components in dBm. * - */ -nrf_radio_txpower_t nrf_802154_tx_power_constrained_pib_power_get(void); + * @retval true Calculation performed successfully. + * @retval false cannot be achieved. If requested value is too high + * Current power set in PIB the @p p_split_power will be set to a value representing maximum + * achievable power. If the requested value is too low, the + * @p p_split_power will be set to a value representing minimum + * achievable power. -/**@brief Get the transmit power stored in PIB after applying the power constraints for the given channel. - * - * @param[in] channel The channel based on which the power should be constrained - * - * @retval Returns the power in dBm which will be used to transmit the frame. * */ -nrf_radio_txpower_t nrf_802154_tx_power_constrained_pib_power_for_channel_get(uint8_t channel); +bool nrf_802154_tx_power_split_pib_power_get(nrf_802154_tx_power_split_t * const p_split_power); + +/**@brief Get the transmit power stored in PIB after applying the power constraints for the given channel and splitting + * into components to be applied on each stage of the transmit path. + * + * @param[in] channel The channel based on which the power should be constrained + * @param[out] p_split_power Pointer to the structure holding TX power split into components in dBm. + * + * @retval true Calculation performed successfully. + * @retval false Current power set in PIB cannot be achieved. If requested value is too high + * the @p p_split_power will be set to a value representing maximum + * achievable power. If the requested value is too low, the + * @p p_split_power will be set to a value representing minimum + * achievable power. + * + */ +bool nrf_802154_tx_power_split_pib_power_for_channel_get( + uint8_t channel, + nrf_802154_tx_power_split_t * const p_split_power); /** *@} diff --git a/drivers/nrf_802154/serialization/include/host/nrf_802154.h b/drivers/nrf_802154/serialization/include/host/nrf_802154.h index d1da659..e30d585 100644 --- a/drivers/nrf_802154/serialization/include/host/nrf_802154.h +++ b/drivers/nrf_802154/serialization/include/host/nrf_802154.h @@ -713,6 +713,17 @@ int8_t nrf_802154_dbm_from_energy_level_calculate(uint8_t energy_level); */ uint64_t nrf_802154_first_symbol_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length); +/** + * @brief Calculates the timestamp of the MAC Header in a received frame. + * + * @param[in] end_timestamp Timestamp of the end of the last symbol in the frame, + * in microseconds. + * @param[in] psdu_length Number of bytes in the frame PSDU. + * + * @return Timestamp of the MHR of a given frame, in microseconds. + */ +uint64_t nrf_802154_mhr_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length); + /** * @} * @defgroup nrf_802154_ifs Inter-frame spacing feature diff --git a/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h b/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h index 57481f6..f7a752e 100644 --- a/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h +++ b/drivers/nrf_802154/serialization/include/host/nrf_802154_callouts.h @@ -72,7 +72,9 @@ extern void nrf_802154_cca_failed(nrf_802154_cca_error_t error); * @brief Notifies that the energy detection procedure finished. * * @note This function passes the EnergyLevel defined in the 802.15.4-2006 specification: - * 0x00 - 0xff, proportionally to the detected energy level (dBm above receiver sensitivity). + * 0x00 - 0xff, where 0x00 represents -75dBm (10dBm above the worst allowed sensitivity level, + * which is -85dBm) and 0xff is the highest possible energy detection level, for which + * the measurements are guaranteed map linearly to the real energy level in dBm. * To calculate the result in dBm, use @ref nrf_802154_dbm_from_energy_level_calculate. * * @param[in] result Maximum energy detected during the energy detection procedure. diff --git a/drivers/nrf_802154/serialization/include/host/nrf_802154_const.h b/drivers/nrf_802154/serialization/include/host/nrf_802154_const.h index e83bee0..cd0873d 100644 --- a/drivers/nrf_802154/serialization/include/host/nrf_802154_const.h +++ b/drivers/nrf_802154/serialization/include/host/nrf_802154_const.h @@ -179,6 +179,8 @@ #define PHY_SYMBOLS_PER_OCTET 2 ///< Number of symbols in a single byte (octet). #define PHY_SHR_SYMBOLS 10 ///< Number of symbols in the Synchronization Header (SHR). +#define PHY_MIN_RECEIVER_SENSITIVITY -85 ///< Lowest receiver sensitivity level in dBm according to 802.15.4-2020 specification, chapter 12.3.4 + #define ED_RESULT_MAX 0xff ///< Maximal ED result. #define BROADCAST_ADDRESS ((uint8_t[SHORT_ADDRESS_SIZE]) {0xff, 0xff}) ///< Broadcast short address. @@ -223,7 +225,4 @@ #define IE_DATA_OFFSET 0x02 ///< Information element data offset #define IE_HEADER_ELEMENT_ID_OFFSET 0x07 ///< Bit offset of Element ID field in a Header IE header. -#define ED_MIN_DBM (-92) ///< dBm value corresponding to value 0 in the EDSAMPLE register. -#define ED_RESULT_FACTOR 4 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. - #endif // NRF_802154_CONST_H_ diff --git a/drivers/nrf_802154/serialization/src/include/nrf_802154_nrfx_addons.h b/drivers/nrf_802154/serialization/src/include/nrf_802154_nrfx_addons.h new file mode 100644 index 0000000..d655f50 --- /dev/null +++ b/drivers/nrf_802154/serialization/src/include/nrf_802154_nrfx_addons.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022, 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. + * + */ + +#ifndef NRF_802154_NRFX_ADDONS_H__ +#define NRF_802154_NRFX_ADDONS_H__ + +#include "nrf.h" +#include "nrf_802154_const.h" + +/* The usage of ED_RSSISCALE is described imprecisely in the nRF product specifications. The meaning of + this constant is the following: If we calculate ed_scaled = EDSAMPLE * ED_RSSISCALE, then + it is guaranteed that in the range 0-255 ed_scaled maps linearly to the ED power in dBm. This means, + that the maximum value in EDSAMPLE which can be reported in compliance with the 802.15.4 specification is + 255/ED_RSSISCALE. */ + +#if defined (NRF52840_XXAA) || defined(NRF52811_XXAA) +#define ED_RSSIOFFS (-92) ///< dBm value corresponding to value 0 in the EDSAMPLE register. +#define ED_RSSISCALE 4 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. +#elif defined (NRF52833_XXAA) || defined(NRF52820_XXAA) || defined(NRF5340_XXAA) +#define ED_RSSIOFFS (-93) ///< dBm value corresponding to value 0 in the EDSAMPLE register. +#define ED_RSSISCALE 5 ///< Factor needed to calculate the ED result based on the data from the RADIO peripheral. +#else +#error "Selected chip is not supported." +#endif + +#define EDSAMPLE_MIN_REPORTED_VALUE (PHY_MIN_RECEIVER_SENSITIVITY - ED_RSSIOFFS + 10) ///< Minimal reported EDSAMPLE value (reported as 0) +#define EDSAMPLE_MAX_REPORTED_VALUE (ED_RESULT_MAX / ED_RSSISCALE) ///< Maximal reported EDSAMPLE value (reported as 255) + +/** + * @brief Converts the energy level received during the energy detection procedure to a dBm value. + * + * @param[in] energy_level Energy level value compliant with the 802.15.4 specification (0-255) + * + * @return Result of the energy detection procedure in dBm. + */ +static inline int8_t nrf_802154_addons_dbm_from_energy_level_calculate(uint8_t energy_level) +{ + return ((int16_t)(EDSAMPLE_MAX_REPORTED_VALUE - EDSAMPLE_MIN_REPORTED_VALUE) * + ((int16_t)energy_level)) / + ED_RESULT_MAX + EDSAMPLE_MIN_REPORTED_VALUE + ED_RSSIOFFS; +} + +#endif // NRF_802154_NRFX_ADDONS_H__ diff --git a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c index b3d9bbc..7582c40 100644 --- a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c +++ b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_app.c @@ -63,6 +63,7 @@ #include "nrf_802154.h" #include "nrf_802154_config.h" #include "nrf_802154_types.h" +#include "nrf_802154_nrfx_addons.h" /** * @brief Wait with timeout for SPINEL_STATUS_OK to be received. @@ -1489,8 +1490,9 @@ bool nrf_802154_transmit_raw_at(uint8_t * p_data { .frame_props = NRF_802154_TRANSMITTED_FRAME_PROPS_DEFAULT_INIT, .cca = true, - .channel = 11, - .tx_power = {.use_metadata_value = false} + // channel set to 0 will be replaced on net core by the current channel from PIB + .channel = 0, + .tx_power = {.use_metadata_value = false} }; p_metadata = &metadata_default; @@ -1769,7 +1771,7 @@ bail: int8_t nrf_802154_dbm_from_energy_level_calculate(uint8_t energy_level) { - return ED_MIN_DBM + (energy_level / ED_RESULT_FACTOR); + return nrf_802154_addons_dbm_from_energy_level_calculate(energy_level); } uint64_t nrf_802154_first_symbol_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length) @@ -1781,6 +1783,11 @@ uint64_t nrf_802154_first_symbol_timestamp_get(uint64_t end_timestamp, uint8_t p return end_timestamp - (frame_symbols * PHY_US_PER_SYMBOL); } +uint64_t nrf_802154_mhr_timestamp_get(uint64_t end_timestamp, uint8_t psdu_length) +{ + return end_timestamp - (psdu_length * PHY_SYMBOLS_PER_OCTET * PHY_US_PER_SYMBOL); +} + void nrf_802154_security_global_frame_counter_set(uint32_t frame_counter) { nrf_802154_ser_err_t res; diff --git a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c index dea2923..3bd17cf 100644 --- a/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c +++ b/drivers/nrf_802154/serialization/src/nrf_802154_spinel_dec_net.c @@ -1354,6 +1354,13 @@ static nrf_802154_ser_err_t spinel_decode_prop_nrf_802154_transmit_raw_at( return NRF_802154_SERIALIZATION_ERROR_NO_MEMORY; } + // tx_metadata.channel set to 0 means that NULL was passed as metadata on app core + // and the channel should be set to the current channel from PIB + if (0 == tx_metadata.channel) + { + tx_metadata.channel = nrf_802154_channel_get(); + } + bool result = nrf_802154_transmit_raw_at(p_local_frame_ptr, tx_time, &tx_metadata); if (!result) diff --git a/drivers/nrf_802154/driver/src/fal/nrf_802154_fal.h b/drivers/nrf_802154/sl/include/nrf_802154_fal.h similarity index 68% rename from drivers/nrf_802154/driver/src/fal/nrf_802154_fal.h rename to drivers/nrf_802154/sl/include/nrf_802154_fal.h index d2a8914..5ef1a33 100644 --- a/drivers/nrf_802154/driver/src/fal/nrf_802154_fal.h +++ b/drivers/nrf_802154/sl/include/nrf_802154_fal.h @@ -46,6 +46,15 @@ extern "C" { #endif +/** + * @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. + int8_t fem_gain; // !< Gain of the Front-End Module in dB. +} nrf_802154_fal_tx_power_split_t; + /** * @brief Returns 'power' value. * @@ -58,6 +67,20 @@ extern "C" { */ int8_t nrf_802154_fal_tx_power_get(const uint8_t channel, const int8_t power); +/** @brief Splits transmit power value into components to be applied on each stage on the transmit path. + * + * @note This is a stub implementation used when MPSL is not linked. + * + * @param[in] channel Ignored. + * @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 Always 0. + */ +int32_t nrf_802154_fal_tx_power_split(const uint8_t channel, + const int8_t power, + nrf_802154_fal_tx_power_split_t * const p_tx_power_split); + #ifdef __cplusplus } #endif diff --git a/drivers/nrf_802154/sl/sl_opensource/include/protocol/mpsl_fem_protocol_api.h b/drivers/nrf_802154/sl/sl_opensource/include/protocol/mpsl_fem_protocol_api.h index 17a919b..8748edb 100644 --- a/drivers/nrf_802154/sl/sl_opensource/include/protocol/mpsl_fem_protocol_api.h +++ b/drivers/nrf_802154/sl/sl_opensource/include/protocol/mpsl_fem_protocol_api.h @@ -103,6 +103,19 @@ typedef struct #endif } mpsl_fem_event_t; +/** TX power, dBm. */ +typedef int8_t mpsl_tx_power_t; + +/** @brief Represents components of tx_power to be applied for stages on transmit path. */ +typedef struct +{ + /** TX power to be applied to the RADIO peripheral. */ + mpsl_tx_power_t radio_tx_power; + + /** Gain of the Front-End Module in dB. */ + int8_t fem_gain; +} mpsl_tx_power_split_t; + /** @brief Disable Front End Module. * * Some Front End Module devices can be explicitly disabled after PA and LNA activities are @@ -292,6 +305,38 @@ int32_t mpsl_fem_abort_clear(void); */ 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. However, if @p power is lower than the minimum achievable power, + * or larger than the maximum achievable power, the function returns failure. + * + * @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. + * + * @retval 0 Calculation performed successfully. + * @retval - ::NRF_EINVAL Given @p power cannot be achieved. If requested value is too high + * the @p p_tx_power_split will be set to a value representing maximum + * achievable power. If the requested value is too low, the + * @p p_tx_power_split will be set to a value representing minimum + * achievable power. + */ +int32_t mpsl_fem_tx_power_split(const mpsl_tx_power_t power, + mpsl_tx_power_split_t *const p_tx_power_split); + +/** @brief Sets PA gain. + * + * @note The gain 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. + * + * @param[in] gain Gain in dB to be set. + * + * @retval 0 Gain has been set successfully. + * @retval -NRF_EINVAL Gain could not be set. Provided @p gain is invalid. + */ +int32_t mpsl_fem_pa_gain_set(int8_t gain); + /** @brief Checks if the PA signaling is configured and enabled, and gets * the configured gain in dB. * diff --git a/drivers/nrf_802154/sl/sl_opensource/src/nrf_802154_sl_fem.c b/drivers/nrf_802154/sl/sl_opensource/src/nrf_802154_sl_fem.c index f98c161..2cd7b52 100644 --- a/drivers/nrf_802154/sl/sl_opensource/src/nrf_802154_sl_fem.c +++ b/drivers/nrf_802154/sl/sl_opensource/src/nrf_802154_sl_fem.c @@ -37,6 +37,8 @@ #include #include +#include "nrf_802154_fal.h" + #include "protocol/mpsl_fem_protocol_api.h" #ifdef __cplusplus @@ -110,6 +112,22 @@ void mpsl_fem_cleanup(void) // Intentionally empty } +int32_t mpsl_fem_tx_power_split(const mpsl_tx_power_t power, + mpsl_tx_power_split_t * const p_tx_power_split) +{ + p_tx_power_split->radio_tx_power = power; + p_tx_power_split->fem_gain = 0; + + return 0; +} + +int32_t mpsl_fem_pa_gain_set(int8_t gain) +{ + (void)gain; + + return 0; +} + void mpsl_fem_pa_is_configured(int8_t * const p_gain) { (void)p_gain; @@ -138,6 +156,18 @@ int8_t nrf_802154_fal_tx_power_get(const uint8_t channel, const int8_t power) return power; } +int32_t nrf_802154_fal_tx_power_split(const uint8_t channel, + const int8_t power, + nrf_802154_fal_tx_power_split_t * const p_tx_power_split) +{ + (void)channel; + + p_tx_power_split->radio_tx_power = power; + p_tx_power_split->fem_gain = 0; + + return 0; +} + #ifdef __cplusplus } #endif