diff --git a/docs/Migration_guide.md b/docs/Migration_guide.md index ee06ca7c..a0e4670e 100644 --- a/docs/Migration_guide.md +++ b/docs/Migration_guide.md @@ -383,7 +383,7 @@ The security callback methods are now incorporated in the `NimBLEServerCallbacks The callback methods are: -> `bool onConfirmPIN(NimBLEConnInfo& connInfo, uint32_t pin)` +> `bool onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin)` Receives the pin when using numeric comparison authentication. Call `NimBLEDevice::injectConfirmPasskey(connInfo, true);` to accept or `NimBLEDevice::injectConfirmPasskey(connInfo, false);` to reject. diff --git a/examples/NimBLE_Client/NimBLE_Client.ino b/examples/NimBLE_Client/NimBLE_Client.ino index 384eb953..6c65649c 100644 --- a/examples/NimBLE_Client/NimBLE_Client.ino +++ b/examples/NimBLE_Client/NimBLE_Client.ino @@ -64,7 +64,7 @@ class ClientCallbacks : public NimBLEClientCallbacks { NimBLEDevice::injectPassKey(connInfo, 123456); }; - void onConfirmPIN(NimBLEConnInfo& connInfo, uint32_t pass_key){ + void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key){ Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); /** Inject false if passkeys don't match. */ NimBLEDevice::injectConfirmPasskey(connInfo, true); diff --git a/examples/NimBLE_Server/NimBLE_Server.ino b/examples/NimBLE_Server/NimBLE_Server.ino index 0ee94301..46af2dce 100644 --- a/examples/NimBLE_Server/NimBLE_Server.ino +++ b/examples/NimBLE_Server/NimBLE_Server.ino @@ -45,7 +45,7 @@ class ServerCallbacks: public NimBLEServerCallbacks { return 123456; }; - void onConfirmPIN(NimBLEConnInfo& connInfo, uint32_t pass_key) { + void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key) { Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); /** Inject false if passkeys don't match. */ NimBLEDevice::injectConfirmPasskey(connInfo, true); diff --git a/examples/Refactored_original_examples/BLE_client/BLE_client.ino b/examples/Refactored_original_examples/BLE_client/BLE_client.ino index e71114d6..c6b0720c 100644 --- a/examples/Refactored_original_examples/BLE_client/BLE_client.ino +++ b/examples/Refactored_original_examples/BLE_client/BLE_client.ino @@ -56,7 +56,7 @@ class MyClientCallback : public BLEClientCallbacks { NimBLEDevice::injectPassKey(connInfo, 123456); } - void onConfirmPIN(const BLEConnInfo& connInfo, uint32_t pass_key) { + void onConfirmPasskey(const BLEConnInfo& connInfo, uint32_t pass_key) { Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); NimBLEDevice::injectConfirmPasskey(connInfo, true); } diff --git a/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino b/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino index 6250c275..6c529c5e 100644 --- a/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino +++ b/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino @@ -62,7 +62,7 @@ class MyServerCallbacks: public BLEServerCallbacks { return 123456; } - void onConfirmPIN(const BLEConnInfo& connInfo, uint32_t pass_key) { + void onConfirmPasskey(const BLEConnInfo& connInfo, uint32_t pass_key) { Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); /** Inject false if passkeys don't match. */ NimBLEDevice::injectConfirmPasskey(connInfo, true); diff --git a/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino b/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino index 43c31899..f1914ae5 100644 --- a/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino +++ b/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino @@ -64,7 +64,7 @@ class MyServerCallbacks: public BLEServerCallbacks { return 123456; } - void onConfirmPIN(const BLEConnInfo& connInfo, uint32_t pass_key) { + void onConfirmPasskey(const BLEConnInfo& connInfo, uint32_t pass_key) { Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); /** Inject false if passkeys don't match. */ NimBLEDevice::injectConfirmPasskey(connInfo, true); diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index e8740400..840137ad 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -14,23 +14,21 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) -#include "NimBLEClient.h" -#include "NimBLERemoteService.h" -#include "NimBLERemoteCharacteristic.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" - -#include -#include -#include - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "nimble/nimble_port.h" -#else -#include "nimble/porting/nimble/include/nimble/nimble_port.h" -#endif - -static const char* LOG_TAG = "NimBLEClient"; +# include "NimBLEClient.h" +# include "NimBLERemoteService.h" +# include "NimBLERemoteCharacteristic.h" +# include "NimBLEDevice.h" +# include "NimBLELog.h" + +# if defined(CONFIG_NIMBLE_CPP_IDF) +# include "nimble/nimble_port.h" +# else +# include "nimble/porting/nimble/include/nimble/nimble_port.h" +# endif + +# include + +static const char* LOG_TAG = "NimBLEClient"; static NimBLEClientCallbacks defaultCallbacks; /* @@ -46,48 +44,40 @@ static NimBLEClientCallbacks defaultCallbacks; * * NimBLERemoteDescriptor - A model of a remote descriptor. * * Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own - * zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors. + * zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more NimBLERemoteDescriptors. * * We will assume that a NimBLERemoteService contains a vector of owned characteristics - * and that a NimBLECharacteristic contains a vector of owned descriptors. - * - * + * and that a NimBLERemoteCharacteristic contains a vector of owned descriptors. */ - /** * @brief Constructor, private - only callable by NimBLEDevice::createClient * to ensure proper handling of the list of client objects. */ -NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(peerAddress) { - m_pClientCallbacks = &defaultCallbacks; - m_conn_id = BLE_HS_CONN_HANDLE_NONE; - m_connectTimeout = 30000; - m_deleteCallbacks = false; - m_pTaskData = nullptr; - m_connEstablished = false; - m_lastErr = 0; -#if CONFIG_BT_NIMBLE_EXT_ADV - m_phyMask = BLE_GAP_LE_PHY_1M_MASK | - BLE_GAP_LE_PHY_2M_MASK | - BLE_GAP_LE_PHY_CODED_MASK; -#endif - - m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default) - m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default) - m_pConnParams.itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; // min_int = 0x10*1.25ms = 20ms - m_pConnParams.itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; // max_int = 0x20*1.25ms = 40ms - m_pConnParams.latency = BLE_GAP_INITIAL_CONN_LATENCY; // number of packets allowed to skip (extends max interval) - m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms - m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units - m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units - - memset(&m_dcTimer, 0, sizeof(m_dcTimer)); - ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(), - NimBLEClient::dcTimerCb, this); +NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress) + : m_peerAddress(peerAddress), + m_lastErr{0}, + m_connectTimeout{30000}, + m_pTaskData{nullptr}, + m_svcVec{}, + m_pClientCallbacks{&defaultCallbacks}, + m_connHandle{BLE_HS_CONN_HANDLE_NONE}, + m_terminateFailCount{0}, + m_deleteCallbacks{false}, + m_connEstablished{false}, +# if CONFIG_BT_NIMBLE_EXT_ADV + m_phyMask{BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK}, +# endif + m_connParams{16, + 16, + BLE_GAP_INITIAL_CONN_ITVL_MIN, + BLE_GAP_INITIAL_CONN_ITVL_MAX, + BLE_GAP_INITIAL_CONN_LATENCY, + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT, + BLE_GAP_INITIAL_CONN_MIN_CE_LEN, + BLE_GAP_INITIAL_CONN_MAX_CE_LEN} { } // NimBLEClient - /** * @brief Destructor, private - only callable by NimBLEDevice::deleteClient * to ensure proper disconnect and removal from device list. @@ -97,66 +87,41 @@ NimBLEClient::~NimBLEClient() { // Before we are finished with the client, we must release resources. deleteServices(); - if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) { + if (m_deleteCallbacks) { delete m_pClientCallbacks; } - - ble_npl_callout_deinit(&m_dcTimer); - } // ~NimBLEClient - -/** - * @brief If we have asked to disconnect and the event does not - * occur within the supervision timeout + added delay, this will - * be called to reset the host in the case of a stalled controller. - */ -void NimBLEClient::dcTimerCb(ble_npl_event *event) { - /* NimBLEClient *pClient = (NimBLEClient*)event->arg; - NIMBLE_LOGE(LOG_TAG, "Timed out disconnecting from %s - resetting host", - std::string(pClient->getPeerAddress()).c_str()); - */ - ble_hs_sched_reset(BLE_HS_ECONTROLLER); -} - - /** * @brief Delete all service objects created by this client and clear the vector. */ void NimBLEClient::deleteServices() { - NIMBLE_LOGD(LOG_TAG, ">> deleteServices"); // Delete all the services. - for(auto &it: m_servicesVector) { + for (auto& it : m_svcVec) { delete it; } - m_servicesVector.clear(); - NIMBLE_LOGD(LOG_TAG, "<< deleteServices"); + std::vector().swap(m_svcVec); } // deleteServices - /** - * @brief Delete service by UUID - * @param [in] uuid The UUID of the service to be deleted from the local database. + * @brief Delete a service by UUID from the local database to free resources. + * @param [in] uuid The UUID of the service to be deleted. * @return Number of services left. */ -size_t NimBLEClient::deleteService(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> deleteService"); +size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) { // Delete the requested service. - for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) { - if((*it)->getUUID() == uuid) { + for (auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) { + if ((*it)->getUUID() == uuid) { delete *it; - m_servicesVector.erase(it); + m_svcVec.erase(it); break; } } - NIMBLE_LOGD(LOG_TAG, "<< deleteService"); - - return m_servicesVector.size(); + return m_svcVec.size(); } // deleteServices - /** * @brief Connect to the BLE Server. * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n @@ -179,36 +144,33 @@ bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttributes return connect(address, deleteAttributes); } - /** - * @brief Connect to the BLE Server. + * @brief Connect to a BLE Server by address. * @param [in] address The address of the server. * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n * have created and clears the vectors after successful connection. * @return True on success. */ -bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) { +bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes) { NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); - if(!NimBLEDevice::m_synced) { + if (!NimBLEDevice::m_synced) { NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync."); return false; } - if(isConnected() || m_connEstablished || m_pTaskData != nullptr) { - NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d", - std::string(m_peerAddress).c_str(), getConnId()); + if (isConnected() || m_connEstablished || m_pTaskData != nullptr) { + NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, handle=%d", std::string(m_peerAddress).c_str(), getConnHandle()); return false; } const ble_addr_t* peerAddr = address.getBase(); - if(ble_gap_conn_find_by_addr(peerAddr, NULL) == 0) { - NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists", - address.toString().c_str()); + if (ble_gap_conn_find_by_addr(peerAddr, NULL) == 0) { + NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists", address.toString().c_str()); return false; } - if(address.isNull()) { + if (address.isNull()) { NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)"); return false; } else { @@ -216,31 +178,30 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) } TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - m_pTaskData = &taskData; - int rc = 0; - - /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for - * timeout (default value of m_connectTimeout). - * Loop on BLE_HS_EBUSY if the scan hasn't stopped yet. - */ + BleTaskData taskData = {this, cur_task, 0, nullptr}; + m_pTaskData = &taskData; + int rc = 0; + do { -#if CONFIG_BT_NIMBLE_EXT_ADV +# if CONFIG_BT_NIMBLE_EXT_ADV rc = ble_gap_ext_connect(NimBLEDevice::m_ownAddrType, peerAddr, m_connectTimeout, m_phyMask, - &m_pConnParams, - &m_pConnParams, - &m_pConnParams, + &m_connParams, + &m_connParams, + &m_connParams, NimBLEClient::handleGapEvent, this); -#else - rc = ble_gap_connect(NimBLEDevice::m_ownAddrType, peerAddr, - m_connectTimeout, &m_pConnParams, - NimBLEClient::handleGapEvent, this); -#endif +# else + rc = ble_gap_connect(NimBLEDevice::m_ownAddrType, + peerAddr, + m_connectTimeout, + &m_connParams, + NimBLEClient::handleGapEvent, + this); +# endif switch (rc) { case 0: break; @@ -254,22 +215,22 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) case BLE_HS_EDONE: // A connection to this device already exists, do not connect twice. - NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s", - std::string(m_peerAddress).c_str()); + NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s", std::string(m_peerAddress).c_str()); break; case BLE_HS_EALREADY: // Already attempting to connect to this device, cancel the previous // attempt and report failure here so we don't get 2 connections. - NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling", - std::string(m_peerAddress).c_str()); + NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling", std::string(m_peerAddress).c_str()); ble_gap_conn_cancel(); break; default: - NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s", + NIMBLE_LOGE(LOG_TAG, + "Failed to connect to %s, rc=%d; %s", std::string(m_peerAddress).c_str(), - rc, NimBLEUtils::returnCodeToString(rc)); + rc, + NimBLEUtils::returnCodeToString(rc)); break; } @@ -277,39 +238,36 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) m_lastErr = rc; - if(rc != 0) { + if (rc != 0) { m_pTaskData = nullptr; return false; } -#ifdef ulTaskNotifyValueClear +# ifdef ulTaskNotifyValueClear // Clear the task notification value to ensure we block ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif +# endif // Wait for the connect timeout time +1 second for the connection to complete - if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) { + if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) { m_pTaskData = nullptr; // If a connection was made but no response from MTU exchange; disconnect - if(isConnected()) { + if (isConnected()) { NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response"); disconnect(); } else { - // workaround; if the controller doesn't cancel the connection - // at the timeout, cancel it here. + // workaround; if the controller doesn't cancel the connection + // at the timeout, cancel it here. NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling"); ble_gap_conn_cancel(); } return false; - } else if(taskData.rc != 0){ + } else if (taskData.rc != 0) { m_lastErr = taskData.rc; - NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", - taskData.rc, - NimBLEUtils::returnCodeToString(taskData.rc)); - // If the failure was not a result of a disconnection - // make sure we disconnect now to avoid dangling connections - if(isConnected()) { + NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", taskData.rc, NimBLEUtils::returnCodeToString(taskData.rc)); + // If the failure was not a result of a disconnection, make sure we disconnect now to avoid dangling connections + if (isConnected()) { disconnect(); } return false; @@ -317,7 +275,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) NIMBLE_LOGI(LOG_TAG, "Connection established"); } - if(deleteAttributes) { + if (deleteAttributes) { deleteServices(); } @@ -329,37 +287,36 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) return isConnected(); } // connect - /** * @brief Initiate a secure connection (pair/bond) with the server.\n * Called automatically when a characteristic or descriptor requires encryption or authentication to access it. * @return True on success. + * @details This is a blocking function and should not be used in a callback. */ bool NimBLEClient::secureConnection() const { NIMBLE_LOGD(LOG_TAG, ">> secureConnection()"); - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {const_cast(this), cur_task, 0, nullptr}; - - int retryCount = 1; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; + int retryCount = 1; do { m_pTaskData = &taskData; - int rc = NimBLEDevice::startSecurity(m_conn_id); - if(rc != 0 && rc != BLE_HS_EALREADY){ - m_lastErr = rc; + int rc = NimBLEDevice::startSecurity(m_connHandle); + if (rc != 0 && rc != BLE_HS_EALREADY) { + m_lastErr = rc; m_pTaskData = nullptr; return false; } -#ifdef ulTaskNotifyValueClear +# ifdef ulTaskNotifyValueClear // Clear the task notification value to ensure we block ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif +# endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); } while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); - if(taskData.rc != 0){ + if (taskData.rc != 0) { m_lastErr = taskData.rc; NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc); return false; @@ -369,56 +326,22 @@ bool NimBLEClient::secureConnection() const { return true; } // secureConnection - /** * @brief Disconnect from the peer. - * @return Error code from NimBLE stack, 0 = success. + * @return True if the command was successfully sent. */ -int NimBLEClient::disconnect(uint8_t reason) { - NIMBLE_LOGD(LOG_TAG, ">> disconnect()"); - int rc = 0; - if(isConnected()) { - // If the timer was already started, ignore this call. - if(ble_npl_callout_is_active(&m_dcTimer)) { - NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started"); - return BLE_HS_EALREADY; - } - - ble_gap_conn_desc desc; - if(ble_gap_conn_find(m_conn_id, &desc) != 0){ - NIMBLE_LOGI(LOG_TAG, "Connection ID not found"); - return BLE_HS_EALREADY; - } - - // We use a timer to detect a controller error in the event that it does - // not inform the stack when disconnection is complete. - // This is a common error in certain esp-idf versions. - // The disconnect timeout time is the supervision timeout time + 1 second. - // In the case that the event happens shortly after the supervision timeout - // we don't want to prematurely reset the host. - ble_npl_time_t ticks; - ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks); - ble_npl_callout_reset(&m_dcTimer, ticks); - - rc = ble_gap_terminate(m_conn_id, reason); - if (rc != 0) { - if(rc != BLE_HS_EALREADY) { - ble_npl_callout_stop(&m_dcTimer); - } - NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - } - } else { - NIMBLE_LOGD(LOG_TAG, "Not connected to any peers"); +bool NimBLEClient::disconnect(uint8_t reason) { + int rc = ble_gap_terminate(m_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)); + m_lastErr = rc; + return false; } - NIMBLE_LOGD(LOG_TAG, "<< disconnect()"); - m_lastErr = rc; - return rc; + return true; } // disconnect - -#if CONFIG_BT_NIMBLE_EXT_ADV +# if CONFIG_BT_NIMBLE_EXT_ADV /** * @brief Set the PHY types to use when connecting to a server. * @param [in] mask A bitmask indicating what PHYS to connect with.\n @@ -430,8 +353,7 @@ int NimBLEClient::disconnect(uint8_t reason) { void NimBLEClient::setConnectPhy(uint8_t mask) { m_phyMask = mask; } -#endif - +# endif /** * @brief Set the connection parameters to use when connecting to a server. @@ -442,25 +364,22 @@ void NimBLEClient::setConnectPhy(uint8_t mask) { * @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units. * @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units. */ -void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout, - uint16_t scanInterval, uint16_t scanWindow)/*, - uint16_t minConnTime, uint16_t maxConnTime)*/ +void NimBLEClient::setConnectionParams( + uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout, uint16_t scanInterval, uint16_t scanWindow) +/*, uint16_t minConnEvtTime, uint16_t maxConnEvtTime)*/ { - - m_pConnParams.scan_itvl = scanInterval; - m_pConnParams.scan_window = scanWindow; - m_pConnParams.itvl_min = minInterval; - m_pConnParams.itvl_max = maxInterval; - m_pConnParams.latency = latency; - m_pConnParams.supervision_timeout = timeout; + m_connParams.itvl_min = minInterval; + m_connParams.itvl_max = maxInterval; + m_connParams.latency = latency; + m_connParams.supervision_timeout = timeout; + m_connParams.scan_itvl = scanInterval; + m_connParams.scan_window = scanWindow; // These are not used by NimBLE at this time - Must leave at defaults - //m_pConnParams->min_ce_len = minConnTime; // Minimum length of connection event in 0.625ms units - //m_pConnParams->max_ce_len = maxConnTime; // Maximum length of connection event in 0.625ms units + // m_connParams.min_ce_len = minConnEvtTime; // Minimum length of connection event in 0.625ms units + // m_connParams.max_ce_len = maxConnEvtTime; // Maximum length of connection event in 0.625ms units } // setConnectionParams - /** * @brief Update the connection parameters: * * Can only be used after a connection has been established. @@ -469,26 +388,23 @@ void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterva * @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 NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout) -{ - ble_gap_upd_params params; - - params.latency = latency; - params.itvl_max = maxInterval; - params.itvl_min = minInterval; - params.supervision_timeout = timeout; - // These are not used by NimBLE at this time - Must leave at defaults - params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; - params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; - - int rc = ble_gap_update_params(m_conn_id, ¶ms); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); +bool NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) { + ble_gap_upd_params params{.itvl_min = minInterval, + .itvl_max = maxInterval, + .latency = latency, + .supervision_timeout = timeout, + // These are not used by NimBLE at this time - leave at defaults + .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN, + .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN}; + + int rc = ble_gap_update_params(m_connHandle, ¶ms); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); + m_lastErr = rc; } -} // updateConnParams + return rc == 0; +} // updateConnParams /** * @brief Request an update of the data packet length. @@ -496,68 +412,62 @@ void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval, * @details Sends a data length update request to the server the client is connected to. * The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes. * The server needs to support the Bluetooth 4.2 specifications, to be capable of DLE. - * @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB). + * @param [in] txOctets The preferred number of payload octets to use (Range 0x001B-0x00FB). */ -void NimBLEClient::setDataLen(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 - return; -#else - uint16_t tx_time = (tx_octets + 14) * 8; - - int rc = ble_gap_set_data_len(m_conn_id, tx_octets, tx_time); - if(rc != 0) { +bool NimBLEClient::setDataLen(uint16_t txOctets) { +# 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 false; +# else + uint16_t txTime = (txOctets + 14) * 8; + int rc = ble_gap_set_data_len(m_connHandle, txOctets, txTime); + if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } -#endif -} // setDataLen + return rc == 0; +# endif +} // setDataLen /** * @brief Get detailed information about the current peer connection. + * @return A NimBLEConnInfo instance with the data, or a NULL instance if not found. */ -NimBLEConnInfo NimBLEClient::getConnInfo() { - NimBLEConnInfo connInfo; - if (!isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Not connected"); - } else { - int rc = ble_gap_conn_find(m_conn_id, &connInfo.m_desc); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Connection info not found"); - } +NimBLEConnInfo NimBLEClient::getConnInfo() const { + NimBLEConnInfo connInfo{}; + if (ble_gap_conn_find(m_connHandle, &connInfo.m_desc) != 0) { + NIMBLE_LOGE(LOG_TAG, "Connection info not found"); } return connInfo; } // getConnInfo - /** * @brief Set the timeout to wait for connection attempt to complete. - * @param [in] time The number of milliseconds before timeout. + * @param [in] time The number of milliseconds before timeout, default is 30 seconds. */ void NimBLEClient::setConnectTimeout(uint32_t time) { m_connectTimeout = time; } // setConnectTimeout - /** - * @brief Get the connection id for this client. - * @return The connection id. + * @brief Get the connection handle for this client. + * @return The connection handle. */ -uint16_t NimBLEClient::getConnId() const { - return m_conn_id; -} // getConnId +uint16_t NimBLEClient::getConnHandle() const { + return m_connHandle; +} // getConnHandle /** * @brief Clear the connection information for this client. * @note This is designed to be used to reset the connection information after - * calling setConnection(), and should not be used to disconnect from a - * peer. To disconnect from a peer, use disconnect(). + * calling setConnection(), and should not be used to disconnect from a peer. + * To disconnect from a peer, use disconnect(). */ void NimBLEClient::clearConnection() { - m_conn_id = BLE_HS_CONN_HANDLE_NONE; + m_connHandle = BLE_HS_CONN_HANDLE_NONE; m_connEstablished = false; - m_peerAddress = NimBLEAddress{}; + m_peerAddress = NimBLEAddress{}; } // clearConnection /** @@ -567,19 +477,18 @@ void NimBLEClient::clearConnection() { * @note Sets the connection established flag to true. * @note If the client is already connected to a peer, this will return false. * @note This is designed to be used when a connection is made outside of the - * NimBLEClient class, such as when a connection is made by the - * NimBLEServer class and the client is passed the connection id. This use - * enables the GATT Server to read the name of the device that has - * connected to it. + * NimBLEClient class, such as when a connection is made by the + * NimBLEServer class and the client is passed the connection info. + * This enables the GATT Server to read the attributes of the client connected to it. */ -bool NimBLEClient::setConnection(NimBLEConnInfo &connInfo) { +bool NimBLEClient::setConnection(const NimBLEConnInfo& connInfo) { if (isConnected() || m_connEstablished) { NIMBLE_LOGE(LOG_TAG, "Already connected"); return false; } - m_peerAddress = connInfo.getAddress(); - m_conn_id = connInfo.getConnHandle(); + m_peerAddress = connInfo.getAddress(); + m_connHandle = connInfo.getConnHandle(); m_connEstablished = true; return true; @@ -587,20 +496,19 @@ bool NimBLEClient::setConnection(NimBLEConnInfo &connInfo) { /** * @brief Set the connection information for this client. - * @param [in] conn_id The connection id. + * @param [in] connHandle The connection handle. * @note Sets the connection established flag to true. * @note This is designed to be used when a connection is made outside of the - * NimBLEClient class, such as when a connection is made by the - * NimBLEServer class and the client is passed the connection id. This use - * enables the GATT Server to read the name of the device that has - * connected to it. + * NimBLEClient class, such as when a connection is made by the + * NimBLEServer class and the client is passed the connection handle. + * This enables the GATT Server to read the attributes of the client connected to it. * @note If the client is already connected to a peer, this will return false. - * @note This will look up the peer address using the connection id. + * @note This will look up the peer address using the connection handle. */ -bool NimBLEClient::setConnection(uint16_t conn_id) { +bool NimBLEClient::setConnection(uint16_t connHandle) { // we weren't provided the peer address, look it up using ble_gap_conn_find NimBLEConnInfo connInfo; - int rc = ble_gap_conn_find(m_conn_id, &connInfo.m_desc); + int rc = ble_gap_conn_find(connHandle, &connInfo.m_desc); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Connection info not found"); return false; @@ -611,70 +519,64 @@ bool NimBLEClient::setConnection(uint16_t conn_id) { /** * @brief Retrieve the address of the peer. + * @return A NimBLEAddress instance with the peer address data. */ NimBLEAddress NimBLEClient::getPeerAddress() const { return m_peerAddress; } // getPeerAddress - /** * @brief Set the peer address. - * @param [in] address The address of the peer that this client is - * connected or should connect to. + * @param [in] address The address of the peer that this client is connected or should connect to. + * @return True if successful. */ -void NimBLEClient::setPeerAddress(const NimBLEAddress &address) { - if(isConnected()) { +bool NimBLEClient::setPeerAddress(const NimBLEAddress& address) { + if (isConnected()) { NIMBLE_LOGE(LOG_TAG, "Cannot set peer address while connected"); - return; + return false; } m_peerAddress = address; - NIMBLE_LOGD(LOG_TAG, "Peer address set: %s", std::string(m_peerAddress).c_str()); + return true; } // setPeerAddress - /** * @brief Ask the BLE server for the RSSI value. - * @return The RSSI value. + * @return The RSSI value or 0 if there was an error. */ -int NimBLEClient::getRssi() { - NIMBLE_LOGD(LOG_TAG, ">> getRssi()"); +int NimBLEClient::getRssi() const { if (!isConnected()) { - NIMBLE_LOGE(LOG_TAG, "<< getRssi(): Not connected"); + NIMBLE_LOGE(LOG_TAG, "getRssi(): Not connected"); return 0; } - int8_t rssiValue = 0; - int rc = ble_gap_conn_rssi(m_conn_id, &rssiValue); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); + int8_t rssi = 0; + int rc = ble_gap_conn_rssi(m_connHandle, &rssi); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); m_lastErr = rc; return 0; } - return rssiValue; + return rssi; } // getRssi - /** * @brief Get iterator to the beginning of the vector of remote service pointers. * @return An iterator to the beginning of the vector of remote service pointers. */ std::vector::iterator NimBLEClient::begin() { - return m_servicesVector.begin(); + return m_svcVec.begin(); } - /** * @brief Get iterator to the end of the vector of remote service pointers. * @return An iterator to the end of the vector of remote service pointers. */ std::vector::iterator NimBLEClient::end() { - return m_servicesVector.end(); + return m_svcVec.end(); } - /** * @brief Get the service BLE Remote Service instance corresponding to the uuid. * @param [in] uuid The UUID of the service being sought. @@ -684,38 +586,35 @@ NimBLERemoteService* NimBLEClient::getService(const char* uuid) { return getService(NimBLEUUID(uuid)); } // getService - /** * @brief Get the service object corresponding to the uuid. * @param [in] uuid The UUID of the service being sought. * @return A pointer to the service or nullptr if not found. */ -NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) { +NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID& uuid) { NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str()); - for(auto &it: m_servicesVector) { - if(it->getUUID() == uuid) { + for (auto& it : m_svcVec) { + if (it->getUUID() == uuid) { NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); return it; } } - size_t prev_size = m_servicesVector.size(); - if(retrieveServices(&uuid)) { - if(m_servicesVector.size() > prev_size) { - return m_servicesVector.back(); + size_t prevSize = m_svcVec.size(); + if (retrieveServices(&uuid)) { + if (m_svcVec.size() > prevSize) { + return m_svcVec.back(); } // If the request was successful but 16/32 bit uuid not found // try again with the 128 bit uuid. - if(uuid.bitSize() == BLE_UUID_TYPE_16 || - uuid.bitSize() == BLE_UUID_TYPE_32) - { + if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) { NimBLEUUID uuid128(uuid); uuid128.to128(); - if(retrieveServices(&uuid128)) { - if(m_servicesVector.size() > prev_size) { - return m_servicesVector.back(); + if (retrieveServices(&uuid128)) { + if (m_svcVec.size() > prevSize) { + return m_svcVec.back(); } } } else { @@ -725,9 +624,9 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) { uuid16.to16(); // if the uuid was 128 bit but not of the BLE base type this check will fail if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if(retrieveServices(&uuid16)) { - if(m_servicesVector.size() > prev_size) { - return m_servicesVector.back(); + if (retrieveServices(&uuid16)) { + if (m_svcVec.size() > prevSize) { + return m_svcVec.back(); } } } @@ -738,7 +637,6 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) { return nullptr; } // getService - /** * @brief Get a pointer to the vector of found services. * @param [in] refresh If true the current services vector will be cleared and\n @@ -746,20 +644,18 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) { * If false the vector will be returned with the currently stored services. * @return A pointer to the vector of available services. */ -std::vector* NimBLEClient::getServices(bool refresh) { - if(refresh) { +const std::vector& NimBLEClient::getServices(bool refresh) { + if (refresh) { deleteServices(); - if (!retrieveServices()) { NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services"); - } - else{ - NIMBLE_LOGI(LOG_TAG, "Found %d services", m_servicesVector.size()); + } else { + NIMBLE_LOGI(LOG_TAG, "Found %d services", m_svcVec.size()); } } - return &m_servicesVector; -} // getServices + return m_svcVec; +} // getServices /** * @brief Retrieves the full database of attributes that the peripheral has available. @@ -767,18 +663,16 @@ std::vector* NimBLEClient::getServices(bool refresh) { */ bool NimBLEClient::discoverAttributes() { deleteServices(); - - if (!retrieveServices()){ + if (!retrieveServices()) { return false; } - - for(auto svc: m_servicesVector) { + for (auto svc : m_svcVec) { if (!svc->retrieveCharacteristics()) { return false; } - for(auto chr: svc->m_vChars) { + for (auto chr : svc->m_vChars) { if (!chr->retrieveDescriptors()) { return false; } @@ -788,36 +682,25 @@ bool NimBLEClient::discoverAttributes() { return true; } // discoverAttributes - /** - * @brief Ask the remote %BLE server for its services.\n - * Here we ask the server for its set of services and wait until we have received them all. + * @brief Ask the remote BLE server for its services. + * * Here we ask the server for its set of services and wait until we have received them all. * @return true on success otherwise false if an error occurred */ -bool NimBLEClient::retrieveServices(const NimBLEUUID *uuidFilter) { -/** - * Design - * ------ - * We invoke ble_gattc_disc_all_svcs. This will request a list of the services exposed by the - * peer BLE partner to be returned in the callback function provided. - */ - - NIMBLE_LOGD(LOG_TAG, ">> retrieveServices"); - - if(!isConnected()){ +bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { + if (!isConnected()) { NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting"); return false; } - int rc = 0; + int rc = 0; TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; + BleTaskData taskData = {this, cur_task, 0, nullptr}; - if(uuidFilter == nullptr) { - rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData); + if (uuidFilter == nullptr) { + rc = ble_gattc_disc_all_svcs(m_connHandle, NimBLEClient::serviceDiscoveredCB, &taskData); } else { - rc = ble_gattc_disc_svc_by_uuid(m_conn_id, uuidFilter->getBase(), - NimBLEClient::serviceDiscoveredCB, &taskData); + rc = ble_gattc_disc_svc_by_uuid(m_connHandle, uuidFilter->getBase(), NimBLEClient::serviceDiscoveredCB, &taskData); } if (rc != 0) { @@ -826,86 +709,84 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuidFilter) { return false; } -#ifdef ulTaskNotifyValueClear +# ifdef ulTaskNotifyValueClear // Clear the task notification value to ensure we block ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif +# endif // wait until we have all the services ulTaskNotifyTake(pdTRUE, portMAX_DELAY); m_lastErr = taskData.rc; - if(taskData.rc == 0){ - NIMBLE_LOGD(LOG_TAG, "<< retrieveServices"); + if (taskData.rc == 0) { return true; - } - else { - NIMBLE_LOGE(LOG_TAG, "Could not retrieve services"); + } else { + NIMBLE_LOGE(LOG_TAG, + "Could not retrieve services, rc=%d %s", + taskData.rc, + NimBLEUtils::returnCodeToString(taskData.rc)); return false; } } // getServices - /** - * @brief STATIC Callback for the service discovery API function.\n - * When a service is found or there is none left or there was an error + * @brief Callback for the service discovery API function. + * @details When a service is found or there is none left or there was an error * the API will call this and report findings. */ -int NimBLEClient::serviceDiscoveredCB( - uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *service, void *arg) -{ - NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d", - error->status, (error->status == 0) ? service->start_handle : -1); - - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLEClient *client = (NimBLEClient*)pTaskData->pATT; +int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle, + const struct ble_gatt_error* error, + const struct ble_gatt_svc* service, + void* arg) { + NIMBLE_LOGD(LOG_TAG, + "Service Discovered >> status: %d handle: %d", + error->status, + (error->status == 0) ? service->start_handle : -1); + + BleTaskData* pTaskData = (BleTaskData*)arg; + NimBLEClient* pClient = (NimBLEClient*)pTaskData->pATT; // Make sure the service discovery is for this device - if(client->getConnId() != conn_handle){ + if (pClient->getConnHandle() != connHandle) { return 0; } - if(error->status == 0) { + if (error->status == 0) { // Found a service - add it to the vector - NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service); - client->m_servicesVector.push_back(pRemoteService); + pClient->m_svcVec.push_back(new NimBLERemoteService(pClient, service)); return 0; } - if(error->status == BLE_HS_EDONE) { + if (error->status == BLE_HS_EDONE) { pTaskData->rc = 0; } else { - NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s", - error->status, - NimBLEUtils::returnCodeToString(error->status)); + NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s", error->status, NimBLEUtils::returnCodeToString(error->status)); pTaskData->rc = error->status; } xTaskNotifyGive(pTaskData->task); - NIMBLE_LOGD(LOG_TAG,"<< Service Discovered"); + NIMBLE_LOGD(LOG_TAG, "<< Service Discovered"); return error->status; } - /** * @brief Get the value of a specific characteristic associated with a specific service. * @param [in] serviceUUID The service that owns the characteristic. * @param [in] characteristicUUID The characteristic whose value we wish to read. - * @returns characteristic value or an empty string if not found + * @returns characteristic value or an empty value if not found. */ -NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) { - NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", - serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - - NimBLEAttValue ret; - NimBLERemoteService* pService = getService(serviceUUID); - - if(pService != nullptr) { - NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID); - if(pChar != nullptr) { +NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID) { + NIMBLE_LOGD(LOG_TAG, + ">> getValue: serviceUUID: %s, characteristicUUID: %s", + serviceUUID.toString().c_str(), + characteristicUUID.toString().c_str()); + + NimBLEAttValue ret{}; + auto pService = getService(serviceUUID); + if (pService != nullptr) { + auto pChar = pService->getCharacteristic(characteristicUUID); + if (pChar != nullptr) { ret = pChar->readValue(); } } @@ -914,7 +795,6 @@ NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBL return ret; } // getValue - /** * @brief Set the value of a specific characteristic associated with a specific service. * @param [in] serviceUUID The service that owns the characteristic. @@ -923,18 +803,20 @@ NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBL * @param [in] response If true, uses write with response operation. * @returns true if successful otherwise false */ -bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID, - const NimBLEAttValue &value, bool response) -{ - NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", - serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - - bool ret = false; - NimBLERemoteService* pService = getService(serviceUUID); - - if(pService != nullptr) { +bool NimBLEClient::setValue(const NimBLEUUID& serviceUUID, + const NimBLEUUID& characteristicUUID, + const NimBLEAttValue& value, + bool response) { + NIMBLE_LOGD(LOG_TAG, + ">> setValue: serviceUUID: %s, characteristicUUID: %s", + serviceUUID.toString().c_str(), + characteristicUUID.toString().c_str()); + + bool ret = false; + auto pService = getService(serviceUUID); + if (pService != nullptr) { NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID); - if(pChar != nullptr) { + if (pChar != nullptr) { ret = pChar->writeValue(value, response); } } @@ -943,26 +825,18 @@ bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &cha return ret; } // setValue - /** * @brief Get the remote characteristic with the specified handle. * @param [in] handle The handle of the desired characteristic. * @returns The matching remote characteristic, nullptr otherwise. */ -NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(const uint16_t handle) -{ - NimBLERemoteService *pService = nullptr; - for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) { - if ((*it)->getStartHandle() <= handle && handle <= (*it)->getEndHandle()) { - pService = *it; - break; - } - } - - if (pService != nullptr) { - for (auto it = pService->begin(); it != pService->end(); ++it) { - if ((*it)->getHandle() == handle) { - return *it; +NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(uint16_t handle) { + for (const auto& svc : m_svcVec) { + if (svc->getStartHandle() <= handle && handle <= svc->getEndHandle()) { + for (const auto& chr : svc->m_vChars) { + if (chr->getHandle() == handle) { + return chr; + } } } } @@ -975,29 +849,26 @@ NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(const uint16_t handl * @returns The MTU value. */ uint16_t NimBLEClient::getMTU() const { - return ble_att_mtu(m_conn_id); + return ble_att_mtu(m_connHandle); } // getMTU - /** * @brief Handle a received GAP event. * @param [in] event The event structure sent by the NimBLE stack. * @param [in] arg A pointer to the client instance that registered for this callback. */ - /*STATIC*/ -int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { +int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { NimBLEClient* pClient = (NimBLEClient*)arg; - int rc; + int rc = 0; NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type)); - switch(event->type) { - + switch (event->type) { case BLE_GAP_EVENT_DISCONNECT: { rc = event->disconnect.reason; // If Host reset tell the device now before returning to prevent // any errors caused by calling host functions before resyncing. - switch(rc) { + switch (rc) { case BLE_HS_ECONTROLLER: case BLE_HS_ETIMEOUT_HCI: case BLE_HS_ENOTSYNCED: @@ -1007,30 +878,26 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { break; default: // Check that the event is for this client. - if(pClient->m_conn_id != event->disconnect.conn.conn_handle) { + if (pClient->m_connHandle != event->disconnect.conn.conn_handle) { return 0; } + break; } - // Stop the disconnect timer since we are now disconnected. - ble_npl_callout_stop(&pClient->m_dcTimer); - - // Remove the device from ignore list so we will scan it again + pClient->m_terminateFailCount = 0; NimBLEDevice::removeIgnored(pClient->m_peerAddress); + pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE; - // No longer connected, clear the connection ID. - pClient->m_conn_id = BLE_HS_CONN_HANDLE_NONE; - - // If we received a connected event but did not get established (no PDU) + // If we received a connected event but did not get established // then a disconnect event will be sent but we should not send it to the // app for processing. Instead we will ensure the task is released // and report the error. - if(!pClient->m_connEstablished) + if (!pClient->m_connEstablished) { break; + } - NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); + NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); pClient->m_connEstablished = false; pClient->m_pClientCallbacks->onDisconnect(pClient, rc); @@ -1038,9 +905,8 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { } // BLE_GAP_EVENT_DISCONNECT case BLE_GAP_EVENT_CONNECT: { - // If we aren't waiting for this connection response - // we should drop the connection immediately. - if(pClient->isConnected() || pClient->m_pTaskData == nullptr) { + // If we aren't waiting for this connection response we should drop the connection immediately. + if (pClient->isConnected() || pClient->m_pTaskData == nullptr) { ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); return 0; } @@ -1049,12 +915,11 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { if (rc == 0) { NIMBLE_LOGI(LOG_TAG, "Connected event"); - pClient->m_conn_id = event->connect.conn_handle; + pClient->m_connHandle = event->connect.conn_handle; - rc = ble_gattc_exchange_mtu(pClient->m_conn_id, NULL,NULL); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s", - rc, NimBLEUtils::returnCodeToString(rc)); + rc = ble_gattc_exchange_mtu(pClient->m_connHandle, NULL, NULL); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); break; } @@ -1062,57 +927,61 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { // scanning since we are already connected to it NimBLEDevice::addIgnored(pClient->m_peerAddress); } else { - pClient->m_conn_id = BLE_HS_CONN_HANDLE_NONE; + pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE; break; } return 0; } // BLE_GAP_EVENT_CONNECT - case BLE_GAP_EVENT_NOTIFY_RX: { - if(pClient->m_conn_id != event->notify_rx.conn_handle) + case BLE_GAP_EVENT_TERM_FAILURE: { + if (pClient->m_connHandle != event->term_failure.conn_handle) { return 0; + } + + NIMBLE_LOGE(LOG_TAG, "Connection termination failure; rc=%d - retrying", event->term_failure.status); + if (++pClient->m_terminateFailCount > 2) { + ble_hs_sched_reset(BLE_HS_ECONTROLLER); + } else { + ble_gap_terminate(event->term_failure.conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } + return 0; + } // BLE_GAP_EVENT_TERM_FAILURE + + case BLE_GAP_EVENT_NOTIFY_RX: { + if (pClient->m_connHandle != event->notify_rx.conn_handle) return 0; // If a notification comes before this flag is set we might // access a vector while it is being cleared in connect() - if(!pClient->m_connEstablished) { + if (!pClient->m_connEstablished) { return 0; } - NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", - event->notify_rx.attr_handle); + NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", event->notify_rx.attr_handle); - for(auto &it: pClient->m_servicesVector) { + for (const auto& svc : pClient->m_svcVec) { // Dont waste cycles searching services without this handle in its range - if(it->getEndHandle() < event->notify_rx.attr_handle) { + if (svc->getEndHandle() < event->notify_rx.attr_handle) { continue; } - auto cVector = &it->m_vChars; - NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", - it->getUUID().toString().c_str(), + NIMBLE_LOGD(LOG_TAG, + "checking service %s for handle: %d", + svc->getUUID().toString().c_str(), event->notify_rx.attr_handle); - auto characteristic = cVector->cbegin(); - for(; characteristic != cVector->cend(); ++characteristic) { - if((*characteristic)->m_handle == event->notify_rx.attr_handle) - break; - } + for (const auto& chr : svc->m_vChars) { + if (chr->getHandle() == event->notify_rx.attr_handle) { + NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", chr->toString().c_str()); - if(characteristic != cVector->cend()) { - NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", - (*characteristic)->toString().c_str()); + uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om); + chr->m_value.setValue(event->notify_rx.om->om_data, data_len); - uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om); - (*characteristic)->m_value.setValue(event->notify_rx.om->om_data, data_len); - - if ((*characteristic)->m_notifyCallback != nullptr) { - NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", - (*characteristic)->toString().c_str()); - (*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data, - data_len, !event->notify_rx.indication); + if (chr->m_notifyCallback != nullptr) { + chr->m_notifyCallback(chr, event->notify_rx.om->om_data, data_len, !event->notify_rx.indication); + } + break; } - break; } } @@ -1121,25 +990,26 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { case BLE_GAP_EVENT_CONN_UPDATE_REQ: case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: { - if(pClient->m_conn_id != event->conn_update_req.conn_handle){ + if (pClient->m_connHandle != event->conn_update_req.conn_handle) { return 0; } NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters"); - NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d", + NIMBLE_LOGD(LOG_TAG, + "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d", event->conn_update_req.peer_params->itvl_min, event->conn_update_req.peer_params->itvl_max, event->conn_update_req.peer_params->latency, event->conn_update_req.peer_params->supervision_timeout); - rc = pClient->m_pClientCallbacks->onConnParamsUpdateRequest(pClient, - event->conn_update_req.peer_params) ? 0 : BLE_ERR_CONN_PARMS; - + rc = pClient->m_pClientCallbacks->onConnParamsUpdateRequest(pClient, event->conn_update_req.peer_params) + ? 0 + : BLE_ERR_CONN_PARMS; - if(!rc && event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ ) { - event->conn_update_req.self_params->itvl_min = pClient->m_pConnParams.itvl_min; - event->conn_update_req.self_params->itvl_max = pClient->m_pConnParams.itvl_max; - event->conn_update_req.self_params->latency = pClient->m_pConnParams.latency; - event->conn_update_req.self_params->supervision_timeout = pClient->m_pConnParams.supervision_timeout; + if (!rc && event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ) { + event->conn_update_req.self_params->itvl_min = pClient->m_connParams.itvl_min; + event->conn_update_req.self_params->itvl_max = pClient->m_connParams.itvl_max; + event->conn_update_req.self_params->latency = pClient->m_connParams.latency; + event->conn_update_req.self_params->supervision_timeout = pClient->m_connParams.supervision_timeout; } NIMBLE_LOGD(LOG_TAG, "%s peer params", (rc == 0) ? "Accepted" : "Rejected"); @@ -1147,10 +1017,10 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { } // BLE_GAP_EVENT_CONN_UPDATE_REQ, BLE_GAP_EVENT_L2CAP_UPDATE_REQ case BLE_GAP_EVENT_CONN_UPDATE: { - if(pClient->m_conn_id != event->conn_update.conn_handle){ + if (pClient->m_connHandle != event->conn_update.conn_handle) { return 0; } - if(event->conn_update.status == 0) { + if (event->conn_update.status == 0) { NIMBLE_LOGI(LOG_TAG, "Connection parameters updated."); } else { NIMBLE_LOGE(LOG_TAG, "Update connection parameters failed."); @@ -1159,17 +1029,15 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { } // BLE_GAP_EVENT_CONN_UPDATE case BLE_GAP_EVENT_ENC_CHANGE: { - if(pClient->m_conn_id != event->enc_change.conn_handle){ + if (pClient->m_connHandle != event->enc_change.conn_handle) { return 0; } - if(event->enc_change.status == 0 || - event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) - { + if (event->enc_change.status == 0 || + event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) { NimBLEConnInfo peerInfo; rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc); if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Connection info not found"); rc = 0; break; } @@ -1184,13 +1052,12 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { rc = event->enc_change.status; break; - } //BLE_GAP_EVENT_ENC_CHANGE + } // BLE_GAP_EVENT_ENC_CHANGE case BLE_GAP_EVENT_IDENTITY_RESOLVED: { NimBLEConnInfo peerInfo; rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &peerInfo.m_desc); if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Connection info not found"); rc = 0; break; } @@ -1200,44 +1067,37 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { } // BLE_GAP_EVENT_IDENTITY_RESOLVED case BLE_GAP_EVENT_MTU: { - if(pClient->m_conn_id != event->mtu.conn_handle){ + if (pClient->m_connHandle != event->mtu.conn_handle) { return 0; } - NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", - event->mtu.conn_handle, - event->mtu.value); + NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", event->mtu.conn_handle, event->mtu.value); rc = 0; break; } // BLE_GAP_EVENT_MTU case BLE_GAP_EVENT_PASSKEY_ACTION: { - struct ble_sm_io pkey = {0,0}; - (void)pkey; //warning: variable 'pkey' set but not used [-Wunused-but-set-variable] - - if(pClient->m_conn_id != event->passkey.conn_handle) + if (pClient->m_connHandle != event->passkey.conn_handle) { return 0; + } NimBLEConnInfo peerInfo; rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc); if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Connection info not found"); rc = 0; break; } if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp); - pClient->m_pClientCallbacks->onConfirmPIN(peerInfo, event->passkey.params.numcmp); - //TODO: Handle out of band pairing + pClient->m_pClientCallbacks->onConfirmPasskey(peerInfo, event->passkey.params.numcmp); } 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_inject_io result: %d", rc); - //////// + NIMBLE_LOGD(LOG_TAG, "OOB request received"); + // TODO: Handle out of band pairing + // struct ble_sm_io pkey; + // pkey.action = BLE_SM_IOACT_OOB; + // pClient->onOobPairingRequest(pkey.oob); + // rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); + // NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc); } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) { NIMBLE_LOGD(LOG_TAG, "Enter the passkey"); pClient->m_pClientCallbacks->onPassKeyEntry(peerInfo); @@ -1253,9 +1113,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { } } // Switch - if(pClient->m_pTaskData != nullptr) { + if (pClient->m_pTaskData != nullptr) { pClient->m_pTaskData->rc = rc; - if(pClient->m_pTaskData->task) { + if (pClient->m_pTaskData->task) { xTaskNotifyGive(pClient->m_pTaskData->task); } pClient->m_pTaskData = nullptr; @@ -1264,84 +1124,81 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { return 0; } // handleGapEvent - /** * @brief Are we connected to a server? * @return True if we are connected and false if we are not connected. */ -bool NimBLEClient::isConnected() { - return m_conn_id != BLE_HS_CONN_HANDLE_NONE; +bool NimBLEClient::isConnected() const { + return m_connHandle != BLE_HS_CONN_HANDLE_NONE; } // isConnected - /** * @brief Set the callbacks that will be invoked when events are received. * @param [in] pClientCallbacks A pointer to a class to receive the event callbacks. * @param [in] deleteCallbacks If true this will delete the callback class sent when the client is destructed. */ void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) { - if (pClientCallbacks != nullptr){ + if (pClientCallbacks != nullptr) { m_pClientCallbacks = pClientCallbacks; + m_deleteCallbacks = deleteCallbacks; } else { m_pClientCallbacks = &defaultCallbacks; + m_deleteCallbacks = false; } - m_deleteCallbacks = deleteCallbacks; } // setClientCallbacks - /** * @brief Return a string representation of this client. * @return A string representation of this client. */ -std::string NimBLEClient::toString() { - std::string res = "peer address: " + m_peerAddress.toString(); - res += "\nServices:\n"; +std::string NimBLEClient::toString() const { + std::string res = "peer address: " + m_peerAddress.toString(); + res += "\nServices:\n"; - for(auto &it: m_servicesVector) { + for (const auto& it : m_svcVec) { res += it->toString() + "\n"; } return res; } // 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() { +int NimBLEClient::getLastError() const { return m_lastErr; } // getLastError - void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) { - NIMBLE_LOGD("NimBLEClientCallbacks", "onConnect: default"); + NIMBLE_LOGD(CB_TAG, "onConnect: default"); } void NimBLEClientCallbacks::onDisconnect(NimBLEClient* pClient, int reason) { - NIMBLE_LOGD("NimBLEClientCallbacks", "onDisconnect: default"); + NIMBLE_LOGD(CB_TAG, "onDisconnect: default"); } bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) { - NIMBLE_LOGD("NimBLEClientCallbacks", "onConnParamsUpdateRequest: default"); + NIMBLE_LOGD(CB_TAG, "onConnParamsUpdateRequest: default"); return true; } -void NimBLEClientCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyEntry: default: 123456"); +void NimBLEClientCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo) { + NIMBLE_LOGD(CB_TAG, "onPassKeyEntry: default: 123456"); NimBLEDevice::injectPassKey(connInfo, 123456); -} //onPassKeyEntry +} // onPassKeyEntry -void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onAuthenticationComplete: default"); +void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) { + NIMBLE_LOGD(CB_TAG, "onAuthenticationComplete: default"); } -void NimBLEClientCallbacks::onIdentity(NimBLEConnInfo& connInfo){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onIdentity: default"); +void NimBLEClientCallbacks::onIdentity(NimBLEConnInfo& connInfo) { + NIMBLE_LOGD(CB_TAG, "onIdentity: default"); } // onIdentity -void NimBLEClientCallbacks::onConfirmPIN(NimBLEConnInfo& connInfo, uint32_t pin){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onConfirmPIN: default: true"); +void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin) { + NIMBLE_LOGD(CB_TAG, "onConfirmPasskey: default: true"); NimBLEDevice::injectConfirmPasskey(connInfo, true); } diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index b571e90b..ef5a08fa 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -11,116 +11,121 @@ * Author: kolban */ -#ifndef MAIN_NIMBLECLIENT_H_ -#define MAIN_NIMBLECLIENT_H_ +#ifndef NIMBLE_CPP_CLIENT_H_ +#define NIMBLE_CPP_CLIENT_H_ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) -#include "NimBLEAddress.h" -#include "NimBLEUUID.h" -#include "NimBLEUtils.h" -#include "NimBLEConnInfo.h" -#include "NimBLEAttValue.h" -#include "NimBLEAdvertisedDevice.h" +# if defined(CONFIG_NIMBLE_CPP_IDF) +# include "host/ble_gap.h" +# else +# include "nimble/nimble/host/include/host/ble_gap.h" +# endif -#include -#include +# include "NimBLEAddress.h" +# include +# include +# include + +class NimBLEAddress; +class NimBLEUUID; class NimBLERemoteService; class NimBLERemoteCharacteristic; class NimBLEAdvertisedDevice; +class NimBLEAttValue; class NimBLEClientCallbacks; +class NimBLEConnInfo; +struct BleTaskData; /** - * @brief A model of a %BLE client. + * @brief A model of a BLE client. */ class NimBLEClient { -public: - bool connect(NimBLEAdvertisedDevice* device, bool deleteAttributes = true); - bool connect(const NimBLEAddress &address, bool deleteAttributes = true); - bool connect(bool deleteAttributes = true); - int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); - NimBLEAddress getPeerAddress() const; - void setPeerAddress(const NimBLEAddress &address); - int getRssi(); - std::vector* getServices(bool refresh = false); + public: + bool connect(NimBLEAdvertisedDevice* device, bool deleteAttributes = true); + bool connect(const NimBLEAddress& address, bool deleteAttributes = true); + bool connect(bool deleteAttributes = true); + bool disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); + NimBLEAddress getPeerAddress() const; + bool setPeerAddress(const NimBLEAddress& address); + int getRssi() const; + bool isConnected() const; + void setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks = true); + std::string toString() const; + uint16_t getConnHandle() const; + void clearConnection(); + bool setConnection(const NimBLEConnInfo& connInfo); + bool setConnection(uint16_t connHandle); + uint16_t getMTU() const; + bool secureConnection() const; + void setConnectTimeout(uint32_t timeout); + bool setDataLen(uint16_t txOctets); + bool discoverAttributes(); + NimBLEConnInfo getConnInfo() const; + int getLastError() const; + bool updateConnParams(uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout); + void setConnectionParams(uint16_t minInterval, + uint16_t maxInterval, + uint16_t latency, + uint16_t timeout, + uint16_t scanInterval = 16, + uint16_t scanWindow = 16); + const std::vector& getServices(bool refresh = false); std::vector::iterator begin(); std::vector::iterator end(); + NimBLERemoteCharacteristic* getCharacteristic(uint16_t handle); NimBLERemoteService* getService(const char* uuid); - NimBLERemoteService* getService(const NimBLEUUID &uuid); + NimBLERemoteService* getService(const NimBLEUUID& uuid); void deleteServices(); - size_t deleteService(const NimBLEUUID &uuid); - NimBLEAttValue getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID); - bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID, - const NimBLEAttValue &value, bool response = false); - NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle); - bool isConnected(); - void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks, - bool deleteCallbacks = true); - std::string toString(); - uint16_t getConnId() const; - void clearConnection(); - bool setConnection(NimBLEConnInfo &conn_info); - bool setConnection(uint16_t conn_id); - uint16_t getMTU() const; - bool secureConnection() const; - void setConnectTimeout(uint32_t timeout); - void setConnectionParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout, - uint16_t scanInterval=16, uint16_t scanWindow=16); - void updateConnParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout); - void setDataLen(uint16_t tx_octets); - bool discoverAttributes(); - NimBLEConnInfo getConnInfo(); - int getLastError(); -#if CONFIG_BT_NIMBLE_EXT_ADV - void setConnectPhy(uint8_t mask); -#endif - -private: - NimBLEClient(const NimBLEAddress &peerAddress); + size_t deleteService(const NimBLEUUID& uuid); + NimBLEAttValue getValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID); + bool setValue(const NimBLEUUID& serviceUUID, + const NimBLEUUID& characteristicUUID, + const NimBLEAttValue& value, + bool response = false); + +# if CONFIG_BT_NIMBLE_EXT_ADV + void setConnectPhy(uint8_t mask); +# endif + + private: + NimBLEClient(const NimBLEAddress& peerAddress); ~NimBLEClient(); - - friend class NimBLEDevice; - friend class NimBLERemoteService; - - static int handleGapEvent(struct ble_gap_event *event, void *arg); - static int serviceDiscoveredCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *service, - void *arg); - static void dcTimerCb(ble_npl_event *event); - bool retrieveServices(const NimBLEUUID *uuidFilter = nullptr); - - NimBLEAddress m_peerAddress; - mutable int m_lastErr; - uint16_t m_conn_id; - bool m_connEstablished; - bool m_deleteCallbacks; - int32_t m_connectTimeout; - NimBLEClientCallbacks* m_pClientCallbacks; - mutable ble_task_data_t* m_pTaskData; - ble_npl_callout m_dcTimer; -#if CONFIG_BT_NIMBLE_EXT_ADV - uint8_t m_phyMask; -#endif - - std::vector m_servicesVector; - -private: - friend class NimBLEClientCallbacks; - ble_gap_conn_params m_pConnParams; - + NimBLEClient(const NimBLEClient&) = delete; + NimBLEClient& operator=(const NimBLEClient&) = delete; + + bool retrieveServices(const NimBLEUUID* uuidFilter = nullptr); + static int handleGapEvent(struct ble_gap_event* event, void* arg); + static int serviceDiscoveredCB(uint16_t connHandle, + const struct ble_gatt_error* error, + const struct ble_gatt_svc* service, + void* arg); + + NimBLEAddress m_peerAddress; + mutable int m_lastErr; + int32_t m_connectTimeout; + mutable BleTaskData* m_pTaskData; + std::vector m_svcVec; + NimBLEClientCallbacks* m_pClientCallbacks; + uint16_t m_connHandle; + uint8_t m_terminateFailCount; + bool m_deleteCallbacks; + bool m_connEstablished; +# if CONFIG_BT_NIMBLE_EXT_ADV + uint8_t m_phyMask; +# endif + ble_gap_conn_params m_connParams; + + friend class NimBLEDevice; }; // class NimBLEClient - /** * @brief Callbacks associated with a %BLE client. */ class NimBLEClientCallbacks { -public: + public: virtual ~NimBLEClientCallbacks() {}; /** @@ -162,7 +167,7 @@ class NimBLEClientCallbacks { * @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info. * @param [in] pin The pin to compare with the server. */ - virtual void onConfirmPIN(NimBLEConnInfo& connInfo, uint32_t pin); + virtual void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin); /** * @brief Called when the peer identity address is resolved. @@ -172,4 +177,4 @@ class NimBLEClientCallbacks { }; #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ -#endif /* MAIN_NIMBLECLIENT_H_ */ +#endif /* NIMBLE_CPP_CLIENT_H_ */ diff --git a/src/NimBLEDevice.cpp b/src/NimBLEDevice.cpp index e60c9f87..9573bb56 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -324,8 +324,7 @@ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) { int rc = 0; if (pClient->isConnected()) { - rc = pClient->disconnect(); - if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) { + if (!pClient->disconnect()) { return false; } @@ -378,7 +377,7 @@ size_t NimBLEDevice::getCreatedClientCount() { */ NimBLEClient* NimBLEDevice::getClientByHandle(uint16_t connHandle) { for (const auto clt : m_pClients) { - if (clt != nullptr && clt->getConnId() == connHandle) { + if (clt != nullptr && clt->getConnHandle() == connHandle) { return clt; } } diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index f6d1207d..fa1e8c5e 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -65,7 +65,7 @@ int NimBLERemoteCharacteristic::descriptorDiscCB( NIMBLE_LOGD(LOG_TAG, "Descriptor Discovery >> status: %d handle: %d", rc, (rc == 0) ? dsc->handle : -1); auto filter = (desc_filter_t*)arg; - auto pTaskData = (ble_task_data_t*)filter->task_data; + auto pTaskData = (BleTaskData*)filter->task_data; const auto pChr = (NimBLERemoteCharacteristic*)pTaskData->pATT; const NimBLEUUID* uuidFilter = filter->uuid; @@ -102,10 +102,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilte NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {const_cast(this), cur_task, 0, nullptr}; + BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; desc_filter_t filter = {uuidFilter, &taskData}; - int rc = ble_gattc_disc_all_dscs(getClient()->getConnId(), + int rc = ble_gattc_disc_all_dscs(getClient()->getConnHandle(), getHandle(), getRemoteService()->getEndHandle(), NimBLERemoteCharacteristic::descriptorDiscCB, diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 0a09e8d7..a31d998b 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -145,11 +145,11 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, const ble_gatt_chr* chr, void* arg) { NIMBLE_LOGD(LOG_TAG, "Characteristic Discovery >>"); - auto pTaskData = (ble_task_data_t*)arg; + auto pTaskData = (BleTaskData*)arg; const auto pSvc = (NimBLERemoteService*)pTaskData->pATT; // Make sure the discovery is for this device - if (pSvc->getClient()->getConnId() != conn_handle) { + if (pSvc->getClient()->getConnHandle() != conn_handle) { return 0; } @@ -173,16 +173,16 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter) NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics()"); int rc = 0; TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {const_cast(this), cur_task, 0, nullptr}; + BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; if (uuidFilter == nullptr) { - rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), + rc = ble_gattc_disc_all_chrs(m_pClient->getConnHandle(), getHandle(), getEndHandle(), NimBLERemoteService::characteristicDiscCB, &taskData); } else { - rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(), + rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnHandle(), getHandle(), getEndHandle(), uuidFilter->getBase(), diff --git a/src/NimBLERemoteValueAttribute.cpp b/src/NimBLERemoteValueAttribute.cpp index 444fa62c..aca3fedd 100644 --- a/src/NimBLERemoteValueAttribute.cpp +++ b/src/NimBLERemoteValueAttribute.cpp @@ -10,6 +10,7 @@ # include "NimBLERemoteValueAttribute.h" # include "NimBLEClient.h" +# include "NimBLEUtils.h" # include @@ -20,7 +21,7 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, const NimBLEClient* pClient = getClient(); TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {const_cast(this), cur_task, 0, nullptr}; + BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; int retryCount = 1; int rc = 0; uint16_t mtu = pClient->getMTU() - 3; @@ -28,7 +29,7 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, // Check if the data length is longer than we can write in one connection event. // If so we must do a long write which requires a response. if (length <= mtu && !response) { - rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), getHandle(), data, length); + rc = ble_gattc_write_no_rsp_flat(pClient->getConnHandle(), getHandle(), data, length); goto Done; } @@ -36,9 +37,9 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, if (length > mtu) { NIMBLE_LOGI(LOG_TAG, "writeValue: long write"); os_mbuf* om = ble_hs_mbuf_from_flat(data, length); - rc = ble_gattc_write_long(pClient->getConnId(), getHandle(), 0, om, NimBLERemoteValueAttribute::onWriteCB, &taskData); + rc = ble_gattc_write_long(pClient->getConnHandle(), getHandle(), 0, om, NimBLERemoteValueAttribute::onWriteCB, &taskData); } else { - rc = ble_gattc_write_flat(pClient->getConnId(), + rc = ble_gattc_write_flat(pClient->getConnHandle(), getHandle(), data, length, @@ -93,10 +94,10 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, * @return success == 0 or error code. */ int NimBLERemoteValueAttribute::onWriteCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg) { - auto pTaskData = static_cast(arg); + auto pTaskData = static_cast(arg); const auto pAtt = static_cast(pTaskData->pATT); - if (pAtt->getClient()->getConnId() != conn_handle) { + if (pAtt->getClient()->getConnHandle() != conn_handle) { return 0; } @@ -119,10 +120,10 @@ NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const { int rc = 0; int retryCount = 1; TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {const_cast(this), cur_task, 0, &value}; + BleTaskData taskData = {const_cast(this), cur_task, 0, &value}; do { - rc = ble_gattc_read_long(pClient->getConnId(), getHandle(), 0, NimBLERemoteValueAttribute::onReadCB, &taskData); + rc = ble_gattc_read_long(pClient->getConnHandle(), getHandle(), 0, NimBLERemoteValueAttribute::onReadCB, &taskData); if (rc != 0) { goto Done; } @@ -142,7 +143,7 @@ NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const { // Characteristic is not long-readable, return with what we have. case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): NIMBLE_LOGI(LOG_TAG, "Attribute not long"); - rc = ble_gattc_read(pClient->getConnId(), getHandle(), NimBLERemoteValueAttribute::onReadCB, &taskData); + rc = ble_gattc_read(pClient->getConnHandle(), getHandle(), NimBLERemoteValueAttribute::onReadCB, &taskData); if (rc != 0) { goto Done; } @@ -179,10 +180,10 @@ NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const { * @return success == 0 or error code. */ int NimBLERemoteValueAttribute::onReadCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg) { - auto pTaskData = static_cast(arg); + auto pTaskData = static_cast(arg); const auto pAtt = static_cast(pTaskData->pATT); - if (pAtt->getClient()->getConnId() != conn_handle) { + if (pAtt->getClient()->getConnHandle() != conn_handle) { return 0; } diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index d21b6a44..65466340 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -457,7 +457,7 @@ NimBLEScanResults NimBLEScan::getResults(uint32_t duration, bool is_continue) { } TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr}; + BleTaskData taskData = {nullptr, cur_task, 0, nullptr}; m_pTaskData = &taskData; if(start(duration, is_continue)) { diff --git a/src/NimBLEScan.h b/src/NimBLEScan.h index f0edcaa9..b7550ea6 100644 --- a/src/NimBLEScan.h +++ b/src/NimBLEScan.h @@ -94,7 +94,7 @@ class NimBLEScan { bool m_ignoreResults; NimBLEScanResults m_scanResults; uint32_t m_duration; - ble_task_data_t *m_pTaskData; + BleTaskData *m_pTaskData; uint8_t m_maxResults; }; diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index 9bf2f7f5..1c2ba395 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -368,7 +368,7 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + BleTaskData *pTaskData = (BleTaskData*)arg; std::string *name = (std::string*)pTaskData->buf; int rc = error->status; @@ -414,7 +414,7 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, */ std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, TaskHandle_t task, int cb_type) { std::string *buf = new std::string{}; - ble_task_data_t *taskData = new ble_task_data_t{this, task, cb_type, buf}; + BleTaskData *taskData = new BleTaskData{this, task, 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, @@ -628,7 +628,7 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { if (rc != 0) { return 0; } - + pServer->m_pServerCallbacks->onConnParamsUpdate(peerInfo); return 0; } // BLE_GAP_EVENT_CONN_UPDATE diff --git a/src/NimBLEUUID.cpp b/src/NimBLEUUID.cpp index c9f9502c..72527d4f 100644 --- a/src/NimBLEUUID.cpp +++ b/src/NimBLEUUID.cpp @@ -19,6 +19,11 @@ # include "NimBLEUUID.h" # include "NimBLELog.h" +/**** FIX COMPILATION ****/ +# undef min +# undef max +/**************************/ + # include static const char* LOG_TAG = "NimBLEUUID"; diff --git a/src/NimBLEUUID.h b/src/NimBLEUUID.h index 7863995b..28638899 100644 --- a/src/NimBLEUUID.h +++ b/src/NimBLEUUID.h @@ -24,11 +24,6 @@ # include "nimble/nimble/host/include/host/ble_uuid.h" # endif -/**** FIX COMPILATION ****/ -# undef min -# undef max -/**************************/ - # include # include diff --git a/src/NimBLEUtils.cpp b/src/NimBLEUtils.cpp index cc50e138..936a9d8a 100644 --- a/src/NimBLEUtils.cpp +++ b/src/NimBLEUtils.cpp @@ -13,6 +13,17 @@ #include "NimBLEAddress.h" #include "NimBLELog.h" +# if defined(CONFIG_NIMBLE_CPP_IDF) +# include "host/ble_hs.h" +# else +# include "nimble/nimble/host/include/host/ble_hs.h" +# endif + +/**** FIX COMPILATION ****/ +#undef min +#undef max +/**************************/ + #include static const char* LOG_TAG = "NimBLEUtils"; diff --git a/src/NimBLEUtils.h b/src/NimBLEUtils.h index a581011b..71928d07 100644 --- a/src/NimBLEUtils.h +++ b/src/NimBLEUtils.h @@ -12,28 +12,21 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) -#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 class NimBLEAddress; -typedef struct { - void *pATT; +struct BleTaskData { + void* pATT; TaskHandle_t task; - int rc; - void *buf; -} ble_task_data_t; + int rc; + void* buf; +}; +struct ble_gap_event; /** * @brief A BLE Utility class with methods for debugging and general purpose use. @@ -48,6 +41,5 @@ class NimBLEUtils { static NimBLEAddress generateAddr(bool nrpa); }; - #endif // CONFIG_BT_ENABLED #endif // COMPONENTS_NIMBLEUTILS_H_