Fix incorrect TX power setting for advertising.

* Adds a new enum class to specify the tx power type to set (unused by non-esp devices).
* When all type is specified it is now ensured that all the tx power types are set to the specified level.
* Correctly sets the power level advertised for extended advertising with legacy pdu selected.
This commit is contained in:
sanastasiou 2025-01-04 10:37:26 -07:00 committed by h2zero
parent 3b019a0c9c
commit 765193f223
5 changed files with 78 additions and 37 deletions

View file

@ -110,7 +110,7 @@ bool NimBLEAdvertisementData::addTxPower() {
data[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1; data[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1;
data[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL; data[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL;
# ifndef CONFIG_IDF_TARGET_ESP32P4 # ifndef CONFIG_IDF_TARGET_ESP32P4
data[2] = NimBLEDevice::getPower(); data[2] = NimBLEDevice::getPower(NimBLETxPowerType::Advertise);
# else # else
data[2] = 0; data[2] = 0;
# endif # endif

View file

@ -464,7 +464,7 @@ bool NimBLEDevice::setPowerLevel(esp_power_level_t powerLevel, esp_ble_power_typ
* @param [in] dbm The power level to set in dBm. * @param [in] dbm The power level to set in dBm.
* @return True if the power level was set successfully. * @return True if the power level was set successfully.
*/ */
bool NimBLEDevice::setPower(int8_t dbm) { bool NimBLEDevice::setPower(int8_t dbm, NimBLETxPowerType type) {
# ifdef ESP_PLATFORM # ifdef ESP_PLATFORM
# ifdef CONFIG_IDF_TARGET_ESP32P4 # ifdef CONFIG_IDF_TARGET_ESP32P4
return false; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_set return false; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_set
@ -472,9 +472,25 @@ bool NimBLEDevice::setPower(int8_t dbm) {
if (dbm % 3 == 2) { if (dbm % 3 == 2) {
dbm++; // round up to the next multiple of 3 to be able to target 20dbm dbm++; // round up to the next multiple of 3 to be able to target 20dbm
} }
return setPowerLevel(static_cast<esp_power_level_t>(dbm / 3 + ESP_PWR_LVL_N0));
bool success = false;
esp_power_level_t espPwr = static_cast<esp_power_level_t>(dbm / 3 + ESP_PWR_LVL_N0);
if (type == NimBLETxPowerType::All) {
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_ADV);
success &= setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_SCAN);
success &= setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_DEFAULT);
} else if (type == NimBLETxPowerType::Advertise) {
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_ADV);
} else if (type == NimBLETxPowerType::Scan) {
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_SCAN);
} else if (type == NimBLETxPowerType::Connection) {
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_DEFAULT);
}
return success;
# endif # endif
# else # else
(void)type; // unused
NIMBLE_LOGD(LOG_TAG, ">> setPower: %d", dbm); NIMBLE_LOGD(LOG_TAG, ">> setPower: %d", dbm);
ble_hci_vs_set_tx_pwr_cp cmd{dbm}; ble_hci_vs_set_tx_pwr_cp cmd{dbm};
ble_hci_vs_set_tx_pwr_rp rsp{0}; ble_hci_vs_set_tx_pwr_rp rsp{0};
@ -493,12 +509,16 @@ bool NimBLEDevice::setPower(int8_t dbm) {
* @brief Get the transmission power. * @brief Get the transmission power.
* @return The power level currently used in dbm or 0xFF on error. * @return The power level currently used in dbm or 0xFF on error.
*/ */
int NimBLEDevice::getPower() { int NimBLEDevice::getPower(NimBLETxPowerType type) {
# ifdef ESP_PLATFORM # ifdef ESP_PLATFORM
# ifdef CONFIG_IDF_TARGET_ESP32P4 # ifdef CONFIG_IDF_TARGET_ESP32P4
return 0xFF; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_get return 0xFF; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_get
# else # else
int pwr = getPowerLevel(); esp_ble_power_type_t espPwr = type == NimBLETxPowerType::Advertise ? ESP_BLE_PWR_TYPE_ADV
: type == NimBLETxPowerType::Scan ? ESP_BLE_PWR_TYPE_SCAN
: ESP_BLE_PWR_TYPE_DEFAULT;
int pwr = getPowerLevel(espPwr);
if (pwr < 0) { if (pwr < 0) {
NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_get failed rc=%d", pwr); NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_get failed rc=%d", pwr);
return 0xFF; return 0xFF;
@ -515,6 +535,7 @@ int NimBLEDevice::getPower() {
return 0; return 0;
# endif # endif
# else # else
(void)type; // unused
return ble_phy_txpwr_get(); return ble_phy_txpwr_get();
# endif # endif
} // getPower } // getPower

View file

@ -101,6 +101,13 @@ class NimBLEAddress;
# define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS # define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS
# endif # endif
enum class NimBLETxPowerType {
All = 0,
Advertise = 1,
Scan = 2,
Connection = 3
};
typedef int (*gap_event_handler)(ble_gap_event* event, void* arg); typedef int (*gap_event_handler)(ble_gap_event* event, void* arg);
/** /**
@ -138,8 +145,8 @@ class NimBLEDevice {
static void onReset(int reason); static void onReset(int reason);
static void onSync(void); static void onSync(void);
static void host_task(void* param); static void host_task(void* param);
static int getPower(); static int getPower(NimBLETxPowerType type = NimBLETxPowerType::All);
static bool setPower(int8_t dbm); static bool setPower(int8_t dbm, NimBLETxPowerType type = NimBLETxPowerType::All);
# ifdef ESP_PLATFORM # ifdef ESP_PLATFORM
# ifndef CONFIG_IDF_TARGET_ESP32P4 # ifndef CONFIG_IDF_TARGET_ESP32P4

View file

@ -359,7 +359,7 @@ NimBLEExtAdvertisement::NimBLEExtAdvertisement(uint8_t priPhy, uint8_t secPhy) {
m_params.own_addr_type = NimBLEDevice::m_ownAddrType; m_params.own_addr_type = NimBLEDevice::m_ownAddrType;
m_params.primary_phy = priPhy; m_params.primary_phy = priPhy;
m_params.secondary_phy = secPhy; m_params.secondary_phy = secPhy;
m_params.tx_power = 127; m_params.tx_power = NimBLEDevice::getPower(NimBLETxPowerType::Advertise);
} // NimBLEExtAdvertisement } // NimBLEExtAdvertisement
/** /**
@ -1014,8 +1014,22 @@ bool NimBLEExtAdvertisement::setPreferredParams(uint16_t minInterval, uint16_t m
/** /**
* @brief Adds Tx power level to the advertisement data. * @brief Adds Tx power level to the advertisement data.
*/ */
void NimBLEExtAdvertisement::addTxPower() { bool NimBLEExtAdvertisement::addTxPower() {
if (m_params.legacy_pdu) {
m_params.include_tx_power = 0;
uint8_t data[3];
data[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1;
data[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL;
# ifndef CONFIG_IDF_TARGET_ESP32P4
data[2] = NimBLEDevice::getPower(NimBLETxPowerType::Advertise);
# else
data[2] = 0;
# endif
return addData(data, 3);
}
m_params.include_tx_power = 1; m_params.include_tx_power = 1;
return true;
} // addTxPower } // addTxPower
/** /**

View file

@ -72,8 +72,7 @@ class NimBLEExtAdvertisement {
bool addData(const uint8_t* data, size_t length); bool addData(const uint8_t* data, size_t length);
bool addData(const std::string& data); bool addData(const std::string& data);
bool setPreferredParams(uint16_t min, uint16_t max); bool setPreferredParams(uint16_t min, uint16_t max);
bool addTxPower();
void addTxPower();
void setLegacyAdvertising(bool enable); void setLegacyAdvertising(bool enable);
void setConnectable(bool enable); void setConnectable(bool enable);
void setScannable(bool enable); void setScannable(bool enable);