From 6c85cfa6c3d5ec9c46b87c761925b1bcb5c3827c Mon Sep 17 00:00:00 2001 From: thekurtovic <40248206+thekurtovic@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:19:44 -0500 Subject: [PATCH] NimBLEDevice::get/setPower support full power range. (#229) * Calculates the tx power level to and from dbm to `esp_power_level` types for esp32 devices. * Add esp32 specific funtions `NimBLEDevice::setPowerLevel` and `NimBLEDevice::getPowerLevel` which take and return the related `esp_power_level* ` types. --------- Co-authored-by: h2zero --- src/NimBLEDevice.cpp | 104 ++++++++++++++++++++----------------------- src/NimBLEDevice.h | 9 +++- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/src/NimBLEDevice.cpp b/src/NimBLEDevice.cpp index e88a4fb..fc62b30 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -421,47 +421,51 @@ std::vector NimBLEDevice::getConnectedClients() { /* TRANSMIT POWER */ /* -------------------------------------------------------------------------- */ +# ifdef ESP_PLATFORM +/** + * @brief Get the transmission power. + * @return The power level currently used in esp_power_level_t. + */ +esp_power_level_t NimBLEDevice::getPowerLevel(esp_ble_power_type_t powerType) { +# ifdef CONFIG_IDF_TARGET_ESP32P4 + return 0xFF; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_get +# else + return esp_ble_tx_power_get(powerType); +# endif +} // getPowerLevel + +/** + * @brief Set the transmission power. + * @param [in] powerLevel The power level to set in esp_power_level_t. + * @return True if the power level was set successfully. + */ +bool NimBLEDevice::setPowerLevel(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) { +# ifdef CONFIG_IDF_TARGET_ESP32P4 + return false; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_set +# else + esp_err_t errRc = esp_ble_tx_power_set(powerType, powerLevel); + if (errRc != ESP_OK) { + NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc); + } + + return errRc == ESP_OK; +# endif +} // setPowerLevel + +# endif /** * @brief Set the transmission power. * @param [in] dbm The power level to set in dBm. * @return True if the power level was set successfully. */ bool NimBLEDevice::setPower(int8_t dbm) { - NIMBLE_LOGD(LOG_TAG, ">> setPower: %d", dbm); # ifdef ESP_PLATFORM -# ifndef CONFIG_IDF_TARGET_ESP32P4 - if (dbm >= 9) { - dbm = ESP_PWR_LVL_P9; - } else if (dbm >= 6) { - dbm = ESP_PWR_LVL_P6; - } else if (dbm >= 3) { - dbm = ESP_PWR_LVL_P3; - } else if (dbm >= 0) { - dbm = ESP_PWR_LVL_N0; - } else if (dbm >= -3) { - dbm = ESP_PWR_LVL_N3; - } else if (dbm >= -6) { - dbm = ESP_PWR_LVL_N6; - } else if (dbm >= -9) { - dbm = ESP_PWR_LVL_N9; - } else if (dbm >= -12) { - dbm = ESP_PWR_LVL_N12; - } else { - NIMBLE_LOGE(LOG_TAG, "Unsupported power level"); - return false; + if (dbm % 3 == 2) { + dbm++; // round up to the next multiple of 3 to be able to target 20dbm } - - esp_err_t errRc = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, (esp_power_level_t)dbm); - if (errRc != ESP_OK) { - NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc); - } - - return errRc == ESP_OK; -# else - return 0xFF; // CONFIG_IDF_TARGET_ESP32P4 -# endif - + return setPowerLevel(static_cast(dbm / 3 + ESP_PWR_LVL_N0)); # else + NIMBLE_LOGD(LOG_TAG, ">> setPower: %d", dbm); ble_hci_vs_set_tx_pwr_cp cmd{dbm}; ble_hci_vs_set_tx_pwr_rp rsp{0}; int rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_TX_PWR, &cmd, sizeof(cmd), &rsp, sizeof(rsp)); @@ -478,34 +482,24 @@ bool NimBLEDevice::setPower(int8_t dbm) { /** * @brief Get the transmission power. * @return The power level currently used in dbm. + * @note ESP32S3 only returns 0xFF as of IDF 5, so this function will return 20dbm. */ int NimBLEDevice::getPower() { # ifdef ESP_PLATFORM -# ifndef CONFIG_IDF_TARGET_ESP32P4 - switch (esp_ble_tx_power_get(ESP_BLE_PWR_TYPE_DEFAULT)) { - case ESP_PWR_LVL_N12: - return -12; - case ESP_PWR_LVL_N9: - return -9; - case ESP_PWR_LVL_N6: - return -6; - case ESP_PWR_LVL_N3: - return -3; - case ESP_PWR_LVL_N0: - return 0; - case ESP_PWR_LVL_P3: - return 3; - case ESP_PWR_LVL_P6: - return 6; - case ESP_PWR_LVL_P9: - return 9; - default: - return 0xFF; - } -# else +# ifdef CONFIG_IDF_TARGET_ESP32P4 return 0xFF; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_get -# endif +# else + int pwr = esp_ble_tx_power_get(ESP_BLE_PWR_TYPE_DEFAULT); + if (pwr < ESP_PWR_LVL_N0) { + return -3 * (ESP_PWR_LVL_N0 - pwr); + } + if (pwr > ESP_PWR_LVL_N0) { + return std::min((pwr - ESP_PWR_LVL_N0) * 3, 20); + } + + return 0; +# endif # else return ble_phy_txpwr_get(); # endif diff --git a/src/NimBLEDevice.h b/src/NimBLEDevice.h index 7be94f1..add0fec 100644 --- a/src/NimBLEDevice.h +++ b/src/NimBLEDevice.h @@ -114,8 +114,6 @@ class NimBLEDevice { static bool onWhiteList(const NimBLEAddress& address); static size_t getWhiteListCount(); static NimBLEAddress getWhiteListAddress(size_t index); - static bool setPower(int8_t dbm); - static int getPower(); static bool setOwnAddrType(uint8_t type); static bool setOwnAddr(const NimBLEAddress& addr); static bool setOwnAddr(const uint8_t* addr); @@ -135,6 +133,13 @@ class NimBLEDevice { static void onReset(int reason); static void onSync(void); static void host_task(void* param); + static int getPower(); + static bool setPower(int8_t dbm); + +# if defined(ESP_PLATFORM) + static esp_power_level_t getPowerLevel(esp_ble_power_type_t powerType = ESP_BLE_PWR_TYPE_DEFAULT); + static bool setPowerLevel(esp_power_level_t powerLevel, esp_ble_power_type_t powerType = ESP_BLE_PWR_TYPE_DEFAULT); +# endif # if CONFIG_BT_NIMBLE_EXT_ADV static bool setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask);