Skip to content

Commit 554c620

Browse files
committed
Remove characteristic subscription tracking.
Removes tracking of client characteristic subscription status from `NimBLEServer` and `NimBLECharacteristic` and instead uses the functions and tracking in the host stack. * `NimBLECharacteristic::notify` and `NimBLECharacteristic::indicate` now return a `bool`, true = success.
1 parent fd7f770 commit 554c620

File tree

5 files changed

+133
-237
lines changed

5 files changed

+133
-237
lines changed

src/NimBLECharacteristic.cpp

Lines changed: 65 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,28 @@
1818
# include "NimBLEDevice.h"
1919
# include "NimBLELog.h"
2020

21-
# define NIMBLE_SUB_NOTIFY 0x0001
22-
# define NIMBLE_SUB_INDICATE 0x0002
23-
2421
static NimBLECharacteristicCallbacks defaultCallback;
2522
static const char* LOG_TAG = "NimBLECharacteristic";
2623

2724
/**
2825
* @brief Construct a characteristic
2926
* @param [in] uuid - UUID (const char*) for the characteristic.
3027
* @param [in] properties - Properties for the characteristic.
31-
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
28+
* @param [in] maxLen - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
3229
* @param [in] pService - pointer to the service instance this characteristic belongs to.
3330
*/
34-
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, uint16_t max_len, NimBLEService* pService)
35-
: NimBLECharacteristic(NimBLEUUID(uuid), properties, max_len, pService) {}
31+
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, uint16_t maxLen, NimBLEService* pService)
32+
: NimBLECharacteristic(NimBLEUUID(uuid), properties, maxLen, pService) {}
3633

3734
/**
3835
* @brief Construct a characteristic
3936
* @param [in] uuid - UUID for the characteristic.
4037
* @param [in] properties - Properties for the characteristic.
41-
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
38+
* @param [in] maxLen - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
4239
* @param [in] pService - pointer to the service instance this characteristic belongs to.
4340
*/
44-
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID& uuid, uint16_t properties, uint16_t max_len, NimBLEService* pService)
45-
: NimBLELocalValueAttribute{uuid, 0, max_len}, m_pCallbacks{&defaultCallback}, m_pService{pService} {
41+
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID& uuid, uint16_t properties, uint16_t maxLen, NimBLEService* pService)
42+
: NimBLELocalValueAttribute{uuid, 0, maxLen}, m_pCallbacks{&defaultCallback}, m_pService{pService} {
4643
setProperties(properties);
4744
} // NimBLECharacteristic
4845

@@ -59,26 +56,26 @@ NimBLECharacteristic::~NimBLECharacteristic() {
5956
* @brief Create a new BLE Descriptor associated with this characteristic.
6057
* @param [in] uuid - The UUID of the descriptor.
6158
* @param [in] properties - The properties of the descriptor.
62-
* @param [in] max_len - The max length in bytes of the descriptor value.
59+
* @param [in] maxLen - The max length in bytes of the descriptor value.
6360
* @return The new BLE descriptor.
6461
*/
65-
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t max_len) {
66-
return createDescriptor(NimBLEUUID(uuid), properties, max_len);
62+
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t maxLen) {
63+
return createDescriptor(NimBLEUUID(uuid), properties, maxLen);
6764
}
6865

