@@ -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 // Set the connection in progress flag to prevent a scan from starting while connecting.
186209 NimBLEDevice::setConnectionInProgress (true );
@@ -242,10 +265,15 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
242265 NimBLEDevice::setConnectionInProgress (false );
243266 m_lastErr = rc;
244267 if (rc != 0 ) {
268+ m_lastErr = rc;
245269 m_pTaskData = nullptr ;
246270 return false ;
247271 }
248272
273+ if (m_asyncConnect) {
274+ return true ;
275+ }
276+
249277# ifdef ulTaskNotifyValueClear
250278 // Clear the task notification value to ensure we block
251279 ulTaskNotifyValueClear (cur_task, ULONG_MAX);
@@ -278,10 +306,6 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
278306 NIMBLE_LOGI (LOG_TAG, " Connection established" );
279307 }
280308
281- if (deleteAttributes) {
282- deleteServices ();
283- }
284-
285309 m_connEstablished = true ;
286310 m_pClientCallbacks->onConnect (this );
287311
@@ -854,6 +878,41 @@ uint16_t NimBLEClient::getMTU() const {
854878 return ble_att_mtu (m_connHandle);
855879} // getMTU
856880
881+ /* *
882+ * @brief Callback for the MTU exchange API function.
883+ * @details When the MTU exchange is complete the API will call this and report the new MTU.
884+ */
885+ int NimBLEClient::exchangeMTUCb (uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void * arg) {
886+ NIMBLE_LOGD (LOG_TAG, " exchangeMTUCb: status=%d, mtu=%d" , error->status , mtu);
887+
888+ NimBLEClient* pClient = (NimBLEClient*)arg;
889+ if (pClient->getConnHandle () != conn_handle) {
890+ return 0 ;
891+ }
892+
893+ if (error->status != 0 ) {
894+ NIMBLE_LOGE (LOG_TAG, " exchangeMTUCb() rc=%d %s" , error->status , NimBLEUtils::returnCodeToString (error->status ));
895+ pClient->m_lastErr = error->status ;
896+ }
897+
898+ return 0 ;
899+ }
900+
901+ /* *
902+ * @brief Begin the MTU exchange process with the server.
903+ * @returns true if the request was sent successfully.
904+ */
905+ bool NimBLEClient::exchangeMTU () {
906+ int rc = ble_gattc_exchange_mtu (m_connHandle, NimBLEClient::exchangeMTUCb, this );
907+ if (rc != 0 ) {
908+ NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s" , rc, NimBLEUtils::returnCodeToString (rc));
909+ m_lastErr = rc;
910+ return false ;
911+ }
912+
913+ return true ;
914+ } // exchangeMTU
915+
857916/* *
858917 * @brief Handle a received GAP event.
859918 * @param [in] event The event structure sent by the NimBLE stack.
@@ -908,7 +967,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
908967
909968 case BLE_GAP_EVENT_CONNECT: {
910969 // If we aren't waiting for this connection response we should drop the connection immediately.
911- if (pClient->isConnected () || pClient->m_pTaskData == nullptr ) {
970+ if (pClient->isConnected () || (! pClient->m_asyncConnect && pClient-> m_pTaskData == nullptr ) ) {
912971 ble_gap_terminate (event->connect .conn_handle , BLE_ERR_REM_USER_CONN_TERM);
913972 return 0 ;
914973 }
@@ -918,19 +977,28 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
918977 NIMBLE_LOGI (LOG_TAG, " Connected event" );
919978
920979 pClient->m_connHandle = event->connect .conn_handle ;
921-
922- rc = ble_gattc_exchange_mtu ( pClient->m_connHandle , NULL , NULL );
923- if ( rc != 0 ) {
924- NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s " , rc, NimBLEUtils::returnCodeToString (rc)) ;
925- break ;
980+ if (pClient-> m_exchangeMTU ) {
981+ if (! pClient->exchangeMTU () && !pClient-> m_asyncConnect ) {
982+ rc = pClient-> m_lastErr ;
983+ break ;
984+ }
926985 }
927986
928987 // In the case of a multi-connecting device we ignore this device when
929988 // scanning since we are already connected to it
930989 NimBLEDevice::addIgnored (pClient->m_peerAddress );
931990 } else {
932991 pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
933- break ;
992+ if (!pClient->m_asyncConnect ) {
993+ break ;
994+ }
995+ }
996+
997+ if (pClient->m_asyncConnect ) {
998+ pClient->m_connEstablished = rc == 0 ;
999+ pClient->m_pClientCallbacks ->onConnect (pClient);
1000+ } else if (!pClient->m_exchangeMTU ) {
1001+ break ; // not wating for MTU exchange so release the task now.
9341002 }
9351003
9361004 return 0 ;
@@ -1072,7 +1140,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10721140 if (pClient->m_connHandle != event->mtu .conn_handle ) {
10731141 return 0 ;
10741142 }
1075- NIMBLE_LOGI (LOG_TAG, " mtu update event; conn_handle=%d mtu=%d" , event->mtu .conn_handle , event->mtu .value );
1143+
1144+ NIMBLE_LOGI (LOG_TAG, " mtu update: mtu=%d" , event->mtu .value );
1145+ pClient->m_pClientCallbacks ->onMTUChange (pClient, event->mtu .value );
10761146 rc = 0 ;
10771147 break ;
10781148 } // BLE_GAP_EVENT_MTU
@@ -1204,4 +1274,8 @@ void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t
12041274 NimBLEDevice::injectConfirmPasskey (connInfo, true );
12051275}
12061276
1277+ void NimBLEClientCallbacks::onMTUChange (NimBLEClient* pClient, uint16_t mtu) {
1278+ NIMBLE_LOGD (CB_TAG, " onMTUChange: default" );
1279+ }
1280+
12071281#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
0 commit comments