@@ -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,44 +125,62 @@ 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
157172 if (!NimBLEDevice::m_synced) {
158173 NIMBLE_LOGE (LOG_TAG, " Host reset, wait for sync." );
159174 return false ;
160175 }
161176
162- if (isConnected () || m_connEstablished || m_pTaskData != nullptr ) {
163- NIMBLE_LOGE (LOG_TAG, " Client busy, connected to %s, handle=%d" , std::string (m_peerAddress).c_str (), getConnHandle ());
177+ if (isConnected () || m_connEstablished) {
178+ NIMBLE_LOGE (LOG_TAG, " Client already connected" );
179+ return false ;
180+ }
181+
182+ if (NimBLEDevice::isConnectionInProgress ()) {
183+ NIMBLE_LOGE (LOG_TAG, " Connection already in progress" );
164184 return false ;
165185 }
166186
@@ -171,16 +191,24 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
171191 }
172192
173193 if (address.isNull ()) {
174- NIMBLE_LOGE (LOG_TAG, " Invalid peer address;(NULL)" );
194+ NIMBLE_LOGE (LOG_TAG, " Invalid peer address; (NULL)" );
175195 return false ;
176196 } else {
177197 m_peerAddress = address;
178198 }
179199
180- TaskHandle_t cur_task = xTaskGetCurrentTaskHandle ();
181- BleTaskData taskData = {this , cur_task, 0 , nullptr };
182- m_pTaskData = &taskData;
200+ if (deleteAttributes) {
201+ deleteServices ();
202+ }
203+
183204 int rc = 0 ;
205+ m_asyncConnect = asyncConnect;
206+ m_exchangeMTU = exchangeMTU;
207+ TaskHandle_t curTask = xTaskGetCurrentTaskHandle ();
208+ BleTaskData taskData = {this , curTask, 0 , nullptr };
209+ if (!asyncConnect) {
210+ m_pTaskData = &taskData;
211+ }
184212
185213 // Set the connection in progress flag to prevent a scan from starting while connecting.
186214 NimBLEDevice::setConnectionInProgress (true );
@@ -239,16 +267,21 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
239267
240268 } while (rc == BLE_HS_EBUSY);
241269
242- NimBLEDevice::setConnectionInProgress (false );
243270 m_lastErr = rc;
244271 if (rc != 0 ) {
272+ m_lastErr = rc;
245273 m_pTaskData = nullptr ;
274+ NimBLEDevice::setConnectionInProgress (false );
246275 return false ;
247276 }
248277
278+ if (m_asyncConnect) {
279+ return true ;
280+ }
281+
249282# ifdef ulTaskNotifyValueClear
250283 // Clear the task notification value to ensure we block
251- ulTaskNotifyValueClear (cur_task , ULONG_MAX);
284+ ulTaskNotifyValueClear (curTask , ULONG_MAX);
252285# endif
253286 // Wait for the connect timeout time +1 second for the connection to complete
254287 if (ulTaskNotifyTake (pdTRUE, pdMS_TO_TICKS (m_connectTimeout + 1000 )) == pdFALSE) {
@@ -278,10 +311,6 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
278311 NIMBLE_LOGI (LOG_TAG, " Connection established" );
279312 }
280313
281- if (deleteAttributes) {
282- deleteServices ();
283- }
284-
285314 m_connEstablished = true ;
286315 m_pClientCallbacks->onConnect (this );
287316
@@ -854,6 +883,41 @@ uint16_t NimBLEClient::getMTU() const {
854883 return ble_att_mtu (m_connHandle);
855884} // getMTU
856885
886+ /* *
887+ * @brief Callback for the MTU exchange API function.
888+ * @details When the MTU exchange is complete the API will call this and report the new MTU.
889+ */
890+ int NimBLEClient::exchangeMTUCb (uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void * arg) {
891+ NIMBLE_LOGD (LOG_TAG, " exchangeMTUCb: status=%d, mtu=%d" , error->status , mtu);
892+
893+ NimBLEClient* pClient = (NimBLEClient*)arg;
894+ if (pClient->getConnHandle () != conn_handle) {
895+ return 0 ;
896+ }
897+
898+ if (error->status != 0 ) {
899+ NIMBLE_LOGE (LOG_TAG, " exchangeMTUCb() rc=%d %s" , error->status , NimBLEUtils::returnCodeToString (error->status ));
900+ pClient->m_lastErr = error->status ;
901+ }
902+
903+ return 0 ;
904+ }
905+
906+ /* *
907+ * @brief Begin the MTU exchange process with the server.
908+ * @returns true if the request was sent successfully.
909+ */
910+ bool NimBLEClient::exchangeMTU () {
911+ int rc = ble_gattc_exchange_mtu (m_connHandle, NimBLEClient::exchangeMTUCb, this );
912+ if (rc != 0 ) {
913+ NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s" , rc, NimBLEUtils::returnCodeToString (rc));
914+ m_lastErr = rc;
915+ return false ;
916+ }
917+
918+ return true ;
919+ } // exchangeMTU
920+
857921/* *
858922 * @brief Handle a received GAP event.
859923 * @param [in] event The event structure sent by the NimBLE stack.
@@ -908,29 +972,39 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
908972
909973 case BLE_GAP_EVENT_CONNECT: {
910974 // If we aren't waiting for this connection response we should drop the connection immediately.
911- if (pClient->isConnected () || pClient->m_pTaskData == nullptr ) {
975+ if (pClient->isConnected () || (! pClient->m_asyncConnect && pClient-> m_pTaskData == nullptr ) ) {
912976 ble_gap_terminate (event->connect .conn_handle , BLE_ERR_REM_USER_CONN_TERM);
913977 return 0 ;
914978 }
915979
980+ NimBLEDevice::setConnectionInProgress (false );
916981 rc = event->connect .status ;
917982 if (rc == 0 ) {
918983 NIMBLE_LOGI (LOG_TAG, " Connected event" );
919984
920985 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 ;
986+ if (pClient-> m_exchangeMTU ) {
987+ if (! pClient->exchangeMTU () && !pClient-> m_asyncConnect ) {
988+ rc = pClient-> m_lastErr ;
989+ break ;
990+ }
926991 }
927992
928993 // In the case of a multi-connecting device we ignore this device when
929994 // scanning since we are already connected to it
930995 NimBLEDevice::addIgnored (pClient->m_peerAddress );
931996 } else {
932997 pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
933- break ;
998+ if (!pClient->m_asyncConnect ) {
999+ break ;
1000+ }
1001+ }
1002+
1003+ if (pClient->m_asyncConnect ) {
1004+ pClient->m_connEstablished = rc == 0 ;
1005+ pClient->m_pClientCallbacks ->onConnect (pClient);
1006+ } else if (!pClient->m_exchangeMTU ) {
1007+ break ; // not wating for MTU exchange so release the task now.
9341008 }
9351009
9361010 return 0 ;
@@ -1072,7 +1146,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10721146 if (pClient->m_connHandle != event->mtu .conn_handle ) {
10731147 return 0 ;
10741148 }
1075- NIMBLE_LOGI (LOG_TAG, " mtu update event; conn_handle=%d mtu=%d" , event->mtu .conn_handle , event->mtu .value );
1149+
1150+ NIMBLE_LOGI (LOG_TAG, " mtu update: mtu=%d" , event->mtu .value );
1151+ pClient->m_pClientCallbacks ->onMTUChange (pClient, event->mtu .value );
10761152 rc = 0 ;
10771153 break ;
10781154 } // BLE_GAP_EVENT_MTU
@@ -1204,4 +1280,8 @@ void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t
12041280 NimBLEDevice::injectConfirmPasskey (connInfo, true );
12051281}
12061282
1283+ void NimBLEClientCallbacks::onMTUChange (NimBLEClient* pClient, uint16_t mtu) {
1284+ NIMBLE_LOGD (CB_TAG, " onMTUChange: default" );
1285+ }
1286+
12071287#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
0 commit comments