mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-23 05:30:54 +01:00
Add asyncronous client connect and MTU exchange.
* Adds parameters `asyncConnect` and `exchangeMTU` to `NimBLEClient::connect`, default values work as the original connect method. * * `asyncConnect`; if true, will send the connect command and return immediately with a true value for successfully sending the command, else false. * * `exchangeMTU`; if true will send the exchange MTU command upon connection, otherwise not and the application can choose to do this later via the `exchangeMTU` method. * Adds `onMTUChange` callback to `NimBLEClientCallbacks` * Add `NimBLEDevice::getConnectedClients()` which returns a vector of pointers to the currently connected client instances. * Calling `NimBLEClient::connect` will no longer cancel already in progress connections.
This commit is contained in:
parent
724e1a7083
commit
38e764d157
10 changed files with 267 additions and 47 deletions
6
examples/NimBLE_Async_Client/CMakeLists.txt
Normal file
6
examples/NimBLE_Async_Client/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(NimBLE_Async_Client)
|
3
examples/NimBLE_Async_Client/Makefile
Normal file
3
examples/NimBLE_Async_Client/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROJECT_NAME := NimBLE_Async_Client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/NimBLE_Async_Client/main/CMakeLists.txt
Normal file
4
examples/NimBLE_Async_Client/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
4
examples/NimBLE_Async_Client/main/component.mk
Normal file
4
examples/NimBLE_Async_Client/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
83
examples/NimBLE_Async_Client/main/main.cpp
Normal file
83
examples/NimBLE_Async_Client/main/main.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
|
||||
/**
|
||||
* NimBLE_Async_client Demo:
|
||||
*
|
||||
* Demonstrates asynchronous client operations.
|
||||
*
|
||||
* Created: on November 4, 2024
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static constexpr uint32_t scanTimeMs = 5 * 1000;
|
||||
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
printf("Connected to: %s\n", pClient->getPeerAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
} clientCB;
|
||||
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if (advertisedDevice->haveName() && advertisedDevice->getName() == "NimBLE-Server") {
|
||||
printf("Found Our Device\n");
|
||||
|
||||
auto pClient = NimBLEDevice::getDisconnectedClient();
|
||||
if (!pClient) {
|
||||
pClient = NimBLEDevice::createClient(advertisedDevice->getAddress());
|
||||
if (!pClient) {
|
||||
printf("Failed to create client\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
if (!pClient->connect(true, true, false)) { // delete attributes, async connect, no MTU exchange
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onScanEnd(NimBLEScanResults results) {
|
||||
printf("Scan Ended\n");
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Async Client\n");
|
||||
NimBLEDevice::init("");
|
||||
NimBLEDevice::setPower(3); /** +3db */
|
||||
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setScanCallbacks(new scanCallbacks());
|
||||
pScan->setInterval(45);
|
||||
pScan->setWindow(15);
|
||||
pScan->setActiveScan(true);
|
||||
pScan->start(scanTimeMs);
|
||||
|
||||
for (;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
auto pClients = NimBLEDevice::getConnectedClients();
|
||||
if (!pClients.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& pClient : pClients) {
|
||||
printf("%s\n", pClient->toString().c_str());
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
}
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
}
|
12
examples/NimBLE_Async_Client/sdkconfig.defaults
Normal file
12
examples/NimBLE_Async_Client/sdkconfig.defaults
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
|
@ -65,6 +65,8 @@ NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress)
|
|||
m_terminateFailCount{0},
|
||||
m_deleteCallbacks{false},
|
||||
m_connEstablished{false},
|
||||
m_asyncConnect{false},
|
||||
m_exchangeMTU{true},
|
||||
# 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
|
||||
|
@ -123,35 +125,48 @@ size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) {
|
|||
} // deleteServices
|
||||
|
||||
/**
|
||||
* @brief Connect to the BLE Server.
|
||||
* @brief Connect to the BLE Server using the address of the last connected device, or the address\n
|
||||
* passed to the constructor.
|
||||
* @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.
|
||||
* have created when last connected.
|
||||
* @param [in] asyncConnect If true, the connection will be made asynchronously and this function will return immediately.\n
|
||||
* If false, this function will block until the connection is established or the connection attempt times out.
|
||||
* @param [in] exchangeMTU If true, the client will attempt to exchange MTU with the server after connection.\n
|
||||
* If false, the client will use the default MTU size and the application will need to call exchangeMTU() later.
|
||||
* @return true on success.
|
||||
*/
|
||||
bool NimBLEClient::connect(bool deleteAttributes) {
|
||||
return connect(m_peerAddress, deleteAttributes);
|
||||
bool NimBLEClient::connect(bool deleteAttributes, bool asyncConnect, bool exchangeMTU) {
|
||||
return connect(m_peerAddress, deleteAttributes, asyncConnect, exchangeMTU);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connect to an advertising device.
|
||||
* @param [in] device The device to connect to.
|
||||
* @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.
|
||||
* have created when last connected.
|
||||
* @param [in] asyncConnect If true, the connection will be made asynchronously and this function will return immediately.\n
|
||||
* If false, this function will block until the connection is established or the connection attempt times out.
|
||||
* @param [in] exchangeMTU If true, the client will attempt to exchange MTU with the server after connection.\n
|
||||
* If false, the client will use the default MTU size and the application will need to call exchangeMTU() later.
|
||||
* @return true on success.
|
||||
*/
|
||||
bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttributes) {
|
||||
bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttributes, bool asyncConnect, bool exchangeMTU) {
|
||||
NimBLEAddress address(device->getAddress());
|
||||
return connect(address, deleteAttributes);
|
||||
return connect(address, deleteAttributes, asyncConnect, exchangeMTU);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* have created when last connected.
|
||||
* @param [in] asyncConnect If true, the connection will be made asynchronously and this function will return immediately.\n
|
||||
* If false, this function will block until the connection is established or the connection attempt times out.
|
||||
* @param [in] exchangeMTU If true, the client will attempt to exchange MTU with the server after connection.\n
|
||||
* If false, the client will use the default MTU size and the application will need to call exchangeMTU() later.
|
||||
* @return true on success.
|
||||
*/
|
||||
bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes) {
|
||||
bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, bool asyncConnect, bool exchangeMTU) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
|
||||
|
||||
if (!NimBLEDevice::m_synced) {
|
||||
|
@ -159,8 +174,13 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
|
|||
return false;
|
||||
}
|
||||
|
||||
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());
|
||||
if (isConnected() || m_connEstablished) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Client already connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NimBLEDevice::isConnectionInProgress()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -177,10 +197,18 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
|
|||
m_peerAddress = address;
|
||||
}
|
||||
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
BleTaskData taskData = {this, cur_task, 0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
if (deleteAttributes) {
|
||||
deleteServices();
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
m_asyncConnect = asyncConnect;
|
||||
m_exchangeMTU = exchangeMTU;
|
||||
TaskHandle_t curTask = xTaskGetCurrentTaskHandle();
|
||||
BleTaskData taskData = {this, curTask, 0, nullptr};
|
||||
if (!asyncConnect) {
|
||||
m_pTaskData = &taskData;
|
||||
}
|
||||
|
||||
// Set the connection in progress flag to prevent a scan from starting while connecting.
|
||||
NimBLEDevice::setConnectionInProgress(true);
|
||||
|
@ -222,10 +250,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
|
|||
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());
|
||||
ble_gap_conn_cancel();
|
||||
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -239,16 +264,21 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
|
|||
|
||||
} while (rc == BLE_HS_EBUSY);
|
||||
|
||||
NimBLEDevice::setConnectionInProgress(false);
|
||||
m_lastErr = rc;
|
||||
if (rc != 0) {
|
||||
m_lastErr = rc;
|
||||
m_pTaskData = nullptr;
|
||||
NimBLEDevice::setConnectionInProgress(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_asyncConnect) {
|
||||
return true;
|
||||
}
|
||||
|
||||
# ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
ulTaskNotifyValueClear(curTask, ULONG_MAX);
|
||||
# endif
|
||||
// Wait for the connect timeout time +1 second for the connection to complete
|
||||
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||
|
@ -278,10 +308,6 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
|
|||
NIMBLE_LOGI(LOG_TAG, "Connection established");
|
||||
}
|
||||
|
||||
if (deleteAttributes) {
|
||||
deleteServices();
|
||||
}
|
||||
|
||||
m_connEstablished = true;
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
|
||||
|
@ -854,6 +880,41 @@ uint16_t NimBLEClient::getMTU() const {
|
|||
return ble_att_mtu(m_connHandle);
|
||||
} // getMTU
|
||||
|
||||
/**
|
||||
* @brief Callback for the MTU exchange API function.
|
||||
* @details When the MTU exchange is complete the API will call this and report the new MTU.
|
||||
*/
|
||||
int NimBLEClient::exchangeMTUCb(uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void* arg) {
|
||||
NIMBLE_LOGD(LOG_TAG, "exchangeMTUCb: status=%d, mtu=%d", error->status, mtu);
|
||||
|
||||
NimBLEClient* pClient = (NimBLEClient*)arg;
|
||||
if (pClient->getConnHandle() != conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error->status != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "exchangeMTUCb() rc=%d %s", error->status, NimBLEUtils::returnCodeToString(error->status));
|
||||
pClient->m_lastErr = error->status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Begin the MTU exchange process with the server.
|
||||
* @returns true if the request was sent successfully.
|
||||
*/
|
||||
bool NimBLEClient::exchangeMTU() {
|
||||
int rc = ble_gattc_exchange_mtu(m_connHandle, NimBLEClient::exchangeMTUCb, this);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
m_lastErr = rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} // exchangeMTU
|
||||
|
||||
/**
|
||||
* @brief Handle a received GAP event.
|
||||
* @param [in] event The event structure sent by the NimBLE stack.
|
||||
|
@ -908,30 +969,40 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
|||
|
||||
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 (pClient->isConnected() || (!pClient->m_asyncConnect && pClient->m_pTaskData == nullptr)) {
|
||||
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NimBLEDevice::setConnectionInProgress(false);
|
||||
rc = event->connect.status;
|
||||
if (rc == 0) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Connected event");
|
||||
|
||||
pClient->m_connHandle = event->connect.conn_handle;
|
||||
|
||||
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));
|
||||
if (pClient->m_exchangeMTU) {
|
||||
if (!pClient->exchangeMTU() && !pClient->m_asyncConnect) {
|
||||
rc = pClient->m_lastErr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// In the case of a multi-connecting device we ignore this device when
|
||||
// scanning since we are already connected to it
|
||||
NimBLEDevice::addIgnored(pClient->m_peerAddress);
|
||||
} else {
|
||||
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
if (!pClient->m_asyncConnect) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pClient->m_asyncConnect) {
|
||||
pClient->m_connEstablished = rc == 0;
|
||||
pClient->m_pClientCallbacks->onConnect(pClient);
|
||||
} else if (!pClient->m_exchangeMTU) {
|
||||
break; // not wating for MTU exchange so release the task now.
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_CONNECT
|
||||
|
@ -1072,7 +1143,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
|||
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: mtu=%d", event->mtu.value);
|
||||
pClient->m_pClientCallbacks->onMTUChange(pClient, event->mtu.value);
|
||||
rc = 0;
|
||||
break;
|
||||
} // BLE_GAP_EVENT_MTU
|
||||
|
@ -1204,4 +1277,8 @@ void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t
|
|||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
}
|
||||
|
||||
void NimBLEClientCallbacks::onMTUChange(NimBLEClient* pClient, uint16_t mtu) {
|
||||
NIMBLE_LOGD(CB_TAG, "onMTUChange: default");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
|
|
@ -44,9 +44,12 @@ struct BleTaskData;
|
|||
*/
|
||||
class NimBLEClient {
|
||||
public:
|
||||
bool connect(NimBLEAdvertisedDevice* device, bool deleteAttributes = true);
|
||||
bool connect(const NimBLEAddress& address, bool deleteAttributes = true);
|
||||
bool connect(bool deleteAttributes = true);
|
||||
bool connect(NimBLEAdvertisedDevice* device,
|
||||
bool deleteAttributes = true,
|
||||
bool asyncConnect = false,
|
||||
bool exchangeMTU = true);
|
||||
bool connect(const NimBLEAddress& address, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
|
||||
bool connect(bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
|
||||
bool disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
NimBLEAddress getPeerAddress() const;
|
||||
bool setPeerAddress(const NimBLEAddress& address);
|
||||
|
@ -59,6 +62,7 @@ class NimBLEClient {
|
|||
bool setConnection(const NimBLEConnInfo& connInfo);
|
||||
bool setConnection(uint16_t connHandle);
|
||||
uint16_t getMTU() const;
|
||||
bool exchangeMTU();
|
||||
bool secureConnection() const;
|
||||
void setConnectTimeout(uint32_t timeout);
|
||||
bool setDataLen(uint16_t txOctets);
|
||||
|
@ -98,6 +102,7 @@ class NimBLEClient {
|
|||
|
||||
bool retrieveServices(const NimBLEUUID* uuidFilter = nullptr);
|
||||
static int handleGapEvent(struct ble_gap_event* event, void* arg);
|
||||
static int exchangeMTUCb(uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void* arg);
|
||||
static int serviceDiscoveredCB(uint16_t connHandle,
|
||||
const struct ble_gatt_error* error,
|
||||
const struct ble_gatt_svc* service,
|
||||
|
@ -113,6 +118,8 @@ class NimBLEClient {
|
|||
uint8_t m_terminateFailCount;
|
||||
bool m_deleteCallbacks;
|
||||
bool m_connEstablished;
|
||||
bool m_asyncConnect;
|
||||
bool m_exchangeMTU;
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t m_phyMask;
|
||||
# endif
|
||||
|
@ -174,6 +181,14 @@ class NimBLEClientCallbacks {
|
|||
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
||||
*/
|
||||
virtual void onIdentity(NimBLEConnInfo& connInfo);
|
||||
|
||||
/**
|
||||
* @brief Called when the connection MTU changes.
|
||||
* @param [in] pClient A pointer to the client that the MTU change is associated with.
|
||||
* @param [in] MTU The new MTU value.
|
||||
* about the peer connection parameters.
|
||||
*/
|
||||
virtual void onMTUChange(NimBLEClient* pClient, uint16_t MTU);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
|
|
@ -405,7 +405,7 @@ NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress& addr) {
|
|||
} // getClientPeerAddress
|
||||
|
||||
/**
|
||||
* @brief Finds the first disconnected client in the list.
|
||||
* @brief Finds the first disconnected client available.
|
||||
* @return A pointer to the first client object that is not connected to a peer or nullptr.
|
||||
*/
|
||||
NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
||||
|
@ -418,6 +418,21 @@ NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
|||
return nullptr;
|
||||
} // getDisconnectedClient
|
||||
|
||||
/**
|
||||
* @brief Get a list of connected clients.
|
||||
* @return A vector of connected client objects.
|
||||
*/
|
||||
std::vector<NimBLEClient*> NimBLEDevice::getConnectedClients() {
|
||||
std::vector<NimBLEClient*> clients;
|
||||
for (const auto clt : m_pClients) {
|
||||
if (clt != nullptr && clt->isConnected()) {
|
||||
clients.push_back(clt);
|
||||
}
|
||||
}
|
||||
|
||||
return clients;
|
||||
} // getConnectedClients
|
||||
|
||||
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
|
@ -175,6 +175,7 @@ class NimBLEDevice {
|
|||
static NimBLEClient* getClientByPeerAddress(const NimBLEAddress& peerAddress);
|
||||
static NimBLEClient* getDisconnectedClient();
|
||||
static size_t getCreatedClientCount();
|
||||
static std::vector<NimBLEClient*> getConnectedClients();
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
|
Loading…
Reference in a new issue