1818# include " NimBLEDevice.h"
1919# include " NimBLELog.h"
2020
21- # define NIMBLE_SUB_NOTIFY 0x0001
22- # define NIMBLE_SUB_INDICATE 0x0002
23-
2421static NimBLECharacteristicCallbacks defaultCallback;
2522static 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
370293void NimBLECharacteristic::readEvent (NimBLEConnInfo& connInfo) {
371294 m_pCallbacks->onRead (this , connInfo);
372- }
295+ } // readEvent
373296
374297void 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 */
457380void NimBLECharacteristicCallbacks::onSubscribe (NimBLECharacteristic* pCharacteristic,
458- NimBLEConnInfo& connInfo,
381+ NimBLEConnInfo& connInfo,
459382 uint16_t subValue) {
460383 NIMBLE_LOGD (" NimBLECharacteristicCallbacks" , " onSubscribe: default" );
461384}
0 commit comments