@@ -65,6 +65,8 @@ NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress)
6565 m_terminateFailCount{0 },
6666 m_deleteCallbacks{false },
6767 m_connEstablished{false },
68+ m_asyncConnect{false },
69+ m_exchangeMTU{true },
6870# if CONFIG_BT_NIMBLE_EXT_ADV
6971 m_phyMask{BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK},
7072# endif
@@ -123,37 +125,54 @@ size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) {
123125} // deleteServices
124126
125127/* *
126- * @brief Connect to the BLE Server.
128+ * @brief Connect to the BLE Server using the address of the last connected device, or the address\n
129+ * passed to the constructor.
127130 * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
128- * have created and clears the vectors after successful connection.
129- * @return True on success.
131+ * have created when last connected.
132+ * @param [in] asyncConnect If true, the connection will be made asynchronously and this function will return immediately.\n
133+ * If false, this function will block until the connection is established or the connection attempt times out.
134+ * @param [in] exchangeMTU If true, the client will attempt to exchange MTU with the server after connection.\n
135+ * If false, the client will use the default MTU size and the application will need to call exchangeMTU() later.
136+ * @return true on success.
130137 */
131- bool NimBLEClient::connect (bool deleteAttributes) {
132- return connect (m_peerAddress, deleteAttributes);
138+ bool NimBLEClient::connect (bool deleteAttributes, bool asyncConnect, bool exchangeMTU ) {
139+ return connect (m_peerAddress, deleteAttributes, asyncConnect, exchangeMTU );
133140}
134141
135142/* *
136143 * @brief Connect to an advertising device.
137144 * @param [in] device The device to connect to.
138145 * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
139- * have created and clears the vectors after successful connection.
140- * @return True on success.
146+ * have created when last connected.
147+ * @param [in] asyncConnect If true, the connection will be made asynchronously and this function will return immediately.\n
148+ * If false, this function will block until the connection is established or the connection attempt times out.
149+ * @param [in] exchangeMTU If true, the client will attempt to exchange MTU with the server after connection.\n
150+ * If false, the client will use the default MTU size and the application will need to call exchangeMTU() later.
151+ * @return true on success.
141152 */
142- bool NimBLEClient::connect (NimBLEAdvertisedDevice* device, bool deleteAttributes) {
153+ bool NimBLEClient::connect (NimBLEAdvertisedDevice* device, bool deleteAttributes, bool asyncConnect, bool exchangeMTU ) {
143154 NimBLEAddress address (device->getAddress ());
144- return connect (address, deleteAttributes);
155+ return connect (address, deleteAttributes, asyncConnect, exchangeMTU );
145156}
146157
147158/* *
148159 * @brief Connect to a BLE Server by address.
149160 * @param [in] address The address of the server.
150161 * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
151- * have created and clears the vectors after successful connection.
152- * @return True on success.
162+ * have created when last connected.
163+ * @param [in] asyncConnect If true, the connection will be made asynchronously and this function will return immediately.\n
164+ * If false, this function will block until the connection is established or the connection attempt times out.
165+ * @param [in] exchangeMTU If true, the client will attempt to exchange MTU with the server after connection.\n
166+ * If false, the client will use the default MTU size and the application will need to call exchangeMTU() later.
167+ * @return true on success.
153168 */
154- bool NimBLEClient::connect (const NimBLEAddress& address, bool deleteAttributes) {
169+ bool NimBLEClient::connect (const NimBLEAddress& address, bool deleteAttributes, bool asyncConnect, bool exchangeMTU ) {
155170 NIMBLE_LOGD (LOG_TAG, " >> connect(%s)" , address.toString ().c_str ());
156171
172+ if (deleteAttributes) {
173+ deleteServices ();
174+ }
175+
157176 if (!NimBLEDevice::m_synced) {
158177 NIMBLE_LOGE (LOG_TAG, " Host reset, wait for sync." );
159178 return false ;
@@ -177,10 +196,14 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
177196 m_peerAddress = address;
178197 }
179198
199+ int rc = 0 ;
200+ m_asyncConnect = asyncConnect;
201+ m_exchangeMTU = exchangeMTU;
180202 TaskHandle_t cur_task = xTaskGetCurrentTaskHandle ();
181203 BleTaskData taskData = {this , cur_task, 0 , nullptr };
182- m_pTaskData = &taskData;
183- int rc = 0 ;
204+ if (!asyncConnect) {
205+ m_pTaskData = &taskData;
206+ }
184207
185208 do {
186209# if CONFIG_BT_NIMBLE_EXT_ADV
@@ -207,10 +230,11 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
207230 break ;
208231
209232 case BLE_HS_EBUSY:
210- // Scan was still running , stop it and try again
233+ // Scan was active , stop it through the NimBLEScan API to release any tasks and call the callback.
211234 if (!NimBLEDevice::getScan ()->stop ()) {
212235 rc = BLE_HS_EUNKNOWN;
213236 }
237+ ble_gap_disc_cancel (); // we call this in case the app restarted the scan in the callback.
214238 break ;
215239
216240 case BLE_HS_EDONE:
@@ -236,13 +260,16 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
236260
237261 } while (rc == BLE_HS_EBUSY);
238262
239- m_lastErr = rc;
240-
241263 if (rc != 0 ) {
264+ m_lastErr = rc;
242265 m_pTaskData = nullptr ;
243266 return false ;
244267 }
245268
269+ if (m_asyncConnect) {
270+ return true ;
271+ }
272+
246273# ifdef ulTaskNotifyValueClear
247274 // Clear the task notification value to ensure we block
248275 ulTaskNotifyValueClear (cur_task, ULONG_MAX);
@@ -275,10 +302,6 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
275302 NIMBLE_LOGI (LOG_TAG, " Connection established" );
276303 }
277304
278- if (deleteAttributes) {
279- deleteServices ();
280- }
281-
282305 m_connEstablished = true ;
283306 m_pClientCallbacks->onConnect (this );
284307
@@ -852,6 +875,41 @@ uint16_t NimBLEClient::getMTU() const {
852875 return ble_att_mtu (m_connHandle);
853876} // getMTU
854877
878+ /* *
879+ * @brief Callback for the MTU exchange API function.
880+ * @details When the MTU exchange is complete the API will call this and report the new MTU.
881+ */
882+ int NimBLEClient::exchangeMTUCb (uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void * arg) {
883+ NIMBLE_LOGD (LOG_TAG, " exchangeMTUCb: status=%d, mtu=%d" , error->status , mtu);
884+
885+ NimBLEClient* pClient = (NimBLEClient*)arg;
886+ if (pClient->getConnHandle () != conn_handle) {
887+ return 0 ;
888+ }
889+
890+ if (error->status != 0 ) {
891+ NIMBLE_LOGE (LOG_TAG, " exchangeMTUCb() rc=%d %s" , error->status , NimBLEUtils::returnCodeToString (error->status ));
892+ pClient->m_lastErr = error->status ;
893+ }
894+
895+ return 0 ;
896+ }
897+
898+ /* *
899+ * @brief Begin the MTU exchange process with the server.
900+ * @returns true if the request was sent successfully.
901+ */
902+ bool NimBLEClient::exchangeMTU () {
903+ int rc = ble_gattc_exchange_mtu (m_connHandle, NimBLEClient::exchangeMTUCb, this );
904+ if (rc != 0 ) {
905+ NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s" , rc, NimBLEUtils::returnCodeToString (rc));
906+ m_lastErr = rc;
907+ return false ;
908+ }
909+
910+ return true ;
911+ } // exchangeMTU
912+
855913/* *
856914 * @brief Handle a received GAP event.
857915 * @param [in] event The event structure sent by the NimBLE stack.
@@ -906,7 +964,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
906964
907965 case BLE_GAP_EVENT_CONNECT: {
908966 // If we aren't waiting for this connection response we should drop the connection immediately.
909- if (pClient->isConnected () || pClient->m_pTaskData == nullptr ) {
967+ if (pClient->isConnected () || (! pClient->m_asyncConnect && pClient-> m_pTaskData == nullptr ) ) {
910968 ble_gap_terminate (event->connect .conn_handle , BLE_ERR_REM_USER_CONN_TERM);
911969 return 0 ;
912970 }
@@ -916,19 +974,28 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
916974 NIMBLE_LOGI (LOG_TAG, " Connected event" );
917975
918976 pClient->m_connHandle = event->connect .conn_handle ;
919-
920- rc = ble_gattc_exchange_mtu ( pClient->m_connHandle , NULL , NULL );
921- if ( rc != 0 ) {
922- NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s " , rc, NimBLEUtils::returnCodeToString (rc)) ;
923- break ;
977+ if (pClient-> m_exchangeMTU ) {
978+ if (! pClient->exchangeMTU () && !pClient-> m_asyncConnect ) {
979+ rc = pClient-> m_lastErr ;
980+ break ;
981+ }
924982 }
925983
926984 // In the case of a multi-connecting device we ignore this device when
927985 // scanning since we are already connected to it
928986 NimBLEDevice::addIgnored (pClient->m_peerAddress );
929987 } else {
930988 pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
931- break ;
989+ if (!pClient->m_asyncConnect ) {
990+ break ;
991+ }
992+ }
993+
994+ if (pClient->m_asyncConnect ) {
995+ pClient->m_connEstablished = rc == 0 ;
996+ pClient->m_pClientCallbacks ->onConnect (pClient);
997+ } else if (!pClient->m_exchangeMTU ) {
998+ break ; // not wating for MTU exchange so release the task now.
932999 }
9331000
9341001 return 0 ;
@@ -1070,7 +1137,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10701137 if (pClient->m_connHandle != event->mtu .conn_handle ) {
10711138 return 0 ;
10721139 }
1073- NIMBLE_LOGI (LOG_TAG, " mtu update event; conn_handle=%d mtu=%d" , event->mtu .conn_handle , event->mtu .value );
1140+
1141+ NIMBLE_LOGI (LOG_TAG, " mtu update: mtu=%d" , event->mtu .value );
1142+ pClient->m_pClientCallbacks ->onMTUChange (pClient, event->mtu .value );
10741143 rc = 0 ;
10751144 break ;
10761145 } // BLE_GAP_EVENT_MTU
@@ -1202,4 +1271,8 @@ void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t
12021271 NimBLEDevice::injectConfirmPasskey (connInfo, true );
12031272}
12041273
1274+ void NimBLEClientCallbacks::onMTUChange (NimBLEClient* pClient, uint16_t mtu) {
1275+ NIMBLE_LOGD (CB_TAG, " onMTUChange: default" );
1276+ }
1277+
12051278#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
0 commit comments