diff --git a/components/bt/include/esp32s31/include/esp_bt.h b/components/bt/include/esp32s31/include/esp_bt.h index 1634f33956c..3d6b982e110 100644 --- a/components/bt/include/esp32s31/include/esp_bt.h +++ b/components/bt/include/esp32s31/include/esp_bt.h @@ -695,6 +695,23 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode); */ esp_err_t esp_bt_controller_disable(void); +#if (UC_BT_CTRL_BR_EDR_IS_ENABLE) +/** + * @brief Get the BR/EDR TX power range (in dBm) actually supported by this chip. + * + * The TX power range configurable in menuconfig represents the maximum possible range. + * The values that can actually be applied depend on the chip and are reported by this function. + * + * @param[out] min_power : pointer to store the minimum supported TX power in dBm + * @param[out] max_power : pointer to store the maximum supported TX power in dBm + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_NOT_SUPPORTED: not supported + */ +esp_err_t esp_bredr_tx_power_range_get(int8_t *min_power, int8_t *max_power); +#endif // (UC_BT_CTRL_BR_EDR_IS_ENABLE) + /** @brief esp_vhci_host_callback * used for vhci call host function to notify what host need to do */ diff --git a/components/bt/porting_btdm/controller/bredr/Kconfig.in b/components/bt/porting_btdm/controller/bredr/Kconfig.in index 52cceb818b1..092df7c0bd6 100644 --- a/components/bt/porting_btdm/controller/bredr/Kconfig.in +++ b/components/bt/porting_btdm/controller/bredr/Kconfig.in @@ -223,43 +223,65 @@ menu "TX Power Level settings" config BT_CTRL_BR_EDR_TX_PWR_ACL_MIN int "Default minimum TX power level for ACL" default -13 - range -24 12 + range -24 20 help Minimum BR/EDR transmission power level for ACL. + The transmission power for an ACL connection link will be affected by the following factors: + It must fall within the range of [`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`] + The initial TX power level for an ACL link is inherited from + `BT_CTRL_BR_EDR_TX_PWR_PAGE` (for Central) and `BT_CTRL_BR_EDR_TX_PWR_PSCAN` (for Peripheral). + If the power is lower than BT_CTRL_BR_EDR_TX_PWR_ACL_MIN, BT_CTRL_BR_EDR_TX_PWR_ACL_MIN will be used. + It can be adjusted in response to LMP power control request PDUs from the peer device. + config BT_CTRL_BR_EDR_TX_PWR_ACL_MAX int "Default maximum TX power level for ACL" default 4 - range -24 12 + range -24 20 help Maximum BR/EDR transmission power level for ACL. + The transmission power for an ACL connection link will be affected by the following factors: + It must fall within the range of [`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`] + The initial TX power level for an ACL link is inherited from + `BT_CTRL_BR_EDR_TX_PWR_PAGE` (for Central) and `BT_CTRL_BR_EDR_TX_PWR_PSCAN` (for Peripheral). + If the power is higher than BT_CTRL_BR_EDR_TX_PWR_ACL_MAX, BT_CTRL_BR_EDR_TX_PWR_ACL_MAX will be used. + It can be adjusted in response to LMP power control request PDUs from the peer device. + config BT_CTRL_BR_EDR_TX_PWR_APB int "Default TX power level for APB" depends on BT_CTRL_BR_EDR_APB_EN default 4 - range -24 12 + range -24 20 help BR/EDR transmission power level for APB. config BT_CTRL_BR_EDR_TX_PWR_PAGE int "Default TX power level for Page" default 4 - range -24 12 + range -24 20 help BR/EDR transmission power level for Page. + `BT_CTRL_BR_EDR_TX_PWR_PAGE` is recommended to fall within the ACL transmission power range + [`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`], because the Bluetooth controller + will try to use it as the initial TX power on the ACL link upon connection establishment from page + substate. config BT_CTRL_BR_EDR_TX_PWR_PSCAN int "Default TX power level for Page Scan" default 4 - range -24 12 + range -24 20 help BR/EDR transmission power level for Page Scan. + `BT_CTRL_BR_EDR_TX_PWR_PSCAN` is recommended to fall within the ACL transmission power range + [`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`], because the Bluetooth controller + will try to use it as the initial TX power on the ACL link upon connection establishment from + page scan substate. config BT_CTRL_BR_EDR_TX_PWR_ISCAN int "Default TX power level for Inquiry Scan" default 4 - range -24 12 + range -24 20 help BR/EDR transmission power level for Inquiry Scan. @@ -267,7 +289,7 @@ menu "TX Power Level settings" int "Default TX power level for CPB" depends on BT_CTRL_BR_EDR_CPB_TX_EN default 4 - range -24 12 + range -24 20 help BR/EDR transmission power level for CPB. @@ -275,7 +297,7 @@ menu "TX Power Level settings" int "Default TX power level for Synchronization Train" depends on BT_CTRL_BR_EDR_CPB_TX_EN default 4 - range -24 12 + range -24 20 help BR/EDR transmission power level for Synchronization Train. endmenu diff --git a/components/bt/porting_btdm/controller/bredr/src/bredr.c b/components/bt/porting_btdm/controller/bredr/src/bredr.c index b8d93ef210d..e8b3b3dca10 100644 --- a/components/bt/porting_btdm/controller/bredr/src/bredr.c +++ b/components/bt/porting_btdm/controller/bredr/src/bredr.c @@ -52,6 +52,7 @@ #include "btdm_osal.h" #include "btdm_endian.h" +#include "btdm_external.h" #if CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS #include "psa/crypto.h" #endif @@ -784,6 +785,78 @@ static int bredr_log_printf(const char *fmt, ...) return len; } +esp_err_t esp_bredr_tx_power_range_get(int8_t *min_power, int8_t *max_power) +{ + if (min_power == NULL && max_power == NULL) { + return ESP_ERR_INVALID_ARG; + } + + uint8_t pwr_tbl_sz = 0; + const int8_t *pwr_tbl = wr_btdm_external_bb_get_tx_pwr_table(&pwr_tbl_sz, TX_PWR_TABLE_MODEM_CFG_BREDR); + + if (pwr_tbl == NULL || pwr_tbl_sz == 0) { + return ESP_ERR_NOT_SUPPORTED; + } + + /* The power table is ordered from the lowest to the highest power level */ + if (min_power != NULL) { + *min_power = pwr_tbl[0]; + } + if (max_power != NULL) { + *max_power = pwr_tbl[pwr_tbl_sz - 1]; + } + + return ESP_OK; +} + +/* Check a single configured TX power value against [min_power, max_power]. */ +static bool bredr_check_tx_pwr(const char *name, int8_t value, int8_t min_power, int8_t max_power) +{ + if (value < min_power || value > max_power) { + ESP_LOGE(BREDR_LOG_TAG, "%s tx power %d dBm out of supported range [%d, %d] dBm", name, value, min_power, max_power); + return false; + } + return true; +} + +/* + * Validate the user-configured BR/EDR TX power values against the range actually supported by the chip. + * The menuconfig limits only describe the maximum possible range, but the achievable range can be narrower depending on the chip. + * Returns ESP_ERR_INVALID_ARG if any configured value is out of range so that controller init can be aborted. + */ +static esp_err_t bredr_validate_tx_pwr_cfg(const esp_bredr_controller_config_t *bredr_cfg) +{ + int8_t min_power = 0; + int8_t max_power = 0; + + esp_err_t ret = esp_bredr_tx_power_range_get(&min_power, &max_power); + if (ret != ESP_OK) { + ESP_LOGE(BREDR_LOG_TAG, "Failed to get TX power range, err 0x%x", ret); + return ret; + } + + bool valid = true; + valid &= bredr_check_tx_pwr("ACL min", bredr_cfg->acl_min_tx_pwr, min_power, max_power); + valid &= bredr_check_tx_pwr("ACL max", bredr_cfg->acl_max_tx_pwr, min_power, max_power); + valid &= bredr_check_tx_pwr("Page", bredr_cfg->page_tx_pwr, min_power, max_power); + valid &= bredr_check_tx_pwr("Page Scan", bredr_cfg->pscan_tx_pwr, min_power, max_power); + valid &= bredr_check_tx_pwr("Inquiry Scan", bredr_cfg->iscan_tx_pwr, min_power, max_power); +#if UC_BR_EDR_APB_EN + valid &= bredr_check_tx_pwr("APB", bredr_cfg->apb_tx_pwr, min_power, max_power); +#endif +#if UC_BR_EDR_CPB_TX_LINK_NB + valid &= bredr_check_tx_pwr("CPB", bredr_cfg->cpb_tx_pwr, min_power, max_power); + valid &= bredr_check_tx_pwr("Sync Train", bredr_cfg->strain_tx_pwr, min_power, max_power); +#endif + + if (bredr_cfg->acl_min_tx_pwr > bredr_cfg->acl_max_tx_pwr) { + ESP_LOGE(BREDR_LOG_TAG, "ACL min tx power %d dBm greater than max %d dBm", bredr_cfg->acl_min_tx_pwr, bredr_cfg->acl_max_tx_pwr); + valid = false; + } + + return valid ? ESP_OK : ESP_ERR_INVALID_ARG; +} + int esp_bredr_controller_init(esp_bt_controller_config_t *cfg) { int status; @@ -791,6 +864,11 @@ int esp_bredr_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGI(BREDR_LOG_TAG, "BT controller compile version [%s]", co_orca_get_git_version_str()); + err = bredr_validate_tx_pwr_cfg(&cfg->bredr); + if (err != ESP_OK) { + return err; + } + bredr_register_setup_callback(bredr_ctrl_setup_callback); bredr_register_ext_dep_callback(bredr_ctrl_ext_dep_callback); diff --git a/components/bt/porting_btdm/controller/btdm_common/include/btdm_external.h b/components/bt/porting_btdm/controller/btdm_common/include/btdm_external.h index 2044a0746e5..51b01be4379 100644 --- a/components/bt/porting_btdm/controller/btdm_common/include/btdm_external.h +++ b/components/bt/porting_btdm/controller/btdm_common/include/btdm_external.h @@ -19,6 +19,13 @@ extern "C" { #define btdm_external_bb_get_tx_pwr_table BTDM_EXTERNAL_WR_FUNC(btdm_external_bb_get_tx_pwr_table) +enum { + TX_PWR_TABLE_MODEM_CFG_BLE = 0, + TX_PWR_TABLE_MODEM_CFG_802154, + TX_PWR_TABLE_MODEM_CFG_BREDR, + TX_PWR_TABLE_MODEM_CFG_MAX, +}; + /* * Function declarations for BTDM EXTERNAL */ diff --git a/components/bt/porting_btdm/controller/btdm_common/src/btdm_external.c b/components/bt/porting_btdm/controller/btdm_common/src/btdm_external.c index 29bfb1da6cc..ee0cb0b6016 100644 --- a/components/bt/porting_btdm/controller/btdm_common/src/btdm_external.c +++ b/components/bt/porting_btdm/controller/btdm_common/src/btdm_external.c @@ -15,11 +15,12 @@ const int8_t * wr_btdm_external_bb_get_tx_pwr_table(uint8_t *length, uint8_t modem_cfg) { assert(length != NULL); - assert (modem_cfg <= 2); - // TODO: replace with bt_bb_tx_pwr_table_get when all the targets(h4, s31, etc) support this API - if (modem_cfg == 2) { // BREDR + assert (modem_cfg < TX_PWR_TABLE_MODEM_CFG_MAX); + + if (modem_cfg == TX_PWR_TABLE_MODEM_CFG_BREDR) { return bt_bb_tx_pwr_table_get(length, modem_cfg); } else { + // TODO: replace with bt_bb_tx_pwr_table_get when all the targets(h4, s31, etc) support this API return bt_bb_get_tx_pwr_table(length); } }