hal_nordic/drivers/nrf_802154/driver/src/nrf_802154_tx_power.c

158 lines
6.3 KiB
C

/*
* 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.
*
*/
#include "nrf_802154_tx_power.h"
#include "nrf_802154_pib.h"
#include "nrf_802154_utils.h"
#include "nrf_802154_fal.h"
/**
* Converts TX power integer values to RADIO TX power allowed values.
*
* @param[in] integer_tx_power TX power integer value.
*
* @retval RADIO TX power allowed value.
*/
static nrf_radio_txpower_t to_radio_tx_power_convert(int8_t integer_tx_power)
{
static const nrf_radio_txpower_t allowed_values[] =
{
#if defined(RADIO_TXPOWER_TXPOWER_Neg40dBm)
NRF_RADIO_TXPOWER_NEG40DBM, /**< -40 dBm. */
#endif
NRF_RADIO_TXPOWER_NEG20DBM, /**< -20 dBm. */
NRF_RADIO_TXPOWER_NEG16DBM, /**< -16 dBm. */
NRF_RADIO_TXPOWER_NEG12DBM, /**< -12 dBm. */
NRF_RADIO_TXPOWER_NEG8DBM, /**< -8 dBm. */
NRF_RADIO_TXPOWER_NEG4DBM, /**< -4 dBm. */
NRF_RADIO_TXPOWER_0DBM, /**< 0 dBm. */
#if defined(RADIO_TXPOWER_TXPOWER_Pos2dBm)
NRF_RADIO_TXPOWER_POS2DBM, /**< 2 dBm. */
#endif
#if defined(RADIO_TXPOWER_TXPOWER_Pos3dBm)
NRF_RADIO_TXPOWER_POS3DBM, /**< 3 dBm. */
#endif
#if defined(RADIO_TXPOWER_TXPOWER_Pos4dBm)
NRF_RADIO_TXPOWER_POS4DBM, /**< 4 dBm. */
#endif
#if defined(RADIO_TXPOWER_TXPOWER_Pos5dBm)
NRF_RADIO_TXPOWER_POS5DBM, /**< 5 dBm. */
#endif
#if defined(RADIO_TXPOWER_TXPOWER_Pos6dBm)
NRF_RADIO_TXPOWER_POS6DBM, /**< 6 dBm. */
#endif
#if defined(RADIO_TXPOWER_TXPOWER_Pos7dBm)
NRF_RADIO_TXPOWER_POS7DBM, /**< 7 dBm. */
#endif
#if defined(RADIO_TXPOWER_TXPOWER_Pos8dBm)
NRF_RADIO_TXPOWER_POS8DBM, /**< 8 dBm. */
#endif
};
nrf_radio_txpower_t radio_tx_power = allowed_values[NUMELTS(allowed_values) - 1];
if (integer_tx_power < (int8_t)radio_tx_power)
{
for (uint32_t i = 0; i < NUMELTS(allowed_values); i++)
{
if (integer_tx_power <= (int8_t)allowed_values[i])
{
radio_tx_power = allowed_values[i];
break;
}
}
}
return radio_tx_power;
}
/**
* 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[out] split_power Pointer to the structure holding TX power split into constrained and converted components.
*
* @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 bool constrain_split_and_convert_tx_power(
uint8_t channel,
int8_t tx_power,
nrf_802154_tx_power_split_t * const split_power)
{
int32_t ret = 0;
nrf_802154_fal_tx_power_split_t fal_split_power = {0};
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);
}
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_split_and_convert_tx_power(channel, power_unconstrained, p_tx_power_split);
}
bool nrf_802154_tx_power_split_pib_power_get(nrf_802154_tx_power_split_t * const p_split_power)
{
return constrain_split_and_convert_tx_power(nrf_802154_pib_channel_get(),
nrf_802154_pib_tx_power_get(),
p_split_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)
{
return constrain_split_and_convert_tx_power(channel,
nrf_802154_pib_tx_power_get(),
p_split_power);
}