@@ -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 );
@@ -222,10 +250,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
222250 break ;
223251
224252 case BLE_HS_EALREADY:
225- // Already attempting to connect to this device, cancel the previous
226- // attempt and report failure here so we don't get 2 connections.
227- NIMBLE_LOGE (LOG_TAG, " Already attempting to connect to %s - cancelling" , std::string (m_peerAddress).c_str ());
228- ble_gap_conn_cancel ();
253+ NIMBLE_LOGE (LOG_TAG, " Already attempting to connect" );
229254 break ;
230255
231256 default :
@@ -239,16 +264,21 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
239264
240265 } while (rc == BLE_HS_EBUSY);
241266
242- NimBLEDevice::setConnectionInProgress (false );
243267 m_lastErr = rc;
244268 if (rc != 0 ) {
269+ m_lastErr = rc;
245270 m_pTaskData = nullptr ;
271+ NimBLEDevice::setConnectionInProgress (false );
246272 return false ;
247273 }
248274
275+ if (m_asyncConnect) {
276+ return true ;
277+ }
278+
249279# ifdef ulTaskNotifyValueClear
250280 // Clear the task notification value to ensure we block
251- ulTaskNotifyValueClear (cur_task , ULONG_MAX);
281+ ulTaskNotifyValueClear (curTask , ULONG_MAX);
252282# endif
253283 // Wait for the connect timeout time +1 second for the connection to complete
254284 if (ulTaskNotifyTake (pdTRUE, pdMS_TO_TICKS (m_connectTimeout + 1000 )) == pdFALSE) {
@@ -278,10 +308,6 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes)
278308 NIMBLE_LOGI (LOG_TAG, " Connection established" );
279309 }
280310
281- if (deleteAttributes) {
282- deleteServices ();
283- }
284-
285311 m_connEstablished = true ;
286312 m_pClientCallbacks->onConnect (this );
287313
@@ -854,6 +880,41 @@ uint16_t NimBLEClient::getMTU() const {
854880 return ble_att_mtu (m_connHandle);
855881} // getMTU
856882
883+ /* *
884+ * @brief Callback for the MTU exchange API function.
885+ * @details When the MTU exchange is complete the API will call this and report the new MTU.
886+ */
887+ int NimBLEClient::exchangeMTUCb (uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void * arg) {
888+ NIMBLE_LOGD (LOG_TAG, " exchangeMTUCb: status=%d, mtu=%d" , error->status , mtu);
889+
890+ NimBLEClient* pClient = (NimBLEClient*)arg;
891+ if (pClient->getConnHandle () != conn_handle) {
892+ return 0 ;
893+ }
894+
895+ if (error->status != 0 ) {
896+ NIMBLE_LOGE (LOG_TAG, " exchangeMTUCb() rc=%d %s" , error->status , NimBLEUtils::returnCodeToString (error->status ));
897+ pClient->m_lastErr = error->status ;
898+ }
899+
900+ return 0 ;
901+ }
902+
903+ /* *
904+ * @brief Begin the MTU exchange process with the server.
905+ * @returns true if the request was sent successfully.
906+ */
907+ bool NimBLEClient::exchangeMTU () {
908+ int rc = ble_gattc_exchange_mtu (m_connHandle, NimBLEClient::exchangeMTUCb, this );
909+ if (rc != 0 ) {
910+ NIMBLE_LOGE (LOG_TAG, " MTU exchange error; rc=%d %s" , rc, NimBLEUtils::returnCodeToString (rc));
911+ m_lastErr = rc;
912+ return false ;
913+ }
914+
915+ return true ;
916+ } // exchangeMTU
917+
857918/* *
858919 * @brief Handle a received GAP event.
859920 * @param [in] event The event structure sent by the NimBLE stack.
@@ -908,29 +969,39 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
908969
909970 case BLE_GAP_EVENT_CONNECT: {
910971 // If we aren't waiting for this connection response we should drop the connection immediately.
911- if (pClient->isConnected () || pClient->m_pTaskData == nullptr ) {
972+ if (pClient->isConnected () || (! pClient->m_asyncConnect && pClient-> m_pTaskData == nullptr ) ) {
912973 ble_gap_terminate (event->connect .conn_handle , BLE_ERR_REM_USER_CONN_TERM);
913974 return 0 ;
914975 }
915976
977+ NimBLEDevice::setConnectionInProgress (false );
916978 rc = event->connect .status ;
917979 if (rc == 0 ) {
918980 NIMBLE_LOGI (LOG_TAG, " Connected event" );
919981
920982 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 ;
983+ if (pClient-> m_exchangeMTU ) {
984+ if (! pClient->exchangeMTU () && !pClient-> m_asyncConnect ) {
985+ rc = pClient-> m_lastErr ;
986+ break ;
987+ }
926988 }
927989
928990 // In the case of a multi-connecting device we ignore this device when
929991 // scanning since we are already connected to it
930992 NimBLEDevice::addIgnored (pClient->m_peerAddress );
931993 } else {
932994 pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
933- break ;
995+ if (!pClient->m_asyncConnect ) {
996+ break ;
997+ }
998+ }
999+
1000+ if (pClient->m_asyncConnect ) {
1001+ pClient->m_connEstablished = rc == 0 ;
1002+ pClient->m_pClientCallbacks ->onConnect (pClient);
1003+ } else if (!pClient->m_exchangeMTU ) {
1004+ break ; // not wating for MTU exchange so release the task now.
9341005 }
9351006
9361007 return 0 ;
@@ -1072,7 +1143,9 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10721143 if (pClient->m_connHandle != event->mtu .conn_handle ) {
10731144 return 0 ;
10741145 }
1075- NIMBLE_LOGI (LOG_TAG, " mtu update event; conn_handle=%d mtu=%d" , event->mtu .conn_handle , event->mtu .value );
1146+
1147+ NIMBLE_LOGI (LOG_TAG, " mtu update: mtu=%d" , event->mtu .value );
1148+ pClient->m_pClientCallbacks ->onMTUChange (pClient, event->mtu .value );
10761149 rc = 0 ;
10771150 break ;
10781151 } // BLE_GAP_EVENT_MTU
@@ -1204,4 +1277,8 @@ void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t
12041277 NimBLEDevice::injectConfirmPasskey (connInfo, true );
12051278}
12061279
1280+ void NimBLEClientCallbacks::onMTUChange (NimBLEClient* pClient, uint16_t mtu) {
1281+ NIMBLE_LOGD (CB_TAG, " onMTUChange: default" );
1282+ }
1283+
12071284#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
0 commit comments