6966
/**
7067
* @brief Create a new BLE Descriptor associated with this characteristic.
7168
* @param [in] uuid - The UUID of the descriptor.
7269
* @param [in] properties - The properties of the descriptor.
73-
* @param [in] max_len - The max length in bytes of the descriptor value.
70+
* @param [in] maxLen - The max length in bytes of the descriptor value.
7471
* @return The new BLE descriptor.
7572
*/
76-
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID& uuid, uint32_t properties, uint16_t max_len) {
73+
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID& uuid, uint32_t properties, uint16_t maxLen) {
7774
NimBLEDescriptor* pDescriptor = nullptr;
7875
if (uuid == NimBLEUUID(uint16_t(0x2904))) {
7976
pDescriptor = new NimBLE2904(this);
8077
} else {
81-
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
78+
pDescriptor = new NimBLEDescriptor(uuid, properties, maxLen, this);
8279
}
8380

8481
addDescriptor(pDescriptor);
@@ -199,182 +196,108 @@ void NimBLECharacteristic::setService(NimBLEService* pService) {
199196
m_pService = pService;
200197
} // setService
201198

202-
/**
203-
* @brief Get the number of clients subscribed to the characteristic.
204-
* @returns Number of clients subscribed to notifications / indications.
205-
*/
206-
size_t NimBLECharacteristic::getSubscribedCount() const {
207-
return m_subscribedVec.size();
208-
}
209-
210-
/**
211-
* @brief Set the subscribe status for this characteristic.\n
212-
* This will maintain a vector of subscribed clients and their indicate/notify status.
213-
*/
214-
void NimBLECharacteristic::setSubscribe(const ble_gap_event* event, NimBLEConnInfo& connInfo) {
215-
uint16_t subVal = 0;
216-
if (event->subscribe.cur_notify > 0 && (m_properties & NIMBLE_PROPERTY::NOTIFY)) {
217-
subVal |= NIMBLE_SUB_NOTIFY;
218-
}
219-
if (event->subscribe.cur_indicate && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
220-
subVal |= NIMBLE_SUB_INDICATE;
221-
}
222-
223-
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", connInfo.getConnHandle(), subVal);
224-
225-
if (!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
226-
NimBLEDevice::getServer()->clearIndicateWait(connInfo.getConnHandle());
227-
}
228-
229-
auto it = m_subscribedVec.begin();
230-
for (; it != m_subscribedVec.end(); ++it) {
231-
if ((*it).first == connInfo.getConnHandle()) {
232-
break;
233-
}
234-
}
235-
236-
if (subVal > 0) {
237-
if (it == m_subscribedVec.end()) {
238-
m_subscribedVec.push_back({connInfo.getConnHandle(), subVal});
239-
} else {
240-
(*it).second = subVal;
241-
}
242-
} else if (it != m_subscribedVec.end()) {
243-
m_subscribedVec.erase(it);
244-
}
245-
246-
m_pCallbacks->onSubscribe(this, connInfo, subVal);
247-
}
248-
249199
/**
250200
* @brief Send an indication.
251-
* @param[in] conn_handle Connection handle to send an individual indication, or BLE_HS_CONN_HANDLE_NONE to send
201+
* @param[in] connHandle Connection handle to send an individual indication, or BLE_HS_CONN_HANDLE_NONE to send
252202
* the indication to all subscribed clients.
203+
* @return True if the indication was sent successfully, false otherwise.
253204
*/
254-
void NimBLECharacteristic::indicate(uint16_t conn_handle) const {
255-
sendValue(m_value.data(), m_value.size(), false, conn_handle);
205+
bool NimBLECharacteristic::indicate(uint16_t connHandle) const {
206+
return sendValue(nullptr, 0, false, connHandle);
256207
} // indicate
257208

258209
/**
259210
* @brief Send an indication.
260211
* @param[in] value A pointer to the data to send.
261212
* @param[in] length The length of the data to send.
262-
* @param[in] conn_handle Connection handle to send an individual indication, or BLE_HS_CONN_HANDLE_NONE to send
213+
* @param[in] connHandle Connection handle to send an individual indication, or BLE_HS_CONN_HANDLE_NONE to send
263214
* the indication to all subscribed clients.
215+
* @return True if the indication was sent successfully, false otherwise.
264216
*/
265-
void NimBLECharacteristic::indicate(const uint8_t* value, size_t length, uint16_t conn_handle) const {
266-
sendValue(value, length, false, conn_handle);
217+
bool NimBLECharacteristic::indicate(const uint8_t* value, size_t length, uint16_t connHandle) const {
218+
return sendValue(value, length, false, connHandle);
267219
} // indicate
268220

269221
/**
270222
* @brief Send a notification.
271-
* @param[in] conn_handle Connection handle to send an individual notification, or BLE_HS_CONN_HANDLE_NONE to send
223+
* @param[in] connHandle Connection handle to send an individual notification, or BLE_HS_CONN_HANDLE_NONE to send
272224
* the notification to all subscribed clients.
225+
* @return True if the notification was sent successfully, false otherwise.
273226
*/
274-
void NimBLECharacteristic::notify(uint16_t conn_handle) const {
275-
sendValue(m_value.data(), m_value.size(), true, conn_handle);
227+
bool NimBLECharacteristic::notify(uint16_t connHandle) const {
228+
return sendValue(nullptr, 0, true, connHandle);
276229
} // notify
277230

278231
/**
279232
* @brief Send a notification.
280233
* @param[in] value A pointer to the data to send.
281234
* @param[in] length The length of the data to send.
282-
* @param[in] conn_handle Connection handle to send an individual notification, or BLE_HS_CONN_HANDLE_NONE to send
235+
* @param[in] connHandle Connection handle to send an individual notification, or BLE_HS_CONN_HANDLE_NONE to send
283236
* the notification to all subscribed clients.
237+
* @return True if the notification was sent successfully, false otherwise.
284238
*/
285-
void NimBLECharacteristic::notify(const uint8_t* value, size_t length, uint16_t conn_handle) const {
286-
sendValue(value, length, true, conn_handle);
239+
bool NimBLECharacteristic::notify(const uint8_t* value, size_t length, uint16_t connHandle) const {
240+
return sendValue(value, length, true, connHandle);
287241
} // indicate
288242

289243
/**
290244
* @brief Sends a notification or indication.
291245
* @param[in] value A pointer to the data to send.
292246
* @param[in] length The length of the data to send.
293-
* @param[in] is_notification if true sends a notification, false sends an indication.
294-
* @param[in] conn_handle Connection handle to send to a specific peer, or BLE_HS_CONN_HANDLE_NONE to send
295-
* to all subscribed clients.
247+
* @param[in] isNotification if true sends a notification, false sends an indication.
248+
* @param[in] connHandle Connection handle to send to a specific peer.
249+
* @return True if the value was sent successfully, false otherwise.
296250
*/
297-
void NimBLECharacteristic::sendValue(const uint8_t* value, size_t length, bool is_notification, uint16_t conn_handle) const {
298-
NIMBLE_LOGD(LOG_TAG, ">> sendValue");
299-
300-
if (is_notification && !(getProperties() & NIMBLE_PROPERTY::NOTIFY)) {
301-
NIMBLE_LOGE(LOG_TAG, "<< sendValue: notification not enabled for characteristic");
302-
return;
303-
}
304-
305-
if (!is_notification && !(getProperties() & NIMBLE_PROPERTY::INDICATE)) {
306-
NIMBLE_LOGE(LOG_TAG, "<< sendValue: indication not enabled for characteristic");
307-
return;
308-
}
309-
310-
if (!m_subscribedVec.size()) {
311-
NIMBLE_LOGD(LOG_TAG, "<< sendValue: No clients subscribed.");
312-
return;
313-
}
314-
315-
for (const auto& it : m_subscribedVec) {
316-
// check if connected and subscribed
317-
if (!it.second) {
318-
continue;
319-
}
320-
321-
// sending to a specific client?
322-
if ((conn_handle <= BLE_HCI_LE_CONN_HANDLE_MAX) && (it.first != conn_handle)) {
323-
continue;
324-
}
325-
326-
if (is_notification && !(it.second & NIMBLE_SUB_NOTIFY)) {
327-
continue;
328-
}
329-
330-
if (!is_notification && !(it.second & NIMBLE_SUB_INDICATE)) {
331-
continue;
332-
}
333-
334-
// check if security requirements are satisfied
335-
if ((getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) || (getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) ||
336-
(getProperties() & BLE_GATT_CHR_F_READ_ENC)) {
337-
ble_gap_conn_desc desc;
338-
if (ble_gap_conn_find(it.first, &desc) != 0 || !desc.sec_state.encrypted) {
339-
continue;
251+
bool NimBLECharacteristic::sendValue(const uint8_t* value, size_t length, bool isNotification, uint16_t connHandle) const {
252+
int rc = 0;
253+
254+
if (value != nullptr && length > 0) { // custom notification value
255+
// Notify all connected peers unless a specific handle is provided
256+
for (const auto& ch : NimBLEDevice::getServer()->getPeerDevices()) {
257+
if (connHandle != BLE_HS_CONN_HANDLE_NONE && ch != connHandle) {
258+
continue; // only send to the specific handle, minor inefficiency but saves code.
340259
}
341-
}
342260

343-
// don't create the m_buf until we are sure to send the data or else
344-
// we could be allocating a buffer that doesn't get released.
345-
// We also must create it in each loop iteration because it is consumed with each host call.
346-
os_mbuf* om = ble_hs_mbuf_from_flat(value, length);
347-
if (!om) {
348-
NIMBLE_LOGE(LOG_TAG, "<< sendValue: failed to allocate mbuf");
349-
return;
350-
}
261+
// Must re-create the data buffer on each iteration because it is freed by the calls bellow.
262+
os_mbuf* om = ble_hs_mbuf_from_flat(value, length);
263+
if (!om) {
264+
NIMBLE_LOGE(LOG_TAG, "<< sendValue: failed to allocate mbuf");
265+
return false;
266+
}
351267

352-
if (is_notification) {
353-
ble_gattc_notify_custom(it.first, getHandle(), om);
354-
} else {
355-
if (!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
356-
NIMBLE_LOGE(LOG_TAG, "<< sendValue: waiting for previous indicate");
357-
os_mbuf_free_chain(om);
358-
return;
268+
if (isNotification) {
269+
rc = ble_gattc_notify_custom(ch, m_handle, om);
270+
} else {
271+
rc = ble_gattc_indicate_custom(ch, m_handle, om);
359272
}
360273

361-
if (ble_gattc_indicate_custom(it.first, getHandle(), om) != 0) {
362-
NimBLEDevice::getServer()->clearIndicateWait(it.first);
274+
if (rc != 0) {
275+
NIMBLE_LOGE(LOG_TAG, "<< sendValue: failed to send value, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
276+
break;
363277
}
364278
}
279+
} else if (connHandle != BLE_HS_CONN_HANDLE_NONE) { // only sending to specific peer
280+
// Null buffer will read the value from the characteristic
281+
if (isNotification) {
282+
rc = ble_gattc_notify_custom(connHandle, m_handle, NULL);
283+
} else {
284+
rc = ble_gattc_indicate_custom(connHandle, m_handle, NULL);
285+
}
286+
} else { // Notify or indicate to all connected peers the characteristic value
287+
ble_gatts_chr_updated(m_handle);
365288
}
366289

367-
NIMBLE_LOGD(LOG_TAG, "<< sendValue");
290+
return rc == 0;
368291
} // sendValue
369292

370293
void NimBLECharacteristic::readEvent(NimBLEConnInfo& connInfo) {
371294
m_pCallbacks->onRead(this, connInfo);
372-
}
295+
} // readEvent
373296

374297
void NimBLECharacteristic::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
375298
setValue(val, len);
376299
m_pCallbacks->onWrite(this, connInfo);
377-
}
300+
} // writeEvent
378301

379302
/**
380303
* @brief Set the callback handlers for this characteristic.
@@ -455,7 +378,7 @@ void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacterist
455378
* * 3 = Notifications and Indications
456379
*/
457380
void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacteristic,
458-
NimBLEConnInfo& connInfo,
381+
NimBLEConnInfo& connInfo,
459382
uint16_t subValue) {
460383
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
461384
}

0 commit comments

Comments
 (0)