Skip to content

Commit 7a98fa8

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 7a98fa8

File tree

4 files changed

+112
-102
lines changed

4 files changed

+112
-102
lines changed

src/NimBLEClient.cpp

Lines changed: 78 additions & 67 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,9 +86,10 @@ 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
}
92+
printf("client deleted\n");
9593
} // ~NimBLEClient
9694

9795
/**
@@ -122,7 +120,7 @@ size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) {
122120
}
123121

124122
return m_svcVec.size();
125-
} // deleteServices
123+
} // deleteService
126124

127125
/**
128126
* @brief Connect to the BLE Server using the address of the last connected device, or the address\n
@@ -174,7 +172,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
174172
return false;
175173
}
176174

177-
if (isConnected() || m_connEstablished) {
175+
if (isConnected()) {
178176
NIMBLE_LOGE(LOG_TAG, "Client already connected");
179177
return false;
180178
}
@@ -201,9 +199,9 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
201199
deleteServices();
202200
}
203201

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

208206
// Set the connection in progress flag to prevent a scan from starting while connecting.
209207
NimBLEDevice::setConnectionInProgress(true);
@@ -265,7 +263,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
265263
return false;
266264
}
267265

268-
if (m_asyncConnect) {
266+
if (m_config.asyncConnect) {
269267
return true;
270268
}
271269

@@ -289,19 +287,14 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
289287
rc = taskData.m_flags;
290288
if (rc != 0) {
291289
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-
}
296290
m_lastErr = rc;
291+
if (m_config.deleteOnConnectFail) {
292+
delete this;
293+
}
297294
return false;
298-
} else {
299-
NIMBLE_LOGI(LOG_TAG, "Connection established");
300295
}
301296

302-
m_connEstablished = true;
303297
m_pClientCallbacks->onConnect(this);
304-
305298
NIMBLE_LOGD(LOG_TAG, "<< connect()");
306299
// Check if still connected before returning
307300
return isConnected();
@@ -357,7 +350,7 @@ bool NimBLEClient::disconnect(uint8_t reason) {
357350
* @brief Cancel an ongoing connection attempt.
358351
* @return True if the command was successfully sent.
359352
*/
360-
bool NimBLEClient::cancelConnect() {
353+
bool NimBLEClient::cancelConnect() const {
361354
int rc = ble_gap_conn_cancel();
362355
if (rc != 0 && rc != BLE_HS_EALREADY) {
363356
NIMBLE_LOGE(LOG_TAG, "ble_gap_conn_cancel failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
@@ -368,6 +361,32 @@ bool NimBLEClient::cancelConnect() {
368361
return true;
369362
} // cancelConnect
370363

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

500518
/**
@@ -509,15 +527,13 @@ void NimBLEClient::clearConnection() {
509527
* This enables the GATT Server to read the attributes of the client connected to it.
510528
*/
511529
bool NimBLEClient::setConnection(const NimBLEConnInfo& connInfo) {
512-
if (isConnected() || m_connEstablished) {
530+
if (isConnected()) {
513531
NIMBLE_LOGE(LOG_TAG, "Already connected");
514532
return false;
515533
}
516534

517-
m_peerAddress = connInfo.getAddress();
518-
m_connHandle = connInfo.getConnHandle();
519-
m_connEstablished = true;
520-
535+
m_peerAddress = connInfo.getAddress();
536+
m_connHandle = connInfo.getConnHandle();
521537
return true;
522538
} // setConnection
523539

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

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

910927
switch (event->type) {
911928
case BLE_GAP_EVENT_DISCONNECT: {
912929
rc = event->disconnect.reason;
913930
// If Host reset tell the device now before returning to prevent
914-
// any errors caused by calling host functions before resyncing.
931+
// any errors caused by calling host functions before re-syncing.
915932
switch (rc) {
916933
case BLE_HS_ECONTROLLER:
917934
case BLE_HS_ETIMEOUT_HCI:
@@ -929,41 +946,38 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
929946
break;
930947
}
931948

949+
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
932950
pClient->m_terminateFailCount = 0;
933951
NimBLEDevice::removeIgnored(pClient->m_peerAddress);
934-
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
935-
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;
942-
}
943-
944-
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
945-
946-
pClient->m_connEstablished = false;
952+
NIMBLE_LOGD(LOG_TAG, "disconnect; reason=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
947953
pClient->m_pClientCallbacks->onDisconnect(pClient, rc);
954+
if (pClient->m_config.deleteOnDisconnect) {
955+
// If we are set to self delete on disconnect but we have a task waiting on the connection
956+
// completion we will set the flag to delete on connect fail instead of deleting here
957+
// to prevent segmentation faults or double deleting
958+
if (pTaskData != nullptr && rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT)) {
959+
pClient->m_config.deleteOnConnectFail = true;
960+
break;
961+
}
962+
delete pClient;
963+
}
948964
break;
949965
} // BLE_GAP_EVENT_DISCONNECT
950966

951967
case BLE_GAP_EVENT_CONNECT: {
952968
// 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)) {
969+
if (pClient->isConnected() || (!pClient->m_config.asyncConnect && pClient->m_pTaskData == nullptr)) {
954970
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
955971
return 0;
956972
}
957973

958974
NimBLEDevice::setConnectionInProgress(false);
959975
rc = event->connect.status;
960976
if (rc == 0) {
961-
NIMBLE_LOGI(LOG_TAG, "Connected event");
962-
963977
pClient->m_connHandle = event->connect.conn_handle;
964-
if (pClient->m_exchangeMTU) {
965-
if (!pClient->exchangeMTU() && !pClient->m_asyncConnect) {
966-
rc = pClient->m_lastErr;
978+
if (pClient->m_config.exchangeMTU) {
979+
if (!pClient->exchangeMTU() && !pClient->m_config.asyncConnect) {
980+
rc = pClient->m_lastErr; // sets the error in the task data
967981
break;
968982
}
969983
}
@@ -973,15 +987,19 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
973987
NimBLEDevice::addIgnored(pClient->m_peerAddress);
974988
} else {
975989
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
976-
if (!pClient->m_asyncConnect) {
990+
if (!pClient->m_config.asyncConnect) {
977991
break;
978992
}
993+
994+
if (pClient->m_config.deleteOnConnectFail) { // async connect
995+
delete pClient;
996+
return 0;
997+
}
979998
}
980999

981-
if (pClient->m_asyncConnect) {
982-
pClient->m_connEstablished = rc == 0;
1000+
if (pClient->m_config.asyncConnect) {
9831001
pClient->m_pClientCallbacks->onConnect(pClient);
984-
} else if (!pClient->m_exchangeMTU) {
1002+
} else if (!pClient->m_config.exchangeMTU) {
9851003
break; // not waiting for MTU exchange so release the task now.
9861004
}
9871005

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

10051023
case BLE_GAP_EVENT_NOTIFY_RX: {
10061024
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-
10141025
NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", event->notify_rx.attr_handle);
10151026

10161027
for (const auto& svc : pClient->m_svcVec) {
@@ -1169,8 +1180,8 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
11691180
}
11701181
} // Switch
11711182

1172-
if (pClient->m_pTaskData != nullptr) {
1173-
NimBLEUtils::taskRelease(*pClient->m_pTaskData, rc);
1183+
if (pTaskData != nullptr) {
1184+
NimBLEUtils::taskRelease(*pTaskData, rc);
11741185
}
11751186

11761187
return 0;
@@ -1191,11 +1202,11 @@ bool NimBLEClient::isConnected() const {
11911202
*/
11921203
void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) {
11931204
if (pClientCallbacks != nullptr) {
1194-
m_pClientCallbacks = pClientCallbacks;
1195-
m_deleteCallbacks = deleteCallbacks;
1205+
m_pClientCallbacks = pClientCallbacks;
1206+
m_config.deleteCallbacks = deleteCallbacks;
11961207
} else {
1197-
m_pClientCallbacks = &defaultCallbacks;
1198-
m_deleteCallbacks = false;
1208+
m_pClientCallbacks = &defaultCallbacks;
1209+
m_config.deleteCallbacks = false;
11991210
}
12001211
} // setClientCallbacks
12011212

src/NimBLEClient.h

Lines changed: 17 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,19 @@ class NimBLEClient {
9596
void setConnectPhy(uint8_t mask);
9697
# endif
9798

99+
// clang-format off
100+
struct Config {
101+
uint8_t deleteCallbacks : 1,
102+
deleteOnDisconnect : 1,
103+
deleteOnConnectFail : 1,
104+
asyncConnect : 1,
105+
exchangeMTU : 1,
106+
selfDeleteFlags : 1;
107+
};
108+
// clang-format on
109+
Config getConfig() const;
110+
void setConfig(NimBLEClient::Config config);
111+
98112
private:
99113
NimBLEClient(const NimBLEAddress& peerAddress);
100114
~NimBLEClient();
@@ -117,10 +131,8 @@ class NimBLEClient {
117131
NimBLEClientCallbacks* m_pClientCallbacks;
118132
uint16_t m_connHandle;
119133
uint8_t m_terminateFailCount;
120-
bool m_deleteCallbacks;
121-
bool m_connEstablished;
122-
bool m_asyncConnect;
123-
bool m_exchangeMTU;
134+
Config m_config;
135+
124136
# if CONFIG_BT_NIMBLE_EXT_ADV
125137
uint8_t m_phyMask;
126138
# endif

0 commit comments

Comments
 (0)