Bluetooth: controller: enable dynamic TXP over LEGACY arch (#17731)
This commit targets solving issue #17731 over the Nordic LL LEGACY 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. Signed-off-by: Andrei Stoica <stoica.razvan.andrei@gmail.com>
This commit is contained in:
parent
abd1d047dd
commit
930d178c69
|
@ -14,6 +14,7 @@
|
|||
#include <drivers/entropy.h>
|
||||
#include <drivers/clock_control.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/hci_vs.h>
|
||||
#include <sys/util.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
|
@ -140,6 +141,10 @@ struct advertiser {
|
|||
struct radio_adv_data scan_data;
|
||||
|
||||
struct connection *conn;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
s8_t tx_pwr_lvl;
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
};
|
||||
|
||||
struct scanner {
|
||||
|
@ -174,6 +179,10 @@ struct scanner {
|
|||
u32_t ticks_conn_slot;
|
||||
struct connection *conn;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
s8_t tx_pwr_lvl;
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
|
||||
u32_t win_offset_us;
|
||||
};
|
||||
|
||||
|
@ -650,6 +659,11 @@ static void common_init(void)
|
|||
|
||||
/* allocate the rx queue */
|
||||
packet_rx_allocate(0xFF);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
_radio.advertiser.tx_pwr_lvl = RADIO_TXP_DEFAULT;
|
||||
_radio.scanner.tx_pwr_lvl = RADIO_TXP_DEFAULT;
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
}
|
||||
|
||||
static inline u32_t addr_us_get(u8_t phy)
|
||||
|
@ -6603,25 +6617,6 @@ again:
|
|||
}
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
|
||||
static void adv_scan_conn_configure(void)
|
||||
{
|
||||
radio_reset();
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
radio_isr_set(isr, NULL);
|
||||
}
|
||||
|
||||
static void adv_scan_configure(u8_t phy, u8_t flags)
|
||||
{
|
||||
u32_t aa = 0x8e89bed6;
|
||||
|
||||
adv_scan_conn_configure();
|
||||
radio_phy_set(phy, flags);
|
||||
radio_aa_set((u8_t *)&aa);
|
||||
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, (phy << 1));
|
||||
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
|
||||
0x555555);
|
||||
}
|
||||
|
||||
void radio_event_adv_prepare(u32_t ticks_at_expire, u32_t remainder,
|
||||
u16_t lazy, void *context)
|
||||
{
|
||||
|
@ -6722,6 +6717,7 @@ static void event_adv(u32_t ticks_at_expire, u32_t remainder,
|
|||
u16_t lazy, void *context)
|
||||
{
|
||||
u32_t remainder_us;
|
||||
u32_t aa = 0x8e89bed6;
|
||||
|
||||
ARG_UNUSED(remainder);
|
||||
ARG_UNUSED(lazy);
|
||||
|
@ -6742,13 +6738,29 @@ static void event_adv(u32_t ticks_at_expire, u32_t remainder,
|
|||
_radio.ticker_id_event = RADIO_TICKER_ID_ADV;
|
||||
_radio.ticks_anchor = ticks_at_expire;
|
||||
|
||||
radio_reset();
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
radio_tx_power_set(_radio.advertiser.tx_pwr_lvl);
|
||||
#else
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
radio_isr_set(isr, NULL);
|
||||
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
/* TODO: if coded we use S8? */
|
||||
adv_scan_configure(_radio.advertiser.phy_p, 1);
|
||||
radio_phy_set(_radio.advertiser.phy_p, 1);
|
||||
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX,
|
||||
(_radio.advertiser.phy_p << 1));
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
adv_scan_configure(0, 0);
|
||||
radio_phy_set(0, 0);
|
||||
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, 0);
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
radio_aa_set((u8_t *)&aa);
|
||||
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
|
||||
0x555555);
|
||||
|
||||
_radio.advertiser.chan_map_current = _radio.advertiser.chan_map;
|
||||
adv_setup();
|
||||
|
||||
|
@ -7137,6 +7149,7 @@ static void event_scan(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
|
|||
{
|
||||
u32_t remainder_us;
|
||||
u32_t ret;
|
||||
u32_t aa = 0x8e89bed6;
|
||||
|
||||
ARG_UNUSED(remainder);
|
||||
ARG_UNUSED(lazy);
|
||||
|
@ -7157,12 +7170,29 @@ static void event_scan(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
|
|||
_radio.ticks_anchor = ticks_at_expire;
|
||||
_radio.scanner.state = 0U;
|
||||
|
||||
radio_reset();
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
radio_tx_power_set(_radio.scanner.tx_pwr_lvl);
|
||||
#else
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
radio_isr_set(isr, NULL);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
adv_scan_configure(_radio.scanner.phy, 1); /* if coded then use S8. */
|
||||
/* if coded then use S8. */
|
||||
radio_phy_set(_radio.scanner.phy, 1);
|
||||
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX,
|
||||
(_radio.scanner.phy << 1));
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
adv_scan_configure(0, 0);
|
||||
radio_phy_set(0, 0);
|
||||
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, 0);
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
radio_aa_set((u8_t *)&aa);
|
||||
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
|
||||
0x555555);
|
||||
|
||||
|
||||
chan_set(37 + _radio.scanner.chan++);
|
||||
if (_radio.scanner.chan == 3) {
|
||||
_radio.scanner.chan = 0U;
|
||||
|
@ -9137,7 +9167,13 @@ event_connection_prepare_skip:
|
|||
|
||||
static void connection_configure(struct connection *conn)
|
||||
{
|
||||
adv_scan_conn_configure();
|
||||
radio_reset();
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
radio_tx_power_set(conn->tx_pwr_lvl);
|
||||
#else
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
radio_isr_set(isr, NULL);
|
||||
radio_aa_set(conn->access_addr);
|
||||
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
|
||||
(((u32_t)conn->crc_init[2] << 16) |
|
||||
|
@ -11526,6 +11562,10 @@ u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
|
|||
conn->rssi_sample_count = 0U;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
conn->tx_pwr_lvl = RADIO_TXP_DEFAULT;
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
|
||||
/* wait for stable 32KHz clock */
|
||||
k32src_wait();
|
||||
|
||||
|
@ -12073,6 +12113,10 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
|
|||
conn->rssi_sample_count = 0U;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
conn->tx_pwr_lvl = RADIO_TXP_DEFAULT;
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
|
||||
/* wait for stable 32KHz clock */
|
||||
k32src_wait();
|
||||
|
||||
|
@ -12419,25 +12463,6 @@ u8_t ll_terminate_ind_send(u16_t handle, u8_t reason)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u8_t ll_tx_pwr_lvl_get(u16_t handle, u8_t type, s8_t *tx_pwr_lvl)
|
||||
{
|
||||
struct connection *conn;
|
||||
|
||||
conn = connection_get(handle);
|
||||
if (!conn) {
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
/*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;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
|
||||
u8_t ll_rssi_get(u16_t handle, u8_t *rssi)
|
||||
{
|
||||
|
@ -12606,6 +12631,125 @@ u8_t ll_phy_req_send(u16_t handle, u8_t tx, u8_t flags, u8_t rx)
|
|||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
|
||||
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): {
|
||||
/* Unique global advertiser as part of ctrl */
|
||||
*tx_pwr_lvl = _radio.advertiser.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): {
|
||||
/* Unique global scanner as part of ctrl */
|
||||
*tx_pwr_lvl = _radio.scanner.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 connection *conn;
|
||||
|
||||
conn = connection_get(handle);
|
||||
if (!conn) {
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
if (type) {
|
||||
/* Level desired is maximum available */
|
||||
*tx_pwr_lvl = radio_tx_power_max_get();
|
||||
} else {
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
/* Current level is requested */
|
||||
*tx_pwr_lvl = conn->tx_pwr_lvl;
|
||||
#else
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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): {
|
||||
/* Unique global advertiser as part of ctrl */
|
||||
_radio.advertiser.tx_pwr_lvl = *tx_pwr_lvl;
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_BT_BROADCASTER */
|
||||
#if defined(CONFIG_BT_OBSERVER)
|
||||
case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
|
||||
/* Unique global scanner as part of ctrl */
|
||||
_radio.scanner.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 connection *conn;
|
||||
|
||||
conn = connection_get(handle);
|
||||
if (!conn) {
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
conn->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;
|
||||
}
|
||||
|
||||
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 u8_t tx_cmplt_get(u16_t *handle, u8_t *first, u8_t last)
|
||||
{
|
||||
u8_t _first;
|
||||
|
|
|
@ -332,6 +332,10 @@ struct connection {
|
|||
u8_t rssi_reported;
|
||||
u8_t rssi_sample_count;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
s8_t tx_pwr_lvl;
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
};
|
||||
#define CONNECTION_T_SIZE MROUND(sizeof(struct connection))
|
||||
|
||||
|
|
Loading…
Reference in a new issue