@@ -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 */
494513void 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 */
511529bool 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 */
904920int 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 */
11921203void 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
0 commit comments