@@ -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
@@ -236,13 +259,16 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
236259
237260 } while (rc == BLE_HS_EBUSY);
238261
239- m_lastErr = rc;
240-
241262 if (rc != 0 ) {
263+ m_lastErr = rc;
242264 m_pTaskData = nullptr ;
243265 return false ;
244266 }
245267
268+ if (m_asyncConnect) {
269+ return true ;
270+ }
271+
246272# ifdef ulTaskNotifyValueClear
247273 // Clear the task notification value to ensure we block
248274 ulTaskNotifyValueClear (cur_task, ULONG_MAX);
@@ -275,10 +301,6 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
275301 NIMBLE_LOGI (LOG_TAG, " Connection established" );
276302 }
277303
278- if (deleteAttributes) {
279- deleteServices ();
280- }
281-
282304 m_connEstablished = true ;
283305 m_pClientCallbacks->onConnect (this );
284306
@@ -852,6 +874,41 @@ uint16_t NimBLEClient::getMTU() const {
852874 return ble_att_mtu (m_connHandle);
853875} // getMTU
854876
877+ /* *
878+ * @brief Callback for the MTU exchange API function.
879+ * @details When the MTU exchange is complete the API will call this and report the new MTU.
880+ */
881+ int NimBLEClient::exchangeMTUCb (uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void * arg) {
882+ NIMBLE_LOGD (LOG_TAG, " exchangeMTUCb: status=%d, mtu=%d" , error->status , mtu);
883+
884+ NimBLEClient* pClient = (NimBLEClient*)arg;
885+ if (pClient->getConnHandle () != conn_handle) {
886+ return 0 ;
887+ }
888+
889+ if (error->status != 0 ) {
890+ NIMBLE_LOGE (LOG_TAG, " exchangeMTUCb() rc=%d %s" , error->status , NimBLEUtils::returnCodeToString (error->status ));
891+ pClient->m_lastErr = error->status ;
892+ }
893+
894+ return 0 ;
895+ }
896+
897+ /* *
898+ * @brief Begin the MTU exchange process with the server.
899+ * @returns true if the request was sent successfully.
900+ */
901+ bool NimBLEClient::exchangeMTU () {
902+ int rc = ble_gattc_exchange_mtu (m_connHandle, NimBLEClient::exchangeMTUCb, this );
903+ if (rc != 0 ) {
904+ NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s" , rc, NimBLEUtils::returnCodeToString (rc));
905+ m_lastErr = rc;
906+ return false ;
907+ }
908+
909+ return true ;
910+ } // exchangeMTU
911+
855912/* *
856913 * @brief Handle a received GAP event.
857914 * @param [in] event The event structure sent by the NimBLE stack.
@@ -906,7 +963,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
906963
907964 case BLE_GAP_EVENT_CONNECT: {
908965 // If we aren't waiting for this connection response we should drop the connection immediately.
909- if (pClient->isConnected () || pClient->m_pTaskData == nullptr ) {
966+ if (pClient->isConnected () || (! pClient->m_asyncConnect && pClient-> m_pTaskData == nullptr ) ) {
910967 ble_gap_terminate (event->connect .conn_handle , BLE_ERR_REM_USER_CONN_TERM);
911968 return 0 ;
912969 }
@@ -916,19 +973,28 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
916973 NIMBLE_LOGI (LOG_TAG, " Connected event" );
917974
918975 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 ;
976+ if (pClient-> m_exchangeMTU ) {
977+ if (! pClient->exchangeMTU () && !pClient-> m_asyncConnect ) {
978+ rc = pClient-> m_lastErr ;
979+ break ;
980+ }
924981 }
925982
926983 // In the case of a multi-connecting device we ignore this device when
927984 // scanning since we are already connected to it
928985 NimBLEDevice::addIgnored (pClient->m_peerAddress );
929986 } else {
930987 pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
931- break ;
988+ if (!pClient->m_asyncConnect ) {
989+ break ;
990+ }
991+ }
992+
993+ if (pClient->m_asyncConnect ) {
994+ pClient->m_connEstablished = rc == 0 ;
995+ pClient->m_pClientCallbacks ->onConnect (pClient);
996+ } else if (!pClient->m_exchangeMTU ) {
997+ break ; // not wating for MTU exchange so release the task now.
932998 }
933999
9341000 return 0 ;
@@ -1070,7 +1136,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10701136 if (pClient->m_connHandle != event->mtu .conn_handle ) {
10711137 return 0 ;
10721138 }
1073- NIMBLE_LOGI (LOG_TAG, " mtu update event; conn_handle=%d mtu=%d" , event->mtu .conn_handle , event->mtu .value );
1139+
1140+ NIMBLE_LOGI (LOG_TAG, " mtu update: mtu=%d" , event->mtu .value );
1141+ pClient->m_pClientCallbacks ->onMTUChange (pClient, event->mtu .value );
10741142 rc = 0 ;
10751143 break ;
10761144 } // BLE_GAP_EVENT_MTU
@@ -1202,4 +1270,8 @@ void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t
12021270 NimBLEDevice::injectConfirmPasskey (connInfo, true );
12031271}
12041272
1273+ void NimBLEClientCallbacks::onMTUChange (NimBLEClient* pClient, uint16_t mtu) {
1274+ NIMBLE_LOGD (CB_TAG, " onMTUChange: default" );
1275+ }
1276+
12051277#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
0 commit comments