Bluetooth: controller: enable dynamic TXP over LL_SPLIT arch (#17731)

This commit targets solving issue #17731 over the LL_SW_SPLIT
arch of the BLE stack in Zephyr. This functionality is exposed
to the user as HCI Zephyr Command extensions

- BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL
- BT_HCI_OP_VS_READ_TX_POWER_LEVEL

which enable Tx power read/write operations within BLE radio events
on a per role/connection basis.

The functionality is enabled upon the Kconfig advanced configuration
triggered by

- BT_CTLR_TX_PWR_DYNAMIC_CONTROL

depending on the enablement of Zephyr HCI vendor-specific command
extensions.

Necessary low-level radio HAL functionality and power definitions
are also supplied to address the high-level functionality of
controlling the Tx power.

Signed-off-by: Andrei Stoica <stoica.razvan.andrei@gmail.com>
This commit is contained in:
Andrei Stoica 2019-10-22 13:13:24 +02:00 committed by Carles Cufí
commit abd1d047dd
28 changed files with 776 additions and 29 deletions

View file

@ -225,11 +225,57 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
return RADIO_TXPOWER_TXPOWER_Pos3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg30dBm) {
return RADIO_TXPOWER_TXPOWER_Neg30dBm;
}
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
ARG_UNUSED(flags);

View file

