@@ -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
@@ -763,6 +778,12 @@ int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle,
763778 NimBLETaskData* pTaskData = (NimBLETaskData*)arg;
764779 NimBLEClient* pClient = (NimBLEClient*)pTaskData->m_pInstance ;
765780
781+ if (error->status == BLE_HS_ENOTCONN) {
782+ NIMBLE_LOGE (LOG_TAG, " << Service Discovered; Not connected" );
783+ NimBLEUtils::taskRelease (*pTaskData, error->status );
784+ return error->status ;
785+ }
786+
766787 // Make sure the service discovery is for this device
767788 if (pClient->getConnHandle () != connHandle) {
768789 return 0 ;
@@ -902,8 +923,9 @@ bool NimBLEClient::exchangeMTU() {
902923 * @param [in] arg A pointer to the client instance that registered for this callback.
903924 */
904925int NimBLEClient::handleGapEvent (struct ble_gap_event * event, void * arg) {
905- NimBLEClient* pClient = (NimBLEClient*)arg;
906- int rc = 0 ;
926+ NimBLEClient* pClient = (NimBLEClient*)arg;
927+ int rc = 0 ;
928+ NimBLETaskData* pTaskData = pClient->m_pTaskData ; // save a copy in case client is deleted
907929
908930 NIMBLE_LOGD (LOG_TAG, " Got Client event %s" , NimBLEUtils::gapEventToString (event->type ));
909931
@@ -917,7 +939,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
917939
918940 rc = event->disconnect .reason ;
919941 // If Host reset tell the device now before returning to prevent
920- // any errors caused by calling host functions before resyncing .
942+ // any errors caused by calling host functions before re-syncing .
921943 switch (rc) {
922944 case BLE_HS_ECONTROLLER:
923945 case BLE_HS_ETIMEOUT_HCI:
@@ -930,41 +952,46 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
930952 break ;
931953 }
932954
955+ NIMBLE_LOGD (LOG_TAG, " disconnect; reason=%d, %s" , rc, NimBLEUtils::returnCodeToString (rc));
956+
933957 pClient->m_terminateFailCount = 0 ;
934958 NimBLEDevice::removeIgnored (pClient->m_peerAddress );
935- pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
936959
937- // If we received a connected event but did not get established
938- // then a disconnect event will be sent but we should not send it to the
939- // app for processing. Instead we will ensure the task is released
940- // and report the error.
941- if (!pClient->m_connEstablished ) {
942- break ;
960+ // Don't call the disconnect callback if we are waiting for a connection to complete and it fails
961+ if (rc != (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT) || pClient->m_config .asyncConnect ) {
962+ pClient->m_pClientCallbacks ->onDisconnect (pClient, rc);
943963 }
944964
945- NIMBLE_LOGI (LOG_TAG, " disconnect; reason=%d, %s" , rc, NimBLEUtils::returnCodeToString (rc));
965+ pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
966+
967+ if (pClient->m_config .deleteOnDisconnect ) {
968+ // If we are set to self delete on disconnect but we have a task waiting on the connection
969+ // completion we will set the flag to delete on connect fail instead of deleting here
970+ // to prevent segmentation faults or double deleting
971+ if (pTaskData != nullptr && rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT)) {
972+ pClient->m_config .deleteOnConnectFail = true ;
973+ break ;
974+ }
975+ NimBLEDevice::deleteClient (pClient);
976+ }
946977
947- pClient->m_connEstablished = false ;
948- pClient->m_pClientCallbacks ->onDisconnect (pClient, rc);
949978 break ;
950979 } // BLE_GAP_EVENT_DISCONNECT
951980
952981 case BLE_GAP_EVENT_CONNECT: {
953982 // If we aren't waiting for this connection response we should drop the connection immediately.
954- if (pClient->isConnected () || (!pClient->m_asyncConnect && pClient->m_pTaskData == nullptr )) {
983+ if (pClient->isConnected () || (!pClient->m_config . asyncConnect && pClient->m_pTaskData == nullptr )) {
955984 ble_gap_terminate (event->connect .conn_handle , BLE_ERR_REM_USER_CONN_TERM);
956985 return 0 ;
957986 }
958987
959988 NimBLEDevice::setConnectionInProgress (false );
960989 rc = event->connect .status ;
961990 if (rc == 0 ) {
962- NIMBLE_LOGI (LOG_TAG, " Connected event" );
963-
964991 pClient->m_connHandle = event->connect .conn_handle ;
965- if (pClient->m_exchangeMTU ) {
966- if (!pClient->exchangeMTU () && !pClient->m_asyncConnect ) {
967- rc = pClient->m_lastErr ;
992+ if (pClient->m_config . exchangeMTU ) {
993+ if (!pClient->exchangeMTU () && !pClient->m_config . asyncConnect ) {
994+ rc = pClient->m_lastErr ; // sets the error in the task data
968995 break ;
969996 }
970997 }
@@ -974,15 +1001,19 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
9741001 NimBLEDevice::addIgnored (pClient->m_peerAddress );
9751002 } else {
9761003 pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
977- if (!pClient->m_asyncConnect ) {
1004+ if (!pClient->m_config . asyncConnect ) {
9781005 break ;
9791006 }
1007+
1008+ if (pClient->m_config .deleteOnConnectFail ) { // async connect
1009+ delete pClient;
1010+ return 0 ;
1011+ }
9801012 }
9811013
982- if (pClient->m_asyncConnect ) {
983- pClient->m_connEstablished = rc == 0 ;
1014+ if (pClient->m_config .asyncConnect ) {
9841015 pClient->m_pClientCallbacks ->onConnect (pClient);
985- } else if (!pClient->m_exchangeMTU ) {
1016+ } else if (!pClient->m_config . exchangeMTU ) {
9861017 break ; // not waiting for MTU exchange so release the task now.
9871018 }
9881019
@@ -1005,13 +1036,6 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10051036
10061037 case BLE_GAP_EVENT_NOTIFY_RX: {
10071038 if (pClient->m_connHandle != event->notify_rx .conn_handle ) return 0 ;
1008-
1009- // If a notification comes before this flag is set we might
1010- // access a vector while it is being cleared in connect()
1011- if (!pClient->m_connEstablished ) {
1012- return 0 ;
1013- }
1014-
10151039 NIMBLE_LOGD (LOG_TAG, " Notify Received for handle: %d" , event->notify_rx .attr_handle );
10161040
10171041 for (const auto & svc : pClient->m_svcVec ) {
@@ -1170,8 +1194,8 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
11701194 }
11711195 } // Switch
11721196
1173- if (pClient-> m_pTaskData != nullptr ) {
1174- NimBLEUtils::taskRelease (*pClient-> m_pTaskData , rc);
1197+ if (pTaskData != nullptr ) {
1198+ NimBLEUtils::taskRelease (*pTaskData , rc);
11751199 }
11761200
11771201 return 0 ;
@@ -1192,11 +1216,11 @@ bool NimBLEClient::isConnected() const {
11921216 */
11931217void NimBLEClient::setClientCallbacks (NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) {
11941218 if (pClientCallbacks != nullptr ) {
1195- m_pClientCallbacks = pClientCallbacks;
1196- m_deleteCallbacks = deleteCallbacks;
1219+ m_pClientCallbacks = pClientCallbacks;
1220+ m_config. deleteCallbacks = deleteCallbacks;
11971221 } else {
1198- m_pClientCallbacks = &defaultCallbacks;
1199- m_deleteCallbacks = false ;
1222+ m_pClientCallbacks = &defaultCallbacks;
1223+ m_config. deleteCallbacks = false ;
12001224 }
12011225} // setClientCallbacks
12021226
0 commit comments