Skip to content

Commit 86d5ebe

Browse files
committed
Refactor client connection establishment and client deletion.
* Removes the connection established flag as it should not be necessary. * Deleting the client instance from the `onDisconnect` callback is now supported. * `NimBLEDevice::deleteClient` no longer blocks tasks * Adds a new `Config` struct to `NimBLEClient` to efficiently set single bit config settings. * Adds `NimBLEClient::setSelfDelete` that takes the bool parameters `deleteOnDisconnect` and `deleteOnConnectFail` This will configure the client to delete itself when disconnected or the connection attempt fails. * Adds `NimBLEClient::setConfig` and `NimBLEClient::getConfig` which takes or returns a `NimBLEClient::Config` object respectively. * Reword `BLE_HS_EAPP` error string to be more accurate.
1 parent a59e8ee commit 86d5ebe

File tree

4 files changed

+116
-100
lines changed

4 files changed

+116
-100
lines changed

src/NimBLEClient.cpp

Lines changed: 82 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,7 @@ NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress)
6363
m_pClientCallbacks{&defaultCallbacks},
6464
m_connHandle{BLE_HS_CONN_HANDLE_NONE},
6565
m_terminateFailCount{0},
66-
m_deleteCallbacks{false},
67-
m_connEstablished{false},
68-
m_asyncConnect{false},
69-
m_exchangeMTU{true},
66+
m_config{},
7067
# if CONFIG_BT_NIMBLE_EXT_ADV
7168
m_phyMask{BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK},
7269
# endif
@@ -89,7 +86,7 @@ NimBLEClient::~NimBLEClient() {
8986
// Before we are finished with the client, we must release resources.
9087
deleteServices();
9188

92-
if (m_deleteCallbacks) {
89+
if (m_config.deleteCallbacks) {
9390
delete m_pClientCallbacks;
9491
}
9592
} // ~NimBLEClient
@@ -122,7 +119,7 @@ size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) {
122119
}
123120

124121
return m_svcVec.size();
125-
} // deleteServices
122+
} // deleteService
126123

127124
/**
128125
* @brief Connect to the BLE Server using the address of the last connected device, or the address\n
@@ -174,7 +171,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
174171
return false;
175172
}
176173

177-
if (isConnected() || m_connEstablished) {
174+
if (isConnected()) {
178175
NIMBLE_LOGE(LOG_TAG, "Client already connected");
179176
return false;
180177
}
@@ -201,9 +198,9 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
201198
deleteServices();
202199
}
203200

204-
int rc = 0;
205-
m_asyncConnect = asyncConnect;
206-
m_exchangeMTU = exchangeMTU;
201+
int rc = 0;
202+
m_config.asyncConnect = asyncConnect;
203+
m_config.exchangeMTU = exchangeMTU;
207204

208205
// Set the connection in progress flag to prevent a scan from starting while connecting.
209206
NimBLEDevice::setConnectionInProgress(true);
@@ -265,7 +262,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
265262
return false;
266263
}
267264

268-
if (m_asyncConnect) {
265+
if (m_config.asyncConnect) {
269266
return true;
270267
}
271268

@@ -289,19 +286,14 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
289286
rc = taskData.m_flags;
290287
if (rc != 0) {
291288
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
292-
// If the failure was not a result of a disconnection, make sure we disconnect now to avoid dangling connections
293-
if (isConnected()) {
294-
disconnect();
295-
}
296289
m_lastErr = rc;
290+
if (m_config.deleteOnConnectFail) {
291+
NimBLEDevice::deleteClient(this);
292+
}
297293
return false;
298-
} else {
299-
NIMBLE_LOGI(LOG_TAG, "Connection established");
300294
}
301295

302-
m_connEstablished = true;
303296
m_pClientCallbacks->onConnect(this);
304-
305297
NIMBLE_LOGD(LOG_TAG, "<< connect()");
306298
// Check if still connected before returning
307299
return isConnected();
@@ -357,7 +349,7 @@ bool NimBLEClient::disconnect(uint8_t reason) {
357349
* @brief Cancel an ongoing connection attempt.
358350
* @return True if the command was successfully sent.
359351
*/
360-
bool NimBLEClient::cancelConnect() {
352+
bool NimBLEClient::cancelConnect() const {
361353
int rc = ble_gap_conn_cancel();
362354
if (rc != 0 && rc != BLE_HS_EALREADY) {
363355
NIMBLE_LOGE(LOG_TAG, "ble_gap_conn_cancel failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
@@ -368,6 +360,32 @@ bool NimBLEClient::cancelConnect() {
368360
return true;
369361
} // cancelConnect
370362

363+
/**
364+
* @brief Set or unset a flag to delete this client when disconnected or connection failed.
365+
* @param [in] deleteOnDisconnect Set the client to self delete when disconnected.
366+
* @param [in] deleteOnConnectFail Set the client to self delete when a connection attempt fails.
367+
*/
368+
void NimBLEClient::setSelfDelete(bool deleteOnDisconnect, bool deleteOnConnectFail) {
369+
m_config.deleteOnDisconnect = deleteOnDisconnect;
370+
m_config.deleteOnConnectFail = deleteOnConnectFail;
371+
} // setSelfDelete
372+
373+
/**
374+
* @brief Get a copy of the clients configuration.
375+
* @return A copy of the clients configuration.
376+
*/
377+
NimBLEClient::Config NimBLEClient::getConfig() const {
378+
return m_config;
379+
} // getConfig
380+
381+
/**
382+
* @brief Set the client configuration options.
383+
* @param [in] config The config options instance to set the client configuration to.
384+
*/
385+
void NimBLEClient::setConfig(NimBLEClient::Config config) {
386+
m_config = config;
387+
} // setConfig
388+
371389
# if CONFIG_BT_NIMBLE_EXT_ADV
372390
/**
373391
* @brief Set the PHY types to use when connecting to a server.
@@ -492,9 +510,8 @@ uint16_t NimBLEClient::getConnHandle() const {
492510
* To disconnect from a peer, use disconnect().
493511
*/
494512
void NimBLEClient::clearConnection() {
495-
m_connHandle = BLE_HS_CONN_HANDLE_NONE;
496-
m_connEstablished = false;
497-
m_peerAddress = NimBLEAddress{};
513+
m_connHandle = BLE_HS_CONN_HANDLE_NONE;
514+
m_peerAddress = NimBLEAddress{};
498515
} // clearConnection
499516

500517
/**
@@ -509,15 +526,13 @@ void NimBLEClient::clearConnection() {
509526
* This enables the GATT Server to read the attributes of the client connected to it.
510527
*/
511528
bool NimBLEClient::setConnection(const NimBLEConnInfo& connInfo) {
512-
if (isConnected() || m_connEstablished) {
529+
if (isConnected()) {
513530
NIMBLE_LOGE(LOG_TAG, "Already connected");
514531
return false;
515532
}
516533

517-
m_peerAddress = connInfo.getAddress();
518-
m_connHandle = connInfo.getConnHandle();
519-
m_connEstablished = true;
520-
534+
m_peerAddress = connInfo.getAddress();
535+
m_connHandle = connInfo.getConnHandle();
521536
return true;
522537
} // setConnection
523538

@@ -902,16 +917,17 @@ bool NimBLEClient::exchangeMTU() {
902917
* @param [in] arg A pointer to the client instance that registered for this callback.
903918
*/
904919
int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
905-
NimBLEClient* pClient = (NimBLEClient*)arg;
906-
int rc = 0;
920+
NimBLEClient* pClient = (NimBLEClient*)arg;
921+
int rc = 0;
922+
NimBLETaskData* pTaskData = pClient->m_pTaskData; // save a copy in case client is deleted
907923

908924
NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type));
909925

910926
switch (event->type) {
911927
case BLE_GAP_EVENT_DISCONNECT: {
912928
rc = event->disconnect.reason;
913929
// If Host reset tell the device now before returning to prevent
914-
// any errors caused by calling host functions before resyncing.
930+
// any errors caused by calling host functions before re-syncing.
915931
switch (rc) {
916932
case BLE_HS_ECONTROLLER:
917933
case BLE_HS_ETIMEOUT_HCI:
@@ -929,41 +945,46 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
929945
break;
930946
}
931947

948+
NIMBLE_LOGD(LOG_TAG, "disconnect; reason=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
949+
932950
pClient->m_terminateFailCount = 0;
933951
NimBLEDevice::removeIgnored(pClient->m_peerAddress);
934-
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
935952

936-
// If we received a connected event but did not get established
937-
// then a disconnect event will be sent but we should not send it to the
938-
// app for processing. Instead we will ensure the task is released
939-
// and report the error.
940-
if (!pClient->m_connEstablished) {
941-
break;
953+
// Don't call the disconnect callback if we are waiting for a connection to complete and it fails
954+
if (rc != (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT) || pClient->m_config.asyncConnect) {
955+
pClient->m_pClientCallbacks->onDisconnect(pClient, rc);
942956
}
943957

944-
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
958+
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
959+
960+
if (pClient->m_config.deleteOnDisconnect) {
961+
// If we are set to self delete on disconnect but we have a task waiting on the connection
962+
// completion we will set the flag to delete on connect fail instead of deleting here
963+
// to prevent segmentation faults or double deleting
964+
if (pTaskData != nullptr && rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT)) {
965+
pClient->m_config.deleteOnConnectFail = true;
966+
break;
967+
}
968+
NimBLEDevice::deleteClient(pClient);
969+
}
945970

946-
pClient->m_connEstablished = false;
947-
pClient->m_pClientCallbacks->onDisconnect(pClient, rc);
948971
break;
949972
} // BLE_GAP_EVENT_DISCONNECT
950973

951974
case BLE_GAP_EVENT_CONNECT: {
952975
// If we aren't waiting for this connection response we should drop the connection immediately.
953-
if (pClient->isConnected() || (!pClient->m_asyncConnect && pClient->m_pTaskData == nullptr)) {
976+
if (pClient->isConnected() || (!pClient->m_config.asyncConnect && pClient->m_pTaskData == nullptr)) {
954977
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
955978
return 0;
956979
}
957980

958981
NimBLEDevice::setConnectionInProgress(false);
959982
rc = event->connect.status;
960983
if (rc == 0) {
961-
NIMBLE_LOGI(LOG_TAG, "Connected event");
962-
963984
pClient->m_connHandle = event->connect.conn_handle;
964-
if (pClient->m_exchangeMTU) {
965-
if (!pClient->exchangeMTU() && !pClient->m_asyncConnect) {
966-
rc = pClient->m_lastErr;
985+
if (pClient->m_config.exchangeMTU) {
986+
if (!pClient->exchangeMTU() && !pClient->m_config.asyncConnect) {
987+
rc = pClient->m_lastErr; // sets the error in the task data
967988
break;
968989
}
969990
}
@@ -973,15 +994,19 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
973994
NimBLEDevice::addIgnored(pClient->m_peerAddress);
974995
} else {
975996
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
976-
if (!pClient->m_asyncConnect) {
997+
if (!pClient->m_config.asyncConnect) {
977998
break;
978999
}
1000+
1001+
if (pClient->m_config.deleteOnConnectFail) { // async connect
1002+
delete pClient;
1003+
return 0;
1004+
}
9791005
}
9801006

981-
if (pClient->m_asyncConnect) {
982-
pClient->m_connEstablished = rc == 0;
1007+
if (pClient->m_config.asyncConnect) {
9831008
pClient->m_pClientCallbacks->onConnect(pClient);
984-
} else if (!pClient->m_exchangeMTU) {
1009+
} else if (!pClient->m_config.exchangeMTU) {
9851010
break; // not waiting for MTU exchange so release the task now.
9861011
}
9871012

@@ -1004,13 +1029,6 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10041029

10051030
case BLE_GAP_EVENT_NOTIFY_RX: {
10061031
if (pClient->m_connHandle != event->notify_rx.conn_handle) return 0;
1007-
1008-
// If a notification comes before this flag is set we might
1009-
// access a vector while it is being cleared in connect()
1010-
if (!pClient->m_connEstablished) {
1011-
return 0;
1012-
}
1013-
10141032
NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", event->notify_rx.attr_handle);
10151033

10161034
for (const auto& svc : pClient->m_svcVec) {
@@ -1169,8 +1187,8 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
11691187
}
11701188
} // Switch
11711189

1172-
if (pClient->m_pTaskData != nullptr) {
1173-
NimBLEUtils::taskRelease(*pClient->m_pTaskData, rc);
1190+
if (pTaskData != nullptr) {
1191+
NimBLEUtils::taskRelease(*pTaskData, rc);
11741192
}
11751193

11761194
return 0;
@@ -1191,11 +1209,11 @@ bool NimBLEClient::isConnected() const {
11911209
*/
11921210
void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) {
11931211
if (pClientCallbacks != nullptr) {
1194-
m_pClientCallbacks = pClientCallbacks;
1195-
m_deleteCallbacks = deleteCallbacks;
1212+
m_pClientCallbacks = pClientCallbacks;
1213+
m_config.deleteCallbacks = deleteCallbacks;
11961214
} else {
1197-
m_pClientCallbacks = &defaultCallbacks;
1198-
m_deleteCallbacks = false;
1215+
m_pClientCallbacks = &defaultCallbacks;
1216+
m_config.deleteCallbacks = false;
11991217
}
12001218
} // setClientCallbacks
12011219

src/NimBLEClient.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ class NimBLEClient {
5151
bool connect(const NimBLEAddress& address, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
5252
bool connect(bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
5353
bool disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
54-
bool cancelConnect();
54+
bool cancelConnect() const;
55+
void setSelfDelete(bool deleteOnDisconnect, bool deleteOnConnectFail);
5556
NimBLEAddress getPeerAddress() const;
5657
bool setPeerAddress(const NimBLEAddress& address);
5758
int getRssi() const;
@@ -95,6 +96,17 @@ class NimBLEClient {
9596
void setConnectPhy(uint8_t mask);
9697
# endif
9798

99+
struct Config {
100+
uint8_t deleteCallbacks : 1; // Delete the callback object when the client is deleted.
101+
uint8_t deleteOnDisconnect : 1; // Delete the client when disconnected.
102+
uint8_t deleteOnConnectFail : 1; // Delete the client when a connection attempt fails.
103+
uint8_t asyncConnect : 1; // Connect asynchronously.
104+
uint8_t exchangeMTU : 1; // Exchange MTU after connection.
105+
};
106+
107+
Config getConfig() const;
108+
void setConfig(Config config);
109+
98110
private:
99111
NimBLEClient(const NimBLEAddress& peerAddress);
100112
~NimBLEClient();
@@ -117,10 +129,8 @@ class NimBLEClient {
117129
NimBLEClientCallbacks* m_pClientCallbacks;
118130
uint16_t m_connHandle;
119131
uint8_t m_terminateFailCount;
120-
bool m_deleteCallbacks;
121-
bool m_connEstablished;
122-
bool m_asyncConnect;
123-
bool m_exchangeMTU;
132+
Config m_config;
133+
124134
# if CONFIG_BT_NIMBLE_EXT_ADV
125135
uint8_t m_phyMask;
126136
# endif

0 commit comments

Comments
 (0)