@ -130,6 +130,37 @@ struct bt_hci_cp_vs_set_scan_req_reports {
u8_t enable;
} __packed;
#define BT_HCI_VS_LL_HANDLE_TYPE_ADV 0x00
#define BT_HCI_VS_LL_HANDLE_TYPE_SCAN 0x01
#define BT_HCI_VS_LL_HANDLE_TYPE_CONN 0x02
#define BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF 0x7F
#define BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000e)
struct bt_hci_cp_vs_write_tx_power_level {
u8_t handle_type;
u16_t handle;
s8_t tx_power_level;
} __packed;
struct bt_hci_rp_vs_write_tx_power_level {
u8_t status;
u8_t handle_type;
u16_t handle;
s8_t selected_tx_power;
} __packed;
#define BT_HCI_OP_VS_READ_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000f)
struct bt_hci_cp_vs_read_tx_power_level {
u8_t handle_type;
u16_t handle;
} __packed;
struct bt_hci_rp_vs_read_tx_power_level {
u8_t status;
u8_t handle_type;
u16_t handle;
s8_t tx_power_level;
} __packed;
/* Events */
struct bt_hci_evt_vs {

View file

@ -289,6 +289,14 @@ config BT_CTLR_TX_PWR_MINUS_40
endchoice
config BT_CTLR_TX_PWR_DYNAMIC_CONTROL
bool "Tx Power Dynamic Control"
depends on BT_HCI_VS_EXT
help
Enable dynamic control of Tx power per role/connection.
Provides HCI VS commands to set and get the current Tx
power on an individual role/connection basis.
config BT_CTLR_SETTINGS
bool "Settings System"
depends on BT_SETTINGS

View file

@ -449,7 +449,8 @@ static void read_tx_power_level(struct net_buf *buf, struct net_buf **evt)
rp = hci_cmd_complete(evt, sizeof(*rp));
status = ll_tx_pwr_lvl_get(handle, type, &rp->tx_power_level);
status = ll_tx_pwr_lvl_get(BT_HCI_VS_LL_HANDLE_TYPE_CONN,
handle, type, &rp->tx_power_level);
rp->status = status;
rp->handle = sys_cpu_to_le16(handle);
@ -1866,6 +1867,10 @@ static void vs_read_supported_commands(struct net_buf *buf,
rp->commands[0] |= BIT(5) | BIT(7);
/* Read Static Addresses, Read Key Hierarchy Roots */
rp->commands[1] |= BIT(0) | BIT(1);
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
/* Write Tx Power, Read Tx Power */
rp->commands[1] |= BIT(5) | BIT(6);
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
#endif /* CONFIG_BT_HCI_VS_EXT */
}
@ -1998,6 +2003,49 @@ static void vs_read_key_hierarchy_roots(struct net_buf *buf,
(void)memset(rp->er, 0x00, sizeof(rp->er));
#endif /* CONFIG_SOC_FAMILY_NRF */
}
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
static void vs_write_tx_power_level(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_vs_write_tx_power_level *cmd = (void *)buf->data;
struct bt_hci_rp_vs_write_tx_power_level *rp;
u8_t handle_type;
u16_t handle;
u8_t status;
handle_type = cmd->handle_type;
handle = sys_le16_to_cpu(cmd->handle);
rp = hci_cmd_complete(evt, sizeof(*rp));
rp->selected_tx_power = cmd->tx_power_level;
status = ll_tx_pwr_lvl_set(handle_type, handle, &rp->selected_tx_power);
rp->status = status;
rp->handle_type = handle_type;
rp->handle = sys_cpu_to_le16(handle);
}
static void vs_read_tx_power_level(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_vs_read_tx_power_level *cmd = (void *)buf->data;
struct bt_hci_rp_vs_read_tx_power_level *rp;
u8_t handle_type;
u16_t handle;
u8_t status;
handle_type = cmd->handle_type;
handle = sys_le16_to_cpu(cmd->handle);
rp = hci_cmd_complete(evt, sizeof(*rp));
status = ll_tx_pwr_lvl_get(handle_type, handle, 0, &rp->tx_power_level);
rp->status = status;
rp->handle_type = handle_type;
rp->handle = sys_cpu_to_le16(handle);
}
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
#endif /* CONFIG_BT_HCI_VS_EXT */
#if defined(CONFIG_BT_HCI_MESH_EXT)
@ -2184,6 +2232,16 @@ int hci_vendor_cmd_handle_common(u16_t ocf, struct net_buf *cmd,
case BT_OCF(BT_HCI_OP_VS_READ_KEY_HIERARCHY_ROOTS):
vs_read_key_hierarchy_roots(cmd, evt);
break;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
case BT_OCF(BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL):
vs_write_tx_power_level(cmd, evt);
break;
case BT_OCF(BT_HCI_OP_VS_READ_TX_POWER_LEVEL):
vs_read_tx_power_level(cmd, evt);
break;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
#endif /* CONFIG_BT_HCI_VS_EXT */
#if defined(CONFIG_BT_HCI_MESH_EXT)

View file

@ -81,8 +81,11 @@ u8_t ll_feature_req_send(u16_t handle);
u8_t ll_version_ind_send(u16_t handle);
u8_t ll_terminate_ind_send(u16_t handle, u8_t reason);
u8_t ll_rssi_get(u16_t handle, u8_t *rssi);
u8_t ll_tx_pwr_lvl_get(u16_t handle, u8_t type, s8_t *tx_pwr_lvl);
u8_t ll_tx_pwr_lvl_get(u8_t handle_type,
u16_t handle, u8_t type, s8_t *tx_pwr_lvl);
void ll_tx_pwr_get(s8_t *min, s8_t *max);
u8_t ll_tx_pwr_lvl_set(u8_t handle_type,
u16_t handle, s8_t *tx_pwr_lvl);
u8_t ll_apto_get(u16_t handle, u16_t *apto);
u8_t ll_apto_set(u16_t handle, u16_t apto);

View file

@ -9,6 +9,7 @@
#include <toolchain.h>
#include <soc.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_vs.h>
#include "hal/ccm.h"
#include "hal/radio.h"
@ -17,36 +18,194 @@
#include "pdu.h"
#include "ll.h"
#include "lll.h"
#include "lll_conn.h"
#include "ull_conn_internal.h"
#if defined(CONFIG_BT_LL_SW_SPLIT)
u8_t ll_tx_pwr_lvl_get(u16_t handle, u8_t type, s8_t *tx_pwr_lvl)
{
struct ll_conn *conn;
#include "util/util.h"
conn = ll_connected_get(handle);
if (!conn) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
#include "lll_scan.h"
#include "ull_scan_types.h"
#include "ull_scan_internal.h"
#include "lll_adv.h"
#include "ull_adv_types.h"
#include "ull_adv_internal.h"
#include "lll_conn.h"
#include "ull_conn_types.h"
#include "ull_conn_internal.h"
u8_t ll_tx_pwr_lvl_get(u8_t handle_type,
u16_t handle, u8_t type, s8_t *tx_pwr_lvl)
{
switch (handle_type) {
#if defined(CONFIG_BT_BROADCASTER) &&\
defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): {
struct ll_adv_set *adv;
#if !defined(CONFIG_BT_CTLR_ADV_EXT)
/* Ignore handle if AE not enabled */
handle = 0;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
/* Allow the app to get Tx power
* when advertising is off
*/
adv = ull_adv_set_get(handle);
if (!adv) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
*tx_pwr_lvl = adv->lll.tx_pwr_lvl;
break;
}
#endif /* CONFIG_BT_BROADCASTER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
#if defined(CONFIG_BT_OBSERVER) &&\
defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
struct ll_scan_set *scan;
/* Ignore handle in case of scanner
* as for mesh extensions and scanning
* sets this control is handled
* at a lower-level in the stack.
*/
handle = 0;
/* Allow the app to get Tx power
* when scanning is off
*/
scan = ull_scan_set_get(handle);
if (!scan) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
*tx_pwr_lvl = scan->lll.tx_pwr_lvl;
break;
}
#endif /* CONFIG_BT_OBSERVER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL*/
#if defined(CONFIG_BT_CONN)
case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): {
struct ll_conn *conn;
conn = ll_connected_get(handle);
if (!conn) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
if (type) {
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
/* Level desired is maximum available */
*tx_pwr_lvl = lll_radio_tx_pwr_max_get();
#else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
/* Return default if not multiple TXP */
*tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
} else {
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
/* Current level is requested */
*tx_pwr_lvl = conn->lll.tx_pwr_lvl;
#else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
/* Return default if not multiple TXP */
*tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
}
break;
}
#endif /* CONFIG_BT_CONN */
default: {
return BT_HCI_ERR_UNKNOWN_CMD;
}
}
/* TODO: check type here for current or maximum */
/* TODO: Support TX Power Level other than default when dynamic
* updates is implemented.
*/
*tx_pwr_lvl = RADIO_TXP_DEFAULT;
return 0;
return BT_HCI_ERR_SUCCESS;
}
#endif
u8_t ll_tx_pwr_lvl_set(u8_t handle_type, u16_t handle,
s8_t *tx_pwr_lvl)
{
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
if (*tx_pwr_lvl == BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF) {
/* If no preference selected, then use default Tx power */
*tx_pwr_lvl = RADIO_TXP_DEFAULT;
}
/**
* Check that desired Tx power matches the achievable transceiver
* Tx power capabilities by flooring - if selected power matches than
* is used, otherwise next smaller power available is used.
*/
*tx_pwr_lvl = lll_radio_tx_pwr_floor(*tx_pwr_lvl);
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
switch (handle_type) {
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
#if defined(CONFIG_BT_BROADCASTER)
case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): {
struct ll_adv_set *adv;
#if !defined(CONFIG_BT_CTLR_ADV_EXT)
/* Ignore handle if AE not enabled */
handle = 0;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
/* Allow the app to set Tx power
* prior to advertising
*/
adv = ull_adv_set_get(handle);
if (!adv) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
adv->lll.tx_pwr_lvl = *tx_pwr_lvl;
break;
}
#endif /* CONFIG_BT_BROADCASTER */
#if defined(CONFIG_BT_OBSERVER)
case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
struct ll_scan_set *scan;
/* Ignore handle in case of scanner
* as for mesh extensions and scanning
* sets this control is handled
* at a lower-level in the stack.
*/
handle = 0;
/* Allow the app to set Tx power
* prior to scanning
*/
scan = ull_scan_set_get(handle);
if (!scan) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
scan->lll.tx_pwr_lvl = *tx_pwr_lvl;
break;
}
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CONN)
case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): {
struct ll_conn *conn;
conn = ll_connected_get(handle);
if (!conn) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
conn->lll.tx_pwr_lvl = *tx_pwr_lvl;
break;
}
#endif /* CONFIG_BT_CONN */
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
default: {
return BT_HCI_ERR_UNKNOWN_CMD;
}
}
return BT_HCI_ERR_SUCCESS;
}
#endif /* CONFIG_BT_LL_SW_SPLIT */
void ll_tx_pwr_get(s8_t *min, s8_t *max)
{
/* TODO: Support TX Power Level other than default when dynamic
* updates is implemented.
*/
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
*min = lll_radio_tx_pwr_min_get();
*max = lll_radio_tx_pwr_max_get();
#else
*min = RADIO_TXP_DEFAULT;
*max = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
}

View file

@ -300,6 +300,9 @@ int lll_prepare(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
void lll_resume(void *param);
void lll_disable(void *param);
u32_t lll_radio_is_idle(void);
s8_t lll_radio_tx_pwr_min_get(void);
s8_t lll_radio_tx_pwr_max_get(void);
s8_t lll_radio_tx_pwr_floor(s8_t tx_pwr_lvl);
int ull_prepare_enqueue(lll_is_abort_cb_t is_abort_cb,
lll_abort_cb_t abort_cb,

View file

@ -112,10 +112,15 @@ struct lll_conn {
#if defined(CONFIG_BT_CTLR_CONN_META)
struct lll_conn_meta conn_meta;
#endif /* CONFIG_BT_CTLR_CONN_META */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
s8_t tx_pwr_lvl;
#endif
};
int lll_conn_init(void);
int lll_conn_reset(void);
u8_t lll_conn_sca_local_get(void);
u32_t lll_conn_ppm_local_get(void);
u32_t lll_conn_ppm_get(u8_t sca);

View file

@ -140,10 +140,10 @@ void radio_phy_set(u8_t phy, u8_t flags)
#endif /* CONFIG_BT_CTLR_RADIO_ENABLE_FAST */
}
void radio_tx_power_set(u32_t power)
void radio_tx_power_set(s8_t power)
{
/* NOTE: valid value range is passed by Kconfig define. */
NRF_RADIO->TXPOWER = power;
NRF_RADIO->TXPOWER = (u32_t)power;
}
void radio_tx_power_max_set(void)
@ -151,6 +151,21 @@ void radio_tx_power_max_set(void)
NRF_RADIO->TXPOWER = hal_radio_tx_power_max_get();
}
s8_t radio_tx_power_min_get(void)
{
return (s8_t)hal_radio_tx_power_min_get();
}
s8_t radio_tx_power_max_get(void)
{
return (s8_t)hal_radio_tx_power_max_get();
}
s8_t radio_tx_power_floor(s8_t power)
{
return (s8_t)hal_radio_tx_power_floor(power);
}
void radio_freq_chan_set(u32_t chan)
{
NRF_RADIO->FREQUENCY = chan;

View file

@ -13,8 +13,11 @@ void radio_isr_set(radio_isr_cb_t cb, void *param);
void radio_setup(void);
void radio_reset(void);
void radio_phy_set(u8_t phy, u8_t flags);
void radio_tx_power_set(u32_t power);
void radio_tx_power_set(s8_t power);
void radio_tx_power_max_set(void);
s8_t radio_tx_power_min_get(void);
s8_t radio_tx_power_max_get(void);
s8_t radio_tx_power_floor(s8_t power);
void radio_freq_chan_set(u32_t chan);
void radio_whiten_iv_set(u32_t iv);
void radio_aa_set(u8_t *aa);

View file

@ -50,11 +50,50 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg30dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
ARG_UNUSED(phy);

View file

@ -256,11 +256,54 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
return RADIO_TXPOWER_TXPOWER_Pos3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
ARG_UNUSED(flags);

View file

@ -450,11 +450,54 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
return RADIO_TXPOWER_TXPOWER_Pos3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
switch (phy) {

View file

@ -260,11 +260,54 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
return RADIO_TXPOWER_TXPOWER_Pos3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
ARG_UNUSED(flags);

View file

@ -430,11 +430,74 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos8dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos8dBm) {
return RADIO_TXPOWER_TXPOWER_Pos8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos7dBm) {
return RADIO_TXPOWER_TXPOWER_Pos7dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos6dBm) {
return RADIO_TXPOWER_TXPOWER_Pos6dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos5dBm) {
return RADIO_TXPOWER_TXPOWER_Pos5dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
return RADIO_TXPOWER_TXPOWER_Pos3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos2dBm) {
return RADIO_TXPOWER_TXPOWER_Pos2dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
switch (phy) {

View file

@ -451,11 +451,74 @@ static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
return mode;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_max_get(void)
{
return RADIO_TXPOWER_TXPOWER_Pos8dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos8dBm) {
return RADIO_TXPOWER_TXPOWER_Pos8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos7dBm) {
return RADIO_TXPOWER_TXPOWER_Pos7dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos6dBm) {
return RADIO_TXPOWER_TXPOWER_Pos6dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos5dBm) {
return RADIO_TXPOWER_TXPOWER_Pos5dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
return RADIO_TXPOWER_TXPOWER_Pos3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Pos2dBm) {
return RADIO_TXPOWER_TXPOWER_Pos2dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
switch (phy) {

View file

@ -404,6 +404,65 @@ static inline u32_t hal_radio_tx_power_max_get(void)
return RADIO_TXPOWER_TXPOWER_0dBm;
}
static inline u32_t hal_radio_tx_power_min_get(void)
{
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_power_floor(s8_t tx_power_lvl)
{
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
return RADIO_TXPOWER_TXPOWER_0dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) {
return RADIO_TXPOWER_TXPOWER_Neg1dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) {
return RADIO_TXPOWER_TXPOWER_Neg2dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) {
return RADIO_TXPOWER_TXPOWER_Neg3dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
return RADIO_TXPOWER_TXPOWER_Neg4dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) {
return RADIO_TXPOWER_TXPOWER_Neg5dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) {
return RADIO_TXPOWER_TXPOWER_Neg6dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) {
return RADIO_TXPOWER_TXPOWER_Neg7dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
return RADIO_TXPOWER_TXPOWER_Neg8dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
return RADIO_TXPOWER_TXPOWER_Neg12dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
return RADIO_TXPOWER_TXPOWER_Neg16dBm;
}
if (tx_power_lvl >= (s8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
return RADIO_TXPOWER_TXPOWER_Neg20dBm;
}
/* Note: The -30 dBm power level is deprecated so ignore it! */
return RADIO_TXPOWER_TXPOWER_Neg40dBm;
}
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
{
switch (phy) {

View file

@ -432,6 +432,20 @@ u32_t lll_radio_is_idle(void)
return radio_is_idle();
}
s8_t lll_radio_tx_pwr_min_get(void)
{
return radio_tx_power_min_get();
}
s8_t lll_radio_tx_pwr_max_get(void)
{
return radio_tx_power_max_get();
}
s8_t lll_radio_tx_pwr_floor(s8_t tx_pwr_lvl)
{
return radio_tx_power_floor(tx_pwr_lvl);
}
static int init_reset(void)
{

View file

@ -144,8 +144,11 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
}
radio_reset();
/* TODO: other Tx Power settings */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
radio_tx_power_set(lll->tx_pwr_lvl);
#else
radio_tx_power_set(RADIO_TXP_DEFAULT);
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
#if defined(CONFIG_BT_CTLR_ADV_EXT)
/* TODO: if coded we use S8? */

View file

@ -40,6 +40,10 @@ struct lll_adv {
struct lll_adv_pdu adv_data;
struct lll_adv_pdu scan_rsp;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
s8_t tx_pwr_lvl;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
};
int lll_adv_init(void);

View file

@ -139,8 +139,12 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
/* Start setting up of Radio h/w */
radio_reset();
/* TODO: other Tx Power settings */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
radio_tx_power_set(lll->tx_pwr_lvl);
#else
radio_tx_power_set(RADIO_TXP_DEFAULT);
#endif
radio_aa_set(lll->access_addr);
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
(((u32_t)lll->crc_init[2] << 16) |

View file

@ -147,8 +147,11 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
LL_ASSERT(node_rx);
radio_reset();
/* TODO: other Tx Power settings */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
radio_tx_power_set(lll->tx_pwr_lvl);
#else
radio_tx_power_set(RADIO_TXP_DEFAULT);
#endif
#if defined(CONFIG_BT_CTLR_ADV_EXT)
/* TODO: if coded we use S8? */

View file

@ -37,6 +37,10 @@ struct lll_scan {
u16_t interval;
u32_t ticks_window;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
s8_t tx_pwr_lvl;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
};
int lll_scan_init(void);

View file

@ -160,8 +160,11 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
/* Start setting up Radio h/w */
radio_reset();
/* TODO: other Tx Power settings */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
radio_tx_power_set(lll->tx_pwr_lvl);
#else
radio_tx_power_set(RADIO_TXP_DEFAULT);
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
lll_conn_rx_pkt_set(lll);

View file

@ -12,6 +12,7 @@
#include "hal/ccm.h"
#include "hal/ticker.h"
#include "hal/radio.h"
#include "util/util.h"
#include "util/mem.h"
@ -446,6 +447,9 @@ u8_t ll_adv_enable(u8_t enable)
}
lll = &adv->lll;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
pdu_adv = lll_adv_data_peek(lll);
if (pdu_adv->tx_addr) {
@ -597,6 +601,10 @@ u8_t ll_adv_enable(u8_t enable)
conn_lll->rssi_sample_count = 0;
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
conn_lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
/* FIXME: BEGIN: Move to ULL? */
conn_lll->role = 1;
conn_lll->data_chan_sel = 0;

View file

@ -14,6 +14,8 @@
#include "hal/ticker.h"
#include "hal/ccm.h"
#include "hal/radio.h"
#include "ticker/ticker.h"
#include "pdu.h"
@ -142,6 +144,10 @@ u8_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
conn_lll->rssi_sample_count = 0;
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
conn_lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
/* FIXME: BEGIN: Move to ULL? */
conn_lll->latency_prepare = 0;
conn_lll->latency_event = 0;
@ -481,6 +487,10 @@ void ull_master_setup(memq_link_t *link, struct node_rx_hdr *rx,
lll->handle = ll_conn_handle_get(conn);
rx->handle = lll->handle;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
/* Use Channel Selection Algorithm #2 if peer too supports it */
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
struct node_rx_pdu *rx_csa;

View file

@ -10,6 +10,7 @@
#include "hal/ccm.h"
#include "hal/ticker.h"
#include "hal/radio.h"
#include "util/util.h"
#include "util/mem.h"
@ -175,6 +176,10 @@ u8_t ull_scan_enable(struct ll_scan_set *scan)
lll->init_addr_type = scan->own_addr_type;
ll_addr_get(lll->init_addr_type, lll->init_addr);
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
ull_hdr_init(&scan->ull);
lll_hdr_init(lll, scan);

View file

@ -14,6 +14,7 @@
#include "hal/ticker.h"
#include "hal/ccm.h"
#include "hal/radio.h"
#include "ticker/ticker.h"
@ -167,6 +168,10 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
lll->handle = ll_conn_handle_get(conn);
rx->handle = lll->handle;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
/* Use Channel Selection Algorithm #2 if peer too supports it */
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
struct node_rx_pdu *rx_csa;