From fbe20f16ead5cdb34f3cd52b0b45f447e2ae5dd1 Mon Sep 17 00:00:00 2001 From: h2zero Date: Thu, 28 Nov 2024 12:50:24 -0700 Subject: [PATCH] Add methods to set/get connection PHY's. * Added `NimBLEDevice::setDefaultPhy` which will set the default preferred PHY for all connections. * Added `NimBLEClient::updatePhy` to request a PHY change with a peer. * Added `NimBLEClient::getPhy` to read the current connection PHY setting. * Added `NimBLEServer::updatePhy` to request a PHY change with a peer. * Added `NimBLEServer::getPhy` to read the PHY of a peer connection. * Added callbacks: * - `NimBLEClientCallbacks::onPhyUpdate` * - `NimBLEServerCallbacks::onPhyUpdate` Which are called when the PHY update is complete. --- src/NimBLEClient.cpp | 80 +++++++++++++++++++++++++++++++++++++++----- src/NimBLEClient.h | 19 ++++++++++- src/NimBLEDevice.cpp | 25 ++++++++++++++ src/NimBLEDevice.h | 4 +++ src/NimBLEServer.cpp | 64 +++++++++++++++++++++++++++++++++++ src/NimBLEServer.h | 17 ++++++++++ 6 files changed, 199 insertions(+), 10 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index ad0bfa63..b2eb70e9 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -388,7 +388,49 @@ void NimBLEClient::setConfig(NimBLEClient::Config config) { */ void NimBLEClient::setConnectPhy(uint8_t mask) { m_phyMask = mask; -} +} // setConnectPhy + +/** + * @brief Request a change to the PHY used for this peer connection. + * @param [in] txPhyMask TX PHY. Can be mask of following: + * - BLE_GAP_LE_PHY_1M_MASK + * - BLE_GAP_LE_PHY_2M_MASK + * - BLE_GAP_LE_PHY_CODED_MASK + * - BLE_GAP_LE_PHY_ANY_MASK + * @param [in] rxPhyMask RX PHY. Can be mask of following: + * - BLE_GAP_LE_PHY_1M_MASK + * - BLE_GAP_LE_PHY_2M_MASK + * - BLE_GAP_LE_PHY_CODED_MASK + * - BLE_GAP_LE_PHY_ANY_MASK + * @param phyOptions Additional PHY options. Valid values are: + * - BLE_GAP_LE_PHY_CODED_ANY (default) + * - BLE_GAP_LE_PHY_CODED_S2 + * - BLE_GAP_LE_PHY_CODED_S8 + * @return True if successful. + */ +bool NimBLEClient::updatePhy(uint8_t txPhyMask, uint8_t rxPhyMask, uint16_t phyOptions) { + int rc = ble_gap_set_prefered_le_phy(m_connHandle, txPhyMask, rxPhyMask, phyOptions); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Failed to update phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + } + + return rc == 0; +} // updatePhy + +/** + * @brief Get the PHY used for this peer connection. + * @param [out] txPhy The TX PHY. + * @param [out] rxPhy The RX PHY. + * @return True if successful. + */ +bool NimBLEClient::getPhy(uint8_t* txPhy, uint8_t* rxPhy) { + int rc = ble_gap_read_le_phy(m_connHandle, txPhy, rxPhy); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Failed to read phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + } + + return rc == 0; +} // getPhy # endif /** @@ -1129,6 +1171,19 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { break; } // BLE_GAP_EVENT_IDENTITY_RESOLVED +# if CONFIG_BT_NIMBLE_EXT_ADV + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: { + NimBLEConnInfo peerInfo; + rc = ble_gap_conn_find(event->phy_updated.conn_handle, &peerInfo.m_desc); + if (rc != 0) { + return BLE_ATT_ERR_INVALID_HANDLE; + } + + pClient->m_pClientCallbacks->onPhyUpdate(pClient, event->phy_updated.tx_phy, event->phy_updated.rx_phy); + return 0; + } // BLE_GAP_EVENT_PHY_UPDATE_COMPLETE +# endif + case BLE_GAP_EVENT_MTU: { if (pClient->m_connHandle != event->mtu.conn_handle) { return 0; @@ -1224,30 +1279,31 @@ std::string NimBLEClient::toString() const { } // toString static const char* CB_TAG = "NimBLEClientCallbacks"; + /** * @brief Get the last error code reported by the NimBLE host * @return int, the NimBLE error code. */ -int NimBLEClient::getLastError() const { +int NimBLEClient::getLastError() const { return m_lastErr; } // getLastError void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) { NIMBLE_LOGD(CB_TAG, "onConnect: default"); -} +} // onConnect void NimBLEClientCallbacks::onConnectFail(NimBLEClient* pClient, int reason) { NIMBLE_LOGD(CB_TAG, "onConnectFail: default, reason: %d", reason); -} +} // onConnectFail void NimBLEClientCallbacks::onDisconnect(NimBLEClient* pClient, int reason) { NIMBLE_LOGD(CB_TAG, "onDisconnect: default, reason: %d", reason); -} +} // onDisconnect bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) { NIMBLE_LOGD(CB_TAG, "onConnParamsUpdateRequest: default"); return true; -} +} // onConnParamsUpdateRequest void NimBLEClientCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo) { NIMBLE_LOGD(CB_TAG, "onPassKeyEntry: default: 123456"); @@ -1256,7 +1312,7 @@ void NimBLEClientCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo) { void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) { NIMBLE_LOGD(CB_TAG, "onAuthenticationComplete: default"); -} +} // onAuthenticationComplete void NimBLEClientCallbacks::onIdentity(NimBLEConnInfo& connInfo) { NIMBLE_LOGD(CB_TAG, "onIdentity: default"); @@ -1265,10 +1321,16 @@ void NimBLEClientCallbacks::onIdentity(NimBLEConnInfo& connInfo) { void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin) { NIMBLE_LOGD(CB_TAG, "onConfirmPasskey: default: true"); NimBLEDevice::injectConfirmPasskey(connInfo, true); -} +} // onConfirmPasskey void NimBLEClientCallbacks::onMTUChange(NimBLEClient* pClient, uint16_t mtu) { NIMBLE_LOGD(CB_TAG, "onMTUChange: default"); -} +} // onMTUChange + +# if CONFIG_BT_NIMBLE_EXT_ADV +void NimBLEClientCallbacks::onPhyUpdate(NimBLEClient* pClient, uint8_t txPhy, uint8_t rxPhy) { + NIMBLE_LOGD(CB_TAG, "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy); +} // onPhyUpdate +# endif #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index 8a23cf8f..3d725f10 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -93,7 +93,9 @@ class NimBLEClient { bool response = false); # if CONFIG_BT_NIMBLE_EXT_ADV - void setConnectPhy(uint8_t mask); + void setConnectPhy(uint8_t phyMask); + bool updatePhy(uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions = 0); + bool getPhy(uint8_t* txPhy, uint8_t* rxPhy); # endif struct Config { @@ -207,6 +209,21 @@ class NimBLEClientCallbacks { * about the peer connection parameters. */ virtual void onMTUChange(NimBLEClient* pClient, uint16_t MTU); + +# if CONFIG_BT_NIMBLE_EXT_ADV + /** + * @brief Called when the PHY update procedure is complete. + * @param [in] pClient A pointer to the client whose PHY was updated. + * about the peer connection parameters. + * @param [in] txPhy The transmit PHY. + * @param [in] rxPhy The receive PHY. + * Possible values: + * * BLE_GAP_LE_PHY_1M + * * BLE_GAP_LE_PHY_2M + * * BLE_GAP_LE_PHY_CODED + */ + virtual void onPhyUpdate(NimBLEClient* pClient, uint8_t txPhy, uint8_t rxPhy); +# endif }; #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/src/NimBLEDevice.cpp b/src/NimBLEDevice.cpp index 07c01ac1..c109cfcf 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -711,6 +711,31 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) { /* STACK FUNCTIONS */ /* -------------------------------------------------------------------------- */ +# if CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) +/** + * @brief Set the preferred default phy to use for connections. + * @param [in] txPhyMask TX PHY. Can be mask of following: + * - BLE_GAP_LE_PHY_1M_MASK + * - BLE_GAP_LE_PHY_2M_MASK + * - BLE_GAP_LE_PHY_CODED_MASK + * - BLE_GAP_LE_PHY_ANY_MASK + * @param [in] rxPhyMask RX PHY. Can be mask of following: + * - BLE_GAP_LE_PHY_1M_MASK + * - BLE_GAP_LE_PHY_2M_MASK + * - BLE_GAP_LE_PHY_CODED_MASK + * - BLE_GAP_LE_PHY_ANY_MASK + * @return True if successful. + */ +bool NimBLEDevice::setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask) { + int rc = ble_gap_set_prefered_default_le_phy(txPhyMask, rxPhyMask); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Failed to set default phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + } + + return rc == 0; +} +# endif + /** * @brief Host reset, we pass the message so we don't make calls until re-synced. * @param [in] reason The reason code for the reset. diff --git a/src/NimBLEDevice.h b/src/NimBLEDevice.h index 51d16c5c..96b2c678 100644 --- a/src/NimBLEDevice.h +++ b/src/NimBLEDevice.h @@ -136,6 +136,10 @@ class NimBLEDevice { static void onSync(void); static void host_task(void* param); +# if CONFIG_BT_NIMBLE_EXT_ADV + static bool setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask); +# endif + # if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) static NimBLEScan* getScan(); # endif diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index 9e9aab7a..9bb1c221 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -671,6 +671,20 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { return 0; } // BLE_GAP_EVENT_IDENTITY_RESOLVED +# if CONFIG_BT_NIMBLE_EXT_ADV + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: { + rc = ble_gap_conn_find(event->phy_updated.conn_handle, &peerInfo.m_desc); + if(rc != 0) { + return BLE_ATT_ERR_INVALID_HANDLE; + } + + pServer->m_pServerCallbacks->onPhyUpdate(peerInfo, + event->phy_updated.tx_phy, + event->phy_updated.rx_phy); + return 0; + } //BLE_GAP_EVENT_PHY_UPDATE_COMPLETE +#endif + case BLE_GAP_EVENT_PASSKEY_ACTION: { struct ble_sm_io pkey = {0,0}; @@ -937,6 +951,50 @@ bool NimBLEServer::startAdvertising(uint8_t inst_id, bool NimBLEServer::stopAdvertising(uint8_t inst_id) { return getAdvertising()->stop(inst_id); } // stopAdvertising + +/** + * @brief Request an update to the PHY used for a peer connection. + * @param [in] connHandle the connection handle to the update the PHY for. + * @param [in] txPhyMask TX PHY. Can be mask of following: + * - BLE_GAP_LE_PHY_1M_MASK + * - BLE_GAP_LE_PHY_2M_MASK + * - BLE_GAP_LE_PHY_CODED_MASK + * - BLE_GAP_LE_PHY_ANY_MASK + * @param [in] rxPhyMask RX PHY. Can be mask of following: + * - BLE_GAP_LE_PHY_1M_MASK + * - BLE_GAP_LE_PHY_2M_MASK + * - BLE_GAP_LE_PHY_CODED_MASK + * - BLE_GAP_LE_PHY_ANY_MASK + * @param phyOptions Additional PHY options. Valid values are: + * - BLE_GAP_LE_PHY_CODED_ANY (default) + * - BLE_GAP_LE_PHY_CODED_S2 + * - BLE_GAP_LE_PHY_CODED_S8 + * @return True if successful. + */ +bool NimBLEServer::updatePhy(uint16_t connHandle, uint8_t txPhyMask, uint8_t rxPhyMask, uint16_t phyOptions) { + int rc = ble_gap_set_prefered_le_phy(connHandle, txPhyMask, rxPhyMask, phyOptions); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Failed to update phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + } + + return rc == 0; +} // updatePhy + +/** + * @brief Get the PHY used for a peer connection. + * @param [in] connHandle the connection handle to the get the PHY for. + * @param [out] txPhy The TX PHY. + * @param [out] rxPhy The RX PHY. + * @return True if successful. + */ +bool NimBLEServer::getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy) { + int rc = ble_gap_read_le_phy(connHandle, txPhy, rxPhy); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Failed to read phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + } + + return rc == 0; +} // getPhy #endif #if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) @@ -1089,4 +1147,10 @@ void NimBLEServerCallbacks::onConnParamsUpdate(NimBLEConnInfo& connInfo){ NIMBLE_LOGD("NimBLEServerCallbacks", "onConnParamsUpdate: default"); } // onConnParamsUpdate +# if CONFIG_BT_NIMBLE_EXT_ADV +void NimBLEServerCallbacks::onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy, uint8_t rxPhy) { + NIMBLE_LOGD("NimBLEServerCallbacks", "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy); +} // onPhyUpdate +# endif + #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h index 86700e19..1417c30b 100644 --- a/src/NimBLEServer.h +++ b/src/NimBLEServer.h @@ -55,6 +55,8 @@ class NimBLEServer { int duration = 0, int max_events = 0); bool stopAdvertising(uint8_t inst_id); + bool updatePhy(uint16_t connHandle, uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions); + bool getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy); #endif # if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) NimBLEAdvertising* getAdvertising(); @@ -213,6 +215,21 @@ class NimBLEServerCallbacks { * updated connection parameters. */ virtual void onConnParamsUpdate(NimBLEConnInfo& connInfo); + +# if CONFIG_BT_NIMBLE_EXT_ADV + /** + * @brief Called when the PHY update procedure is complete. + * @param [in] connInfo A reference to a NimBLEConnInfo instance with information + * about the peer connection parameters. + * @param [in] txPhy The transmit PHY. + * @param [in] rxPhy The receive PHY. + * Possible values: + * * BLE_GAP_LE_PHY_1M + * * BLE_GAP_LE_PHY_2M + * * BLE_GAP_LE_PHY_CODED + */ + virtual void onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy, uint8_t rxPhy); +# endif }; // NimBLEServerCallbacks #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */