Skip to content

Commit 63f05ba

Browse files
h2zeroh2zero
authored andcommitted
Add asyncronous client connect and MTU exchange.
* Adds parameters `asyncConnect` and `exchangeMTU` to `NimBLEClient::connect`, default values work as the original connect method. * * `asyncConnect`; if true, will send the connect command and return immediately with a true value for successfully sending the command, else false. * * `exchangeMTU`; if true will send the exchange MTU command upon connection, otherwise not and the application can choose to do this later via the `exchangeMTU` method. * Adds `onMTUChange` callback to `NimBLEClientCallbacks`
1 parent 523e92f commit 63f05ba

File tree

2 files changed

+118
-31
lines changed

2 files changed

+118
-31
lines changed

src/NimBLEClient.cpp

Lines changed: 100 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */

src/NimBLEClient.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,12 @@ struct BleTaskData;
4444
*/
4545
class NimBLEClient {
4646
public:
47-
bool connect(NimBLEAdvertisedDevice* device, bool deleteAttributes = true);
48-
bool connect(const NimBLEAddress& address, bool deleteAttributes = true);
49-
bool connect(bool deleteAttributes = true);
47+
bool connect(NimBLEAdvertisedDevice* device,
48+
bool deleteAttributes = true,
49+
bool asyncConnect = false,
50+
bool exchangeMTU = true);
51+
bool connect(const NimBLEAddress& address, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
52+
bool connect(bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
5053
bool disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
5154
NimBLEAddress getPeerAddress() const;
5255
bool setPeerAddress(const NimBLEAddress& address);
@@ -59,6 +62,7 @@ class NimBLEClient {
5962
bool setConnection(const NimBLEConnInfo& connInfo);
6063
bool setConnection(uint16_t connHandle);
6164
uint16_t getMTU() const;
65+
bool exchangeMTU();
6266
bool secureConnection() const;
6367
void setConnectTimeout(uint32_t timeout);
6468
bool setDataLen(uint16_t txOctets);
@@ -98,6 +102,7 @@ class NimBLEClient {
98102

99103
bool retrieveServices(const NimBLEUUID* uuidFilter = nullptr);
100104
static int handleGapEvent(struct ble_gap_event* event, void* arg);
105+
static int exchangeMTUCb(uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void* arg);
101106
static int serviceDiscoveredCB(uint16_t connHandle,
102107
const struct ble_gatt_error* error,
103108
const struct ble_gatt_svc* service,
@@ -113,6 +118,8 @@ class NimBLEClient {
113118
uint8_t m_terminateFailCount;
114119
bool m_deleteCallbacks;
115120
bool m_connEstablished;
121+
bool m_asyncConnect;
122+
bool m_exchangeMTU;
116123
# if CONFIG_BT_NIMBLE_EXT_ADV
117124
uint8_t m_phyMask;
118125
# endif
@@ -174,6 +181,14 @@ class NimBLEClientCallbacks {
174181
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
175182
*/
176183
virtual void onIdentity(NimBLEConnInfo& connInfo);
184+
185+
/**
186+
* @brief Called when the connection MTU changes.
187+
* @param [in] pClient A pointer to the client that the MTU change is associated with.
188+
* @param [in] MTU The new MTU value.
189+
* about the peer connection parameters.
190+
*/
191+
virtual void onMTUChange(NimBLEClient* pClient, uint16_t MTU);
177192
};
178193

179194
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */

0 commit comments

Comments
 (0)