@@ -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 */
494512void 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 */
511528bool 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 */
904919int 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 */
11921210void 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
0 commit comments