From d9178cfa9b68b2a6973fae9806d65ce53a2e803a Mon Sep 17 00:00:00 2001 From: h2zero Date: Sun, 24 Nov 2024 19:59:56 -0700 Subject: [PATCH] [BREAKING] Refactor NimBLEServer * General code cleanup * `NimBLEServerCallbacks::onMTUChanged` renamed to `NimBLEServerCallbacks::onMTUChange` to be consistent with the client callback. * `NimBLEServer::getPeerIDInfo` renamed to `NimBLEServer::getPeerInfoByHandle` to better describe it's use. * Use a std::array to store client connection handles instead of std::vector to reduce memory allocation. * `NimBLEServer::disconnect` now returns `bool`, true = success, instead of `int` to be consistent with the rest of the library. --- src/NimBLEAdvertising.cpp | 7 +- src/NimBLEExtAdvertising.cpp | 4 +- src/NimBLEServer.cpp | 735 ++++++++++++++++------------------- src/NimBLEServer.h | 205 +++++----- src/NimBLEService.cpp | 7 +- 5 files changed, 448 insertions(+), 510 deletions(-) diff --git a/src/NimBLEAdvertising.cpp b/src/NimBLEAdvertising.cpp index d11bcfb..f3227a0 100644 --- a/src/NimBLEAdvertising.cpp +++ b/src/NimBLEAdvertising.cpp @@ -199,12 +199,7 @@ bool NimBLEAdvertising::start(uint32_t duration, const NimBLEAddress* dirAddr) { # if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) NimBLEServer* pServer = NimBLEDevice::getServer(); if (pServer != nullptr) { - if (!pServer->m_gattsStarted) { - pServer->start(); - } else if (pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) { - NIMBLE_LOGE(LOG_TAG, "Unable to advertise; Max connections reached"); - return false; - } + pServer->start(); // make sure the GATT server is ready before advertising } # endif diff --git a/src/NimBLEExtAdvertising.cpp b/src/NimBLEExtAdvertising.cpp index bf1681e..3104f6f 100644 --- a/src/NimBLEExtAdvertising.cpp +++ b/src/NimBLEExtAdvertising.cpp @@ -62,9 +62,7 @@ bool NimBLEExtAdvertising::setInstanceData(uint8_t instId, NimBLEExtAdvertisemen # if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) NimBLEServer* pServer = NimBLEDevice::getServer(); if (pServer != nullptr) { - if (!pServer->m_gattsStarted) { - pServer->start(); - } + pServer->start(); // make sure the GATT server is ready before advertising } int rc = ble_gap_ext_adv_configure( diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index 9bb1c22..a808496 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -15,180 +15,164 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#include "NimBLEServer.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" +# include "NimBLEServer.h" +# include "NimBLEDevice.h" +# include "NimBLELog.h" -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "services/gap/ble_svc_gap.h" -#include "services/gatt/ble_svc_gatt.h" -#else -#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h" -#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h" -#endif +# if defined(CONFIG_NIMBLE_CPP_IDF) +# include "services/gap/ble_svc_gap.h" +# include "services/gatt/ble_svc_gatt.h" +# else +# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h" +# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h" +# endif -#include -#include +# define NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB 0 +# define NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB 1 -#define NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB 0 -#define NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB 1 - -static const char* LOG_TAG = "NimBLEServer"; +static const char* LOG_TAG = "NimBLEServer"; static NimBLEServerCallbacks defaultCallbacks; - /** - * @brief Construct a %BLE Server + * @brief Construct a BLE Server * - * This class is not designed to be individually instantiated. Instead one should create a server by asking - * the NimBLEDevice class. + * This class is not designed to be individually instantiated. + * Instead it should be created the NimBLEDevice API. */ -NimBLEServer::NimBLEServer() { - memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait)); -// m_svcChgChrHdl = 0xffff; // Future Use - m_pServerCallbacks = &defaultCallbacks; - m_gattsStarted = false; -#if !CONFIG_BT_NIMBLE_EXT_ADV - m_advertiseOnDisconnect = true; -#endif - m_svcChanged = false; - m_deleteCallbacks = true; - m_getPeerNameOnConnect = false; +NimBLEServer::NimBLEServer() + : m_gattsStarted{false}, + m_getPeerNameOnConnect{false}, + m_svcChanged{false}, + m_deleteCallbacks{false}, +# if !CONFIG_BT_NIMBLE_EXT_ADV + m_advertiseOnDisconnect{false}, +# endif + m_pServerCallbacks{&defaultCallbacks}, + m_svcVec{}, + m_notifyChrVec{} { + m_connectedPeers.fill(BLE_HS_CONN_HANDLE_NONE); + m_indWait.fill(BLE_HS_CONN_HANDLE_NONE); } // NimBLEServer - /** * @brief Destructor: frees all resources / attributes created. */ NimBLEServer::~NimBLEServer() { - for(const auto &it : m_svcVec) { - delete it; + for (const auto& svc : m_svcVec) { + delete svc; } - if(m_deleteCallbacks && m_pServerCallbacks != &defaultCallbacks) { + if (m_deleteCallbacks) { delete m_pServerCallbacks; } } - /** - * @brief Create a %BLE Service. + * @brief Create a BLE Service. * @param [in] uuid The UUID of the new service. - * @return A reference to the new service object. + * @return A pointer to the new service object. */ NimBLEService* NimBLEServer::createService(const char* uuid) { return createService(NimBLEUUID(uuid)); } // createService - /** - * @brief Create a %BLE Service. + * @brief Create a BLE Service. * @param [in] uuid The UUID of the new service. - * @return A reference to the new service object. + * @return A pointer to the new service object. */ -NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); - - // Check that a service with the supplied UUID does not already exist. - if(getServiceByUUID(uuid) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", - std::string(uuid).c_str()); - } - +NimBLEService* NimBLEServer::createService(const NimBLEUUID& uuid) { NimBLEService* pService = new NimBLEService(uuid); m_svcVec.push_back(pService); serviceChanged(); - NIMBLE_LOGD(LOG_TAG, "<< createService"); return pService; } // createService - /** - * @brief Get a %BLE Service by its UUID + * @brief Get a BLE Service by its UUID * @param [in] uuid The UUID of the service. * @param instanceId The index of the service to return (used when multiple services have the same UUID). * @return A pointer to the service object or nullptr if not found. */ -NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) { +NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) const { return getServiceByUUID(NimBLEUUID(uuid), instanceId); } // getServiceByUUID - /** - * @brief Get a %BLE Service by its UUID + * @brief Get a BLE Service by its UUID * @param [in] uuid The UUID of the service. * @param instanceId The index of the service to return (used when multiple services have the same UUID). * @return A pointer to the service object or nullptr if not found. */ -NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) { +NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId) const { uint16_t position = 0; - for (auto &it : m_svcVec) { - if (it->getUUID() == uuid) { - if (position == instanceId){ - return it; + for (const auto& svc : m_svcVec) { + if (svc->getUUID() == uuid) { + if (position == instanceId) { + return svc; } position++; } } + return nullptr; } // getServiceByUUID /** - * @brief Get a %BLE Service by its handle + * @brief Get a BLE Service by its handle * @param handle The handle of the service. * @return A pointer to the service object or nullptr if not found. */ -NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) { - for (auto &it : m_svcVec) { - if (it->getHandle() == handle) { - return it; +NimBLEService* NimBLEServer::getServiceByHandle(uint16_t handle) const { + for (const auto& svc : m_svcVec) { + if (svc->getHandle() == handle) { + return svc; } } + return nullptr; } - -#if CONFIG_BT_NIMBLE_EXT_ADV +# if CONFIG_BT_NIMBLE_EXT_ADV /** * @brief Retrieve the advertising object that can be used to advertise the existence of the server. - * @return An advertising object. + * @return A pinter to an advertising object. */ -NimBLEExtAdvertising* NimBLEServer::getAdvertising() { +NimBLEExtAdvertising* NimBLEServer::getAdvertising() const { return NimBLEDevice::getAdvertising(); } // getAdvertising -#endif +# endif -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) +# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) /** * @brief Retrieve the advertising object that can be used to advertise the existence of the server. - * @return An advertising object. + * @return A pointer to an advertising object. */ -NimBLEAdvertising* NimBLEServer::getAdvertising() { +NimBLEAdvertising* NimBLEServer::getAdvertising() const { return NimBLEDevice::getAdvertising(); } // getAdvertising -#endif +# endif /** * @brief Sends a service changed notification and resets the GATT server. */ void NimBLEServer::serviceChanged() { - if(m_gattsStarted) { + if (m_gattsStarted) { m_svcChanged = true; ble_svc_gatt_changed(0x0001, 0xffff); resetGATT(); } -} - +} // serviceChanged /** - * @brief Start the GATT server. Required to be called after setup of all - * services and characteristics / descriptors for the NimBLE host to register them. + * @brief Start the GATT server. + * @details Required to be called after setup of all services and characteristics / descriptors + * for the NimBLE host to register them. */ void NimBLEServer::start() { - if(m_gattsStarted) { - NIMBLE_LOGW(LOG_TAG, "Gatt server already started"); - return; + if (m_gattsStarted) { + return; //already started } int rc = ble_gatts_start(); @@ -197,49 +181,33 @@ void NimBLEServer::start() { return; } -#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4 +# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4 ble_gatts_show_local(); -#endif -/*** Future use *** - * TODO: implement service changed handling +# endif - ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801}; - ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05}; - - rc = ble_gatts_find_chr(&svc.u, &chr.u, NULL, &m_svcChgChrHdl); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gatts_find_chr: rc=%d, %s", rc, - NimBLEUtils::returnCodeToString(rc)); - abort(); - } - - NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl); -*/ // Get the assigned service handles and build a vector of characteristics // with Notify / Indicate capabilities for event handling - for(auto &svc : m_svcVec) { - if(svc->getRemoved() == 0) { + for (const auto& svc : m_svcVec) { + if (svc->getRemoved() == 0) { rc = ble_gatts_find_svc(svc->getUUID().getBase(), &svc->m_handle); - if(rc != 0) { - NIMBLE_LOGW(LOG_TAG, "GATT Server started without service: %s, Service %s", - svc->getUUID().toString().c_str(), svc->isStarted() ? "missing" : "not started"); + if (rc != 0) { + NIMBLE_LOGW(LOG_TAG, + "GATT Server started without service: %s, Service %s", + svc->getUUID().toString().c_str(), + svc->isStarted() ? "missing" : "not started"); continue; // Skip this service as it was not started } } - for(auto &chr : svc->m_vChars) { + for (auto& chr : svc->m_vChars) { // if Notify / Indicate is enabled but we didn't create the descriptor // we do it now. - if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) || - (chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) { + if ((chr->m_properties & BLE_GATT_CHR_F_INDICATE) || (chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) { m_notifyChrVec.push_back(chr); } - for (auto &desc : chr->m_vDescriptors) { - ble_gatts_find_dsc(svc->getUUID().getBase(), - chr->getUUID().getBase(), - desc->getUUID().getBase(), - &desc->m_handle); + for (auto& desc : chr->m_vDescriptors) { + ble_gatts_find_dsc(svc->getUUID().getBase(), chr->getUUID().getBase(), desc->getUUID().getBase(), &desc->m_handle); } } } @@ -247,24 +215,20 @@ void NimBLEServer::start() { m_gattsStarted = true; } // start - /** * @brief Disconnect the specified client with optional reason. - * @param [in] connId Connection Id of the client to disconnect. + * @param [in] connHandle Connection handle of the client to disconnect. * @param [in] reason code for disconnecting. - * @return NimBLE host return code. + * @return True if successful. */ -int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) { - NIMBLE_LOGD(LOG_TAG, ">> disconnect()"); - - int rc = ble_gap_terminate(connId, reason); - if(rc != 0){ - NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc, - NimBLEUtils::returnCodeToString(rc)); +bool NimBLEServer::disconnect(uint16_t connHandle, uint8_t reason) const { + int rc = ble_gap_terminate(connHandle, reason); + if (rc != 0 && rc != BLE_HS_ENOTCONN && rc != BLE_HS_EALREADY) { + NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } - NIMBLE_LOGD(LOG_TAG, "<< disconnect()"); - return rc; + return true; } // disconnect /** @@ -273,19 +237,19 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) { * @param [in] reason code for disconnecting. * @return NimBLE host return code. */ -int NimBLEServer::disconnect(const NimBLEConnInfo &connInfo, uint8_t reason) { +bool NimBLEServer::disconnect(const NimBLEConnInfo& connInfo, uint8_t reason) const { return disconnect(connInfo.getConnHandle(), reason); } // disconnect -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) +# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) /** * @brief Set the server to automatically start advertising when a client disconnects. - * @param [in] aod true == advertise, false == don't advertise. + * @param [in] enable true == advertise, false == don't advertise. */ -void NimBLEServer::advertiseOnDisconnect(bool aod) { - m_advertiseOnDisconnect = aod; +void NimBLEServer::advertiseOnDisconnect(bool enable) { + m_advertiseOnDisconnect = enable; } // advertiseOnDisconnect -#endif +# endif /** * @brief Set the server to automatically read the name from the connected peer before @@ -300,57 +264,78 @@ void NimBLEServer::getPeerNameOnConnect(bool enable) { * @brief Return the number of connected clients. * @return The number of connected clients. */ -size_t NimBLEServer::getConnectedCount() { - return m_connectedPeersVec.size(); +uint8_t NimBLEServer::getConnectedCount() const { + size_t count = 0; + for (const auto& peer : m_connectedPeers) { + if (peer != BLE_HS_CONN_HANDLE_NONE) { + count++; + } + } + + return count; } // getConnectedCount - /** - * @brief Get the vector of the connected client ID's. + * @brief Get a vector of the connected client handles. + * @return A vector of the connected client handles. */ -std::vector NimBLEServer::getPeerDevices() { - return m_connectedPeersVec; -} // getPeerDevices +std::vector NimBLEServer::getPeerDevices() const { + std::vector peers{}; + for (const auto& peer : m_connectedPeers) { + if (peer != BLE_HS_CONN_HANDLE_NONE) { + peers.push_back(peer); + } + } + return peers; +} // getPeerDevices /** * @brief Get the connection information of a connected peer by vector index. * @param [in] index The vector index of the peer. + * @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found. */ -NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) { - if (index >= m_connectedPeersVec.size()) { - NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index); - return NimBLEConnInfo(); +NimBLEConnInfo NimBLEServer::getPeerInfo(uint8_t index) const { + if (index >= m_connectedPeers.size()) { + NIMBLE_LOGE(LOG_TAG, "Invalid index %u", index); + return NimBLEConnInfo{}; } - return getPeerIDInfo(m_connectedPeersVec[index]); -} // getPeerInfo + auto count = 0; + for (const auto& peer : m_connectedPeers) { + if (peer != BLE_HS_CONN_HANDLE_NONE) { + if (count == index) { + return getPeerInfoByHandle(m_connectedPeers[count]); + } + count++; + } + } + return NimBLEConnInfo{}; +} // getPeerInfo /** * @brief Get the connection information of a connected peer by address. * @param [in] address The address of the peer. + * @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found. */ -NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) { - NimBLEConnInfo peerInfo; - int rc = ble_gap_conn_find_by_addr(address.getBase(), &peerInfo.m_desc); - if (rc != 0) { +NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) const { + NimBLEConnInfo peerInfo{}; + if (ble_gap_conn_find_by_addr(address.getBase(), &peerInfo.m_desc) != 0) { NIMBLE_LOGE(LOG_TAG, "Peer info not found"); } return peerInfo; } // getPeerInfo - /** - * @brief Get the connection information of a connected peer by connection ID. - * @param [in] id The connection id of the peer. + * @brief Get the connection information of a connected peer by connection handle. + * @param [in] connHandle The connection handle of the peer. + * @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found. */ -NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) { - NimBLEConnInfo peerInfo; - - int rc = ble_gap_conn_find(id, &peerInfo.m_desc); - if (rc != 0) { +NimBLEConnInfo NimBLEServer::getPeerInfoByHandle(uint16_t connHandle) const { + NimBLEConnInfo peerInfo{}; + if (ble_gap_conn_find(connHandle, &peerInfo.m_desc) != 0) { NIMBLE_LOGE(LOG_TAG, "Peer info not found"); } @@ -361,16 +346,13 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) { * @brief Callback that is called after reading from the peer name characteristic. * @details This will check the task pointer in the task data struct to determine * the action to take once the name has been read. If there is a task waiting then - * it will be woken, if not, the the RC value is checked to determine which callback + * it will be resumed, if not, the the RC value is checked to determine which callback * should be called. */ -int NimBLEServer::peerNameCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) { - NimBLETaskData *pTaskData = (NimBLETaskData*)arg; - std::string *name = (std::string*)pTaskData->m_pBuf; - int rc = error->status; +int NimBLEServer::peerNameCB(uint16_t connHandle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg) { + NimBLETaskData* pTaskData = (NimBLETaskData*)arg; + std::string* name = (std::string*)pTaskData->m_pBuf; + int rc = error->status; if (rc == 0) { if (attr) { @@ -381,9 +363,9 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, if (rc == BLE_HS_EDONE) { if (pTaskData->m_flags != -1) { - NimBLEServer* pServer = (NimBLEServer*)pTaskData->m_pInstance; + NimBLEServer* pServer = (NimBLEServer*)pTaskData->m_pInstance; NimBLEConnInfo peerInfo{}; - ble_gap_conn_find(conn_handle, &peerInfo.m_desc); + ble_gap_conn_find(connHandle, &peerInfo.m_desc); // check the flag to indicate which callback should be called. if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) { @@ -408,30 +390,25 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, } /** - * @brief Internal method that sends the read command. + * @brief Implementation of the function that sends the read command. */ -std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, int cb_type) { - std::string *buf = new std::string{}; - NimBLETaskData *pTaskData = new NimBLETaskData(this, cb_type, buf); - ble_uuid16_t uuid {{BLE_UUID_TYPE_16}, BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME}; - int rc = ble_gattc_read_by_uuid(conn_handle, - 1, - 0xffff, - &uuid.u, - NimBLEServer::peerNameCB, - pTaskData); +std::string NimBLEServer::getPeerNameImpl(uint16_t connHandle, int cbType) const { + std::string* buf = new std::string{}; + NimBLETaskData* pTaskData = new NimBLETaskData(const_cast(this), cbType, buf); + ble_uuid16_t uuid{{BLE_UUID_TYPE_16}, BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME}; + int rc = ble_gattc_read_by_uuid(connHandle, 1, 0xffff, &uuid.u, NimBLEServer::peerNameCB, pTaskData); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "ble_gattc_read_by_uuid rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); NimBLEConnInfo peerInfo{}; - ble_gap_conn_find(conn_handle, &peerInfo.m_desc); - if (cb_type == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) { - m_pServerCallbacks->onConnect(this, peerInfo, *buf); - } else if (cb_type == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) { + ble_gap_conn_find(connHandle, &peerInfo.m_desc); + if (cbType == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) { + m_pServerCallbacks->onConnect(const_cast(this), peerInfo, *buf); + } else if (cbType == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) { m_pServerCallbacks->onAuthenticationComplete(peerInfo, *buf); } delete buf; delete pTaskData; - } else if (cb_type == -1) { + } else if (cbType == -1) { NimBLEUtils::taskWait(*pTaskData, BLE_NPL_TIME_FOREVER); rc = pTaskData->m_flags; std::string name{*(std::string*)pTaskData->m_pBuf}; @@ -454,61 +431,56 @@ std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, int cb_type) * @returns A string containing the name. * @note This is a blocking call and should NOT be called from any callbacks! */ -std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) { - std::string name = getPeerNameInternal(connInfo.getConnHandle()); +std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) const { + std::string name = getPeerNameImpl(connInfo.getConnHandle()); return name; } /** - * @brief Handle a GATT Server Event. - * - * @param [in] event - * @param [in] gatts_if - * @param [in] param - * + * @brief Gap event handler. */ -/*STATIC*/ -int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { +int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) { NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s", NimBLEUtils::gapEventToString(event->type)); - int rc = 0; - NimBLEConnInfo peerInfo; - NimBLEServer* pServer = NimBLEDevice::getServer(); - - switch(event->type) { + int rc = 0; + NimBLEConnInfo peerInfo{}; + NimBLEServer* pServer = NimBLEDevice::getServer(); + switch (event->type) { case BLE_GAP_EVENT_CONNECT: { if (event->connect.status != 0) { /* Connection failed; resume advertising */ NIMBLE_LOGE(LOG_TAG, "Connection failed"); -#if !CONFIG_BT_NIMBLE_EXT_ADV +# if !CONFIG_BT_NIMBLE_EXT_ADV NimBLEDevice::startAdvertising(); -#endif +# endif } else { rc = ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc); if (rc != 0) { return 0; } - pServer->m_connectedPeersVec.push_back(event->connect.conn_handle); + for (auto& peer : pServer->m_connectedPeers) { + if (peer == BLE_HS_CONN_HANDLE_NONE) { + peer = event->connect.conn_handle; + break; + } + } if (pServer->m_getPeerNameOnConnect) { - pServer->getPeerNameInternal(event->connect.conn_handle, - NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB); + pServer->getPeerNameImpl(event->connect.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB); } else { pServer->m_pServerCallbacks->onConnect(pServer, peerInfo); } - } - return 0; + break; } // BLE_GAP_EVENT_CONNECT - case BLE_GAP_EVENT_DISCONNECT: { // If Host reset tell the device now before returning to prevent // any errors caused by calling host functions before resync. - switch(event->disconnect.reason) { + switch (event->disconnect.reason) { case BLE_HS_ETIMEOUT_HCI: case BLE_HS_EOS: case BLE_HS_ECONTROLLER: @@ -520,110 +492,103 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { break; } - pServer->m_connectedPeersVec.erase(std::remove(pServer->m_connectedPeersVec.begin(), - pServer->m_connectedPeersVec.end(), - event->disconnect.conn.conn_handle), - pServer->m_connectedPeersVec.end()); + for (auto& peer : pServer->m_connectedPeers) { + if (peer == event->disconnect.conn.conn_handle) { + peer = BLE_HS_CONN_HANDLE_NONE; + break; + } + } - if(pServer->m_svcChanged) { + if (pServer->m_svcChanged) { pServer->resetGATT(); } - NimBLEConnInfo peerInfo(event->disconnect.conn); + peerInfo.m_desc = event->disconnect.conn; pServer->m_pServerCallbacks->onDisconnect(pServer, peerInfo, event->disconnect.reason); - -#if !CONFIG_BT_NIMBLE_EXT_ADV - if(pServer->m_advertiseOnDisconnect) { +# if !CONFIG_BT_NIMBLE_EXT_ADV + if (pServer->m_advertiseOnDisconnect) { pServer->startAdvertising(); } -#endif - return 0; +# endif + break; } // BLE_GAP_EVENT_DISCONNECT case BLE_GAP_EVENT_SUBSCRIBE: { - NIMBLE_LOGI(LOG_TAG, "subscribe event; attr_handle=%d, subscribed: %s", - event->subscribe.attr_handle, - (event->subscribe.cur_notify ? "true":"false")); + NIMBLE_LOGI(LOG_TAG, + "subscribe event; attr_handle=%d, subscribed: %s", + event->subscribe.attr_handle, + (event->subscribe.cur_notify ? "true" : "false")); - for(auto &it : pServer->m_notifyChrVec) { - if(it->getHandle() == event->subscribe.attr_handle) { + for (const auto& chr : pServer->m_notifyChrVec) { + if (chr->getHandle() == event->subscribe.attr_handle) { rc = ble_gap_conn_find(event->subscribe.conn_handle, &peerInfo.m_desc); if (rc != 0) { break; } - if(((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) || - (it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) || - (it->getProperties() & BLE_GATT_CHR_F_READ_ENC)) && - !peerInfo.isEncrypted()) { - NimBLEDevice::startSecurity(event->subscribe.conn_handle); + auto chrProps = chr->getProperties(); + if (!peerInfo.isEncrypted() && + (chrProps & BLE_GATT_CHR_F_READ_AUTHEN || chrProps & BLE_GATT_CHR_F_READ_AUTHOR || + chrProps & BLE_GATT_CHR_F_READ_ENC)) { + NimBLEDevice::startSecurity(event->subscribe.conn_handle); } - it->setSubscribe(event, peerInfo); + chr->setSubscribe(event, peerInfo); break; } } - return 0; + break; } // BLE_GAP_EVENT_SUBSCRIBE case BLE_GAP_EVENT_MTU: { - NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", - event->mtu.conn_handle, - event->mtu.value); - - rc = ble_gap_conn_find(event->mtu.conn_handle, &peerInfo.m_desc); - if (rc != 0) { - return 0; + NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", event->mtu.conn_handle, event->mtu.value); + if (ble_gap_conn_find(event->mtu.conn_handle, &peerInfo.m_desc) == 0) { + pServer->m_pServerCallbacks->onMTUChange(event->mtu.value, peerInfo); } - pServer->m_pServerCallbacks->onMTUChange(event->mtu.value, peerInfo); - return 0; + break; } // BLE_GAP_EVENT_MTU case BLE_GAP_EVENT_NOTIFY_TX: { - NimBLECharacteristic *pChar = nullptr; + NimBLECharacteristic* pChar = nullptr; - for(auto &it : pServer->m_notifyChrVec) { - if(it->getHandle() == event->notify_tx.attr_handle) { - pChar = it; + for (auto& chr : pServer->m_notifyChrVec) { + if (chr->getHandle() == event->notify_tx.attr_handle) { + pChar = chr; } } - if(pChar == nullptr) { + if (pChar == nullptr) { return 0; } - if(event->notify_tx.indication) { - if(event->notify_tx.status == 0) { + if (event->notify_tx.indication) { + if (event->notify_tx.status == 0) { return 0; // Indication sent but not yet acknowledged. } pServer->clearIndicateWait(event->notify_tx.conn_handle); } pChar->m_pCallbacks->onStatus(pChar, event->notify_tx.status); - - return 0; + break; } // BLE_GAP_EVENT_NOTIFY_TX - - case BLE_GAP_EVENT_ADV_COMPLETE: -#if CONFIG_BT_NIMBLE_EXT_ADV - case BLE_GAP_EVENT_SCAN_REQ_RCVD: - return NimBLEExtAdvertising::handleGapEvent(event, arg); -#else + case BLE_GAP_EVENT_ADV_COMPLETE: { +# if CONFIG_BT_NIMBLE_EXT_ADV + case BLE_GAP_EVENT_SCAN_REQ_RCVD: + return NimBLEExtAdvertising::handleGapEvent(event, arg); +# else return NimBLEAdvertising::handleGapEvent(event, arg); -#endif - // BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD +# endif + } // BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD case BLE_GAP_EVENT_CONN_UPDATE: { - rc = ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc); - if (rc != 0) { - return 0; + if (ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc) == 0) { + pServer->m_pServerCallbacks->onConnParamsUpdate(peerInfo); } - pServer->m_pServerCallbacks->onConnParamsUpdate(peerInfo); - return 0; + break; } // BLE_GAP_EVENT_CONN_UPDATE case BLE_GAP_EVENT_REPEAT_PAIRING: { @@ -634,7 +599,7 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { /* Delete the old bond. */ rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &peerInfo.m_desc); - if (rc != 0){ + if (rc != 0) { return BLE_GAP_REPEAT_PAIRING_IGNORE; } @@ -648,53 +613,51 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { case BLE_GAP_EVENT_ENC_CHANGE: { rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc); - if(rc != 0) { + if (rc != 0) { return BLE_ATT_ERR_INVALID_HANDLE; } if (pServer->m_getPeerNameOnConnect) { - pServer->getPeerNameInternal(event->enc_change.conn_handle, - NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB); + pServer->getPeerNameImpl(event->enc_change.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB); } else { pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo); } - return 0; + + break; } // BLE_GAP_EVENT_ENC_CHANGE case BLE_GAP_EVENT_IDENTITY_RESOLVED: { rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &peerInfo.m_desc); - if(rc != 0) { + if (rc != 0) { return BLE_ATT_ERR_INVALID_HANDLE; } pServer->m_pServerCallbacks->onIdentity(peerInfo); - return 0; + break; } // 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) { + if (rc != 0) { return BLE_ATT_ERR_INVALID_HANDLE; } - pServer->m_pServerCallbacks->onPhyUpdate(peerInfo, - event->phy_updated.tx_phy, - event->phy_updated.rx_phy); + pServer->m_pServerCallbacks->onPhyUpdate(peerInfo, event->phy_updated.tx_phy, event->phy_updated.rx_phy); return 0; - } //BLE_GAP_EVENT_PHY_UPDATE_COMPLETE -#endif + } // BLE_GAP_EVENT_PHY_UPDATE_COMPLETE +# endif case BLE_GAP_EVENT_PASSKEY_ACTION: { - struct ble_sm_io pkey = {0,0}; + struct ble_sm_io pkey = {0, 0}; if (event->passkey.params.action == BLE_SM_IOACT_DISP) { - pkey.action = event->passkey.params.action; + pkey.action = event->passkey.params.action; // backward compatibility pkey.passkey = NimBLEDevice::getSecurityPasskey(); // This is the passkey to be entered on peer // if the (static)passkey is the default, check the callback for custom value // both values default to the same. - if(pkey.passkey == 123456) { + if (pkey.passkey == 123456) { pkey.passkey = pServer->m_pServerCallbacks->onPassKeyDisplay(); } rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); @@ -704,27 +667,25 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp); rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc); - if(rc != 0) { + if (rc != 0) { return BLE_ATT_ERR_INVALID_HANDLE; } pServer->m_pServerCallbacks->onConfirmPassKey(peerInfo, event->passkey.params.numcmp); - //TODO: Handle out of band pairing } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) { - static uint8_t tem_oob[16] = {0}; - pkey.action = event->passkey.params.action; - for (int i = 0; i < 16; i++) { - pkey.oob[i] = tem_oob[i]; - } - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc); - ////////////////////////////////// + // TODO: Handle out of band pairing + // static uint8_t tem_oob[16] = {0}; + // pkey.action = event->passkey.params.action; + // for (int i = 0; i < 16; i++) { + // pkey.oob[i] = tem_oob[i]; + // } + // rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); + // NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc); } else if (event->passkey.params.action == BLE_SM_IOACT_NONE) { NIMBLE_LOGD(LOG_TAG, "No passkey action required"); } - NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent"); - return 0; + break; } // BLE_GAP_EVENT_PASSKEY_ACTION default: @@ -735,27 +696,25 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { return 0; } // handleGapEvent - /** - * @brief STATIC callback to handle events from the NimBLE stack. + * @brief GATT event handler. */ -int NimBLEServer::handleGattEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) { - NIMBLE_LOGD(LOG_TAG, "Gatt %s event", (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR || - ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) ? "Read" : "Write"); - auto pAtt = static_cast(arg); - const auto& val = pAtt->getAttVal(); +int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg) { + NIMBLE_LOGD(LOG_TAG, + "Gatt %s event", + (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) ? "Read" : "Write"); + auto pAtt = static_cast(arg); + const auto& val = pAtt->getAttVal(); NimBLEConnInfo peerInfo{}; - ble_gap_conn_find(conn_handle, &peerInfo.m_desc); + ble_gap_conn_find(connHandle, &peerInfo.m_desc); - switch(ctxt->op) { + switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_DSC: case BLE_GATT_ACCESS_OP_READ_CHR: { // If the packet header is only 8 bytes this is a follow up of a long read // so we don't want to call the onRead() callback again. - if(ctxt->om->om_pkthdr_len > 8 || - conn_handle == BLE_HS_CONN_HANDLE_NONE || - val.size() <= (ble_att_mtu(conn_handle) - 3)) { + if (ctxt->om->om_pkthdr_len > 8 || connHandle == BLE_HS_CONN_HANDLE_NONE || + val.size() <= (ble_att_mtu(connHandle) - 3)) { pAtt->readEvent(peerInfo); } @@ -772,19 +731,19 @@ int NimBLEServer::handleGattEvent(uint16_t conn_handle, uint16_t attr_handle, return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - uint8_t buf[att_max_len]; + uint8_t buf[att_max_len]; uint16_t len = ctxt->om->om_len; - memcpy(buf, ctxt->om->om_data,len); + memcpy(buf, ctxt->om->om_data, len); - os_mbuf *next; + os_mbuf* next; next = SLIST_NEXT(ctxt->om, om_next); - while(next != NULL){ - if((len + next->om_len) > att_max_len) { + while (next != NULL) { + if ((len + next->om_len) > att_max_len) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } memcpy(&buf[len], next->om_data, next->om_len); - len += next->om_len; - next = SLIST_NEXT(next, om_next); + len += next->om_len; + next = SLIST_NEXT(next, om_next); } pAtt->writeEvent(buf, len, peerInfo); @@ -801,7 +760,7 @@ int NimBLEServer::handleGattEvent(uint16_t conn_handle, uint16_t attr_handle, /** * @brief Set the server callbacks. * - * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client + * As a BLE server operates, it will generate server level events such as a new client connecting or a previous client * disconnecting. This function can be called to register a callback handler that will be invoked when these * events are detected. * @@ -809,15 +768,15 @@ int NimBLEServer::handleGattEvent(uint16_t conn_handle, uint16_t attr_handle, * @param [in] deleteCallbacks if true callback class will be deleted when server is destructed. */ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks) { - if (pCallbacks != nullptr){ + if (pCallbacks != nullptr) { m_pServerCallbacks = pCallbacks; - m_deleteCallbacks = deleteCallbacks; + m_deleteCallbacks = deleteCallbacks; } else { m_pServerCallbacks = &defaultCallbacks; + m_deleteCallbacks = false; } } // setCallbacks - /** * @brief Remove a service from the server. * @@ -840,9 +799,9 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) { // Check if the service was already removed and if so check if this // is being called to delete the object and do so if requested. // Otherwise, ignore the call and return. - if(service->getRemoved() > 0) { - if(deleteSvc) { - for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) { + if (service->getRemoved() > 0) { + if (deleteSvc) { + for (auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) { if ((*it) == service) { delete *it; m_svcVec.erase(it); @@ -855,17 +814,16 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) { } int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0); - if(rc !=0) { + if (rc != 0) { return; } service->setRemoved(deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE); serviceChanged(); -#if !CONFIG_BT_NIMBLE_EXT_ADV +# if !CONFIG_BT_NIMBLE_EXT_ADV NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID()); -#endif -} - +# endif +} // removeService /** * @brief Adds a service which was either already created but removed from availability,\n @@ -876,14 +834,13 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) { */ void NimBLEServer::addService(NimBLEService* service) { // Check that a service with the supplied UUID does not already exist. - if(getServiceByUUID(service->getUUID()) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", - std::string(service->getUUID()).c_str()); + if (getServiceByUUID(service->getUUID()) != nullptr) { + NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", std::string(service->getUUID()).c_str()); } // If adding a service that was not removed add it and return. // Else reset GATT and send service changed notification. - if(service->getRemoved() == 0) { + if (service->getRemoved() == 0) { m_svcVec.push_back(service); return; } @@ -892,12 +849,11 @@ void NimBLEServer::addService(NimBLEService* service) { serviceChanged(); } - /** * @brief Resets the GATT server, used when services are added/removed after initialization. */ void NimBLEServer::resetGATT() { - if(getConnectedCount() > 0) { + if (getConnectedCount() > 0) { return; } @@ -906,7 +862,7 @@ void NimBLEServer::resetGATT() { ble_svc_gap_init(); ble_svc_gatt_init(); - for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) { + for (auto it = m_svcVec.begin(); it != m_svcVec.end();) { if ((*it)->getRemoved() > 0) { if ((*it)->getRemoved() == NIMBLE_ATT_REMOVE_DELETE) { delete *it; @@ -921,35 +877,31 @@ void NimBLEServer::resetGATT() { ++it; } - m_svcChanged = false; + m_svcChanged = false; m_gattsStarted = false; -} +} // resetGATT - -#if CONFIG_BT_NIMBLE_EXT_ADV +# if CONFIG_BT_NIMBLE_EXT_ADV /** * @brief Start advertising. - * @param [in] inst_id The extended advertisement instance ID to start. + * @param [in] instId The extended advertisement instance ID to start. * @param [in] duration How long to advertise for in milliseconds, 0 = forever (default). - * @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default). + * @param [in] maxEvents Maximum number of advertisement events to send, 0 = no limit (default). * @return True if advertising started successfully. * @details Start the server advertising its existence. This is a convenience function and is equivalent to * retrieving the advertising object and invoking start upon it. */ -bool NimBLEServer::startAdvertising(uint8_t inst_id, - int duration, - int max_events) { - return getAdvertising()->start(inst_id, duration, max_events); +bool NimBLEServer::startAdvertising(uint8_t instId, int duration, int maxEvents) const { + return getAdvertising()->start(instId, duration, maxEvents); } // startAdvertising - /** * @brief Convenience function to stop advertising a data set. - * @param [in] inst_id The extended advertisement instance ID to stop advertising. + * @param [in] instId The extended advertisement instance ID to stop advertising. * @return True if advertising stopped successfully. */ -bool NimBLEServer::stopAdvertising(uint8_t inst_id) { - return getAdvertising()->stop(inst_id); +bool NimBLEServer::stopAdvertising(uint8_t instId) const { + return getAdvertising()->stop(instId); } // stopAdvertising /** @@ -995,9 +947,9 @@ bool NimBLEServer::getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy) { return rc == 0; } // getPhy -#endif +# endif -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) +# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) /** * @brief Start advertising. * @param [in] duration The duration in milliseconds to advertise for, default = forever. @@ -1005,86 +957,78 @@ bool NimBLEServer::getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy) { * @details Start the server advertising its existence. This is a convenience function and is equivalent to * retrieving the advertising object and invoking start upon it. */ -bool NimBLEServer::startAdvertising(uint32_t duration) { +bool NimBLEServer::startAdvertising(uint32_t duration) const { return getAdvertising()->start(duration); } // startAdvertising -#endif - /** * @brief Stop advertising. * @return True if advertising stopped successfully. */ -bool NimBLEServer::stopAdvertising() { +bool NimBLEServer::stopAdvertising() const { return getAdvertising()->stop(); } // stopAdvertising - +# endif /** - * @brief Get the MTU of the client. - * @returns The client MTU or 0 if not found/connected. + * @brief Get the MTU value of a client connection. + * @param [in] connHandle The connection handle of the client to get the MTU value for. + * @returns The MTU or 0 if not found/connected. */ -uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) { - return ble_att_mtu(conn_id); -} //getPeerMTU - +uint16_t NimBLEServer::getPeerMTU(uint16_t connHandle) const { + return ble_att_mtu(connHandle); +} // getPeerMTU /** * @brief Request an Update the connection parameters: * * Can only be used after a connection has been established. - * @param [in] conn_handle The connection handle of the peer to send the request to. + * @param [in] connHandle The connection handle of the peer to send the request to. * @param [in] minInterval The minimum connection interval in 1.25ms units. * @param [in] maxInterval The maximum connection interval in 1.25ms units. * @param [in] latency The number of packets allowed to skip (extends max interval). * @param [in] timeout The timeout time in 10ms units before disconnecting. */ -void NimBLEServer::updateConnParams(uint16_t conn_handle, - uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout) -{ - ble_gap_upd_params params; +void NimBLEServer::updateConnParams( + uint16_t connHandle, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) const { + ble_gap_upd_params params = {.itvl_min = minInterval, + .itvl_max = maxInterval, + .latency = latency, + .supervision_timeout = timeout, + .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN, + .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN}; - params.latency = latency; - params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms - params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms - params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms - params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units - params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units - - int rc = ble_gap_update_params(conn_handle, ¶ms); - if(rc != 0) { + int rc = ble_gap_update_params(connHandle, ¶ms); + if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } } // updateConnParams - /** * @brief Request an update of the data packet length. * * Can only be used after a connection has been established. * @details Sends a data length update request to the peer. * The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes. * The peer needs to support the Bluetooth 4.2 specifications, to be capable of DLE. - * @param [in] conn_handle The connection handle of the peer to send the request to. - * @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB). + * @param [in] connHandle The connection handle of the peer to send the request to. + * @param [in] octets The preferred number of payload octets to use (Range 0x001B-0x00FB). */ -void NimBLEServer::setDataLen(uint16_t conn_handle, uint16_t tx_octets) { -#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \ - (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432 +void NimBLEServer::setDataLen(uint16_t connHandle, uint16_t octets) const { +# if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \ + (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432 return; -#else - uint16_t tx_time = (tx_octets + 14) * 8; +# else + uint16_t tx_time = (octets + 14) * 8; - int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time); - if(rc != 0) { + int rc = ble_gap_set_data_len(connHandle, octets, tx_time); + if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } -#endif +# endif } // setDataLen - -bool NimBLEServer::setIndicateWait(uint16_t conn_handle) { - for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { - if(m_indWait[i] == conn_handle) { +bool NimBLEServer::setIndicateWait(uint16_t connHandle) { + for (auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { + if (m_indWait[i] == connHandle) { return false; } } @@ -1092,17 +1036,15 @@ bool NimBLEServer::setIndicateWait(uint16_t conn_handle) { return true; } - -void NimBLEServer::clearIndicateWait(uint16_t conn_handle) { - for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { - if(m_indWait[i] == conn_handle) { +void NimBLEServer::clearIndicateWait(uint16_t connHandle) { + for (auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { + if (m_indWait[i] == connHandle) { m_indWait[i] = BLE_HS_CONN_HANDLE_NONE; return; } } } - /** Default callback handlers */ void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) { NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default"); @@ -1112,8 +1054,7 @@ void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& con NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default"); } // onConnect -void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, - NimBLEConnInfo& connInfo, int reason) { +void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) { NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default"); } // onDisconnect @@ -1121,29 +1062,29 @@ void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default"); } // onMTUChange -uint32_t NimBLEServerCallbacks::onPassKeyDisplay(){ +uint32_t NimBLEServerCallbacks::onPassKeyDisplay() { NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyDisplay: default: 123456"); return 123456; -} //onPassKeyDisplay +} // onPassKeyDisplay -void NimBLEServerCallbacks::onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pin){ +void NimBLEServerCallbacks::onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pin) { NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true"); NimBLEDevice::injectConfirmPasskey(connInfo, true); } // onConfirmPIN -void NimBLEServerCallbacks::onIdentity(NimBLEConnInfo& connInfo){ +void NimBLEServerCallbacks::onIdentity(NimBLEConnInfo& connInfo) { NIMBLE_LOGD("NimBLEServerCallbacks", "onIdentity: default"); } // onIdentity -void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo){ +void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) { NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default"); } // onAuthenticationComplete -void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo, const std::string& name){ +void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo, const std::string& name) { NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default"); } // onAuthenticationComplete -void NimBLEServerCallbacks::onConnParamsUpdate(NimBLEConnInfo& connInfo){ +void NimBLEServerCallbacks::onConnParamsUpdate(NimBLEConnInfo& connInfo) { NIMBLE_LOGD("NimBLEServerCallbacks", "onConnParamsUpdate: default"); } // onConnParamsUpdate diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h index 1417c30..d926e11 100644 --- a/src/NimBLEServer.h +++ b/src/NimBLEServer.h @@ -12,128 +12,127 @@ * Author: kolban */ -#ifndef MAIN_NIMBLESERVER_H_ -#define MAIN_NIMBLESERVER_H_ +#ifndef NIMBLE_CPP_SERVER_H_ +#define NIMBLE_CPP_SERVER_H_ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -class NimBLEServer; +# if defined(CONFIG_NIMBLE_CPP_IDF) +# include "host/ble_gap.h" +# else +# include "nimble/nimble/host/include/host/ble_gap.h" +# endif + +/**** FIX COMPILATION ****/ +# undef min +# undef max +/**************************/ + +# include +# include +# include + +# define NIMBLE_ATT_REMOVE_HIDE 1 +# define NIMBLE_ATT_REMOVE_DELETE 2 + +class NimBLEService; class NimBLEServerCallbacks; - -#include "NimBLEUtils.h" -#include "NimBLEAddress.h" -#if CONFIG_BT_NIMBLE_EXT_ADV -#include "NimBLEExtAdvertising.h" -#else -#include "NimBLEAdvertising.h" -#endif -#include "NimBLEService.h" -#include "NimBLECharacteristic.h" -#include "NimBLEConnInfo.h" - -#define NIMBLE_ATT_REMOVE_HIDE 1 -#define NIMBLE_ATT_REMOVE_DELETE 2 - -#define onMtuChanged onMTUChange +class NimBLEUUID; +class NimBLEConnInfo; +class NimBLEAddress; +class NimBLEService; +class NimBLECharacteristic; +# if CONFIG_BT_NIMBLE_EXT_ADV +class NimBLEExtAdvertising; +# else +class NimBLEAdvertising; +# endif /** - * @brief The model of a %BLE server. + * @brief The model of a BLE server. */ class NimBLEServer { -public: - size_t getConnectedCount(); - NimBLEService* createService(const char* uuid); - NimBLEService* createService(const NimBLEUUID &uuid); - void removeService(NimBLEService* service, bool deleteSvc = false); - void addService(NimBLEService* service); - void setCallbacks(NimBLEServerCallbacks* pCallbacks, - bool deleteCallbacks = true); -#if CONFIG_BT_NIMBLE_EXT_ADV - NimBLEExtAdvertising* getAdvertising(); - bool startAdvertising(uint8_t inst_id, - 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(); - bool startAdvertising(uint32_t duration = 0); -#endif - bool stopAdvertising(); - void start(); - NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0); - NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0); - NimBLEService* getServiceByHandle(uint16_t handle); - int disconnect(uint16_t connID, - uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); - int disconnect(const NimBLEConnInfo &connInfo, - uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); - void updateConnParams(uint16_t conn_handle, - uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout); - void setDataLen(uint16_t conn_handle, uint16_t tx_octets); - uint16_t getPeerMTU(uint16_t conn_id); - std::vector getPeerDevices(); - NimBLEConnInfo getPeerInfo(size_t index); - NimBLEConnInfo getPeerInfo(const NimBLEAddress& address); - NimBLEConnInfo getPeerIDInfo(uint16_t id); - std::string getPeerName(const NimBLEConnInfo& connInfo); - void getPeerNameOnConnect(bool enable); -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) - void advertiseOnDisconnect(bool); -#endif + public: + void start(); + uint8_t getConnectedCount() const; + bool disconnect(uint16_t connHandle, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const; + bool disconnect(const NimBLEConnInfo& connInfo, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const; + void setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks = true); + void updateConnParams(uint16_t connHandle, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) const; + NimBLEService* createService(const char* uuid); + NimBLEService* createService(const NimBLEUUID& uuid); + NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0) const; + NimBLEService* getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId = 0) const; + NimBLEService* getServiceByHandle(uint16_t handle) const; + void removeService(NimBLEService* service, bool deleteSvc = false); + void addService(NimBLEService* service); + uint16_t getPeerMTU(uint16_t connHandle) const; + std::vector getPeerDevices() const; + NimBLEConnInfo getPeerInfo(uint8_t index) const; + NimBLEConnInfo getPeerInfo(const NimBLEAddress& address) const; + NimBLEConnInfo getPeerInfoByHandle(uint16_t connHandle) const; + std::string getPeerName(const NimBLEConnInfo& connInfo) const; + void getPeerNameOnConnect(bool enable); + void advertiseOnDisconnect(bool enable); + void setDataLen(uint16_t connHandle, uint16_t tx_octets) const; + +# if CONFIG_BT_NIMBLE_EXT_ADV + NimBLEExtAdvertising* getAdvertising() const; + bool startAdvertising(uint8_t instanceId, int duration = 0, int maxEvents = 0) const; + bool stopAdvertising(uint8_t instanceId) const; + 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() const; + bool startAdvertising(uint32_t duration = 0) const; + bool stopAdvertising() const; +# endif + + private: + friend class NimBLEDevice; + friend class NimBLEService; + friend class NimBLECharacteristic; +# if CONFIG_BT_NIMBLE_EXT_ADV + friend class NimBLEExtAdvertising; +# else + friend class NimBLEAdvertising; +# endif -private: NimBLEServer(); ~NimBLEServer(); - friend class NimBLECharacteristic; - friend class NimBLEService; - friend class NimBLEDevice; - friend class NimBLEAdvertising; -#if CONFIG_BT_NIMBLE_EXT_ADV - friend class NimBLEExtAdvertising; - friend class NimBLEExtAdvertisementData; -#endif - bool m_gattsStarted; -#if !CONFIG_BT_NIMBLE_EXT_ADV - bool m_advertiseOnDisconnect; -#endif - bool m_getPeerNameOnConnect; - bool m_svcChanged; - NimBLEServerCallbacks* m_pServerCallbacks; - bool m_deleteCallbacks; - uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS]; - std::vector m_connectedPeersVec; + bool m_gattsStarted : 1; + bool m_getPeerNameOnConnect : 1; + bool m_svcChanged : 1; + bool m_deleteCallbacks : 1; +# if !CONFIG_BT_NIMBLE_EXT_ADV + bool m_advertiseOnDisconnect : 1; +# endif + NimBLEServerCallbacks* m_pServerCallbacks; + std::vector m_svcVec; + std::vector m_notifyChrVec; + std::array m_connectedPeers; + std::array m_indWait; -// uint16_t m_svcChgChrHdl; // Future use - - std::vector m_svcVec; - std::vector m_notifyChrVec; - - static int handleGapEvent(struct ble_gap_event *event, void *arg); - static int peerNameCB(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg); - std::string getPeerNameInternal(uint16_t conn_handle, int cb_type = -1); - void serviceChanged(); - void resetGATT(); - bool setIndicateWait(uint16_t conn_handle); - void clearIndicateWait(uint16_t conn_handle); - - static int handleGattEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg); + static int handleGapEvent(struct ble_gap_event* event, void* arg); + static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg); + static int peerNameCB(uint16_t connHandle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg); + std::string getPeerNameImpl(uint16_t connHandle, int cb_type = -1) const; + void serviceChanged(); + void resetGATT(); + bool setIndicateWait(uint16_t connHandle); + void clearIndicateWait(uint16_t connHandle); }; // NimBLEServer - /** * @brief Callbacks associated with the operation of a %BLE server. */ class NimBLEServerCallbacks { -public: + public: virtual ~NimBLEServerCallbacks() {}; /** @@ -232,5 +231,5 @@ public: # endif }; // NimBLEServerCallbacks -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ -#endif /* MAIN_NIMBLESERVER_H_ */ +#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL +#endif // NIMBLE_CPP_SERVER_H_ diff --git a/src/NimBLEService.cpp b/src/NimBLEService.cpp index 1f73a24..a0b9601 100644 --- a/src/NimBLEService.cpp +++ b/src/NimBLEService.cpp @@ -17,8 +17,13 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -# include "NimBLEDevice.h" # include "NimBLEService.h" +# if CONFIG_BT_NIMBLE_EXT_ADV +# include "NimBLEExtAdvertising.h" +# else +# include "NimBLEAdvertising.h" +# endif +# include "NimBLEDevice.h" # include "NimBLEUtils.h" # include "NimBLELog.h"