Skip to content

Commit 5137fc5

Browse files
romansavrulinme-no-dev
authored andcommitted
Ble notification/indication status and timeout (#2998)
* add timed wait * Added Notification/Indication data and status callbacks * imply null-object pattern for BLE callback
1 parent 03066e4 commit 5137fc5

File tree

4 files changed

+105
-12
lines changed

4 files changed

+105
-12
lines changed

libraries/BLE/src/BLECharacteristic.cpp

+56-12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#define NULL_HANDLE (0xffff)
2424

25+
static BLECharacteristicCallbacks defaultCallback; //null-object-pattern
2526

2627
/**
2728
* @brief Construct a characteristic
@@ -40,7 +41,7 @@ BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) {
4041
m_bleUUID = uuid;
4142
m_handle = NULL_HANDLE;
4243
m_properties = (esp_gatt_char_prop_t)0;
43-
m_pCallbacks = nullptr;
44+
m_pCallbacks = &defaultCallback;
4445

4546
setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
4647
setReadProperty((properties & PROPERTY_READ) != 0);
@@ -220,9 +221,7 @@ void BLECharacteristic::handleGATTServerEvent(
220221
case ESP_GATTS_EXEC_WRITE_EVT: {
221222
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
222223
m_value.commit();
223-
if (m_pCallbacks != nullptr) {
224-
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
225-
}
224+
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
226225
} else {
227226
m_value.cancel();
228227
}
@@ -307,7 +306,7 @@ void BLECharacteristic::handleGATTServerEvent(
307306
}
308307
} // Response needed
309308

310-
if (m_pCallbacks != nullptr && param->write.is_prep != true) {
309+
if (param->write.is_prep != true) {
311310
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
312311
}
313312
} // Match on handles.
@@ -378,9 +377,9 @@ void BLECharacteristic::handleGATTServerEvent(
378377
}
379378
} else { // read.is_long == false
380379

381-
if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback
382-
m_pCallbacks->onRead(this); // Invoke the read callback.
383-
}
380+
// If is.long is false then this is the first (or only) request to read data, so invoke the callback
381+
// Invoke the read callback.
382+
m_pCallbacks->onRead(this);
384383

385384
std::string value = m_value.getValue();
386385

@@ -480,10 +479,13 @@ void BLECharacteristic::notify(bool is_notification) {
480479
assert(getService() != nullptr);
481480
assert(getService()->getServer() != nullptr);
482481

482+
m_pCallbacks->onNotify(this); // Invoke the notify callback.
483+
483484
GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length());
484485

485486
if (getService()->getServer()->getConnectedCount() == 0) {
486487
log_v("<< notify: No connected clients.");
488+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NO_CLIENT, 0);
487489
return;
488490
}
489491

@@ -494,12 +496,14 @@ void BLECharacteristic::notify(bool is_notification) {
494496
if(is_notification) {
495497
if (p2902 != nullptr && !p2902->getNotifications()) {
496498
log_v("<< notifications disabled; ignoring");
499+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NOTIFY_DISABLED, 0); // Invoke the notify callback.
497500
return;
498501
}
499502
}
500503
else{
501504
if (p2902 != nullptr && !p2902->getIndications()) {
502505
log_v("<< indications disabled; ignoring");
506+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED, 0); // Invoke the notify callback.
503507
return;
504508
}
505509
}
@@ -510,7 +514,7 @@ void BLECharacteristic::notify(bool is_notification) {
510514
}
511515

512516
size_t length = m_value.getValue().length();
513-
if(!is_notification)
517+
if(!is_notification) // is indication
514518
m_semaphoreConfEvt.take("indicate");
515519
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
516520
getService()->getServer()->getGattsIf(),
@@ -519,10 +523,23 @@ void BLECharacteristic::notify(bool is_notification) {
519523
if (errRc != ESP_OK) {
520524
log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
521525
m_semaphoreConfEvt.give();
526+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_GATT, errRc); // Invoke the notify callback.
522527
return;
523528
}
524-
if(!is_notification)
525-
m_semaphoreConfEvt.wait("indicate");
529+
if(!is_notification){ // is indication
530+
if(!m_semaphoreConfEvt.timedWait("indicate", indicationTimeout)){
531+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, 0); // Invoke the notify callback.
532+
} else {
533+
auto code = (esp_gatt_status_t) m_semaphoreConfEvt.value();
534+
if(code == ESP_GATT_OK) {
535+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_INDICATE, code); // Invoke the notify callback.
536+
} else {
537+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, code);
538+
}
539+
}
540+
} else {
541+
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0); // Invoke the notify callback.
542+
}
526543
}
527544
log_v("<< notify");
528545
} // Notify
@@ -551,7 +568,11 @@ void BLECharacteristic::setBroadcastProperty(bool value) {
551568
*/
552569
void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
553570
log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
554-
m_pCallbacks = pCallbacks;
571+
if (pCallbacks != nullptr){
572+
m_pCallbacks = pCallbacks;
573+
} else {
574+
m_pCallbacks = &defaultCallback;
575+
}
555576
log_v("<< setCallbacks");
556577
} // setCallbacks
557578

@@ -754,4 +775,27 @@ void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) {
754775
log_d("BLECharacteristicCallbacks", "<< onWrite");
755776
} // onWrite
756777

778+
779+
/**
780+
* @brief Callback function to support a Notify request.
781+
* @param [in] pCharacteristic The characteristic that is the source of the event.
782+
*/
783+
void BLECharacteristicCallbacks::onNotify(BLECharacteristic* pCharacteristic) {
784+
log_d("BLECharacteristicCallbacks", ">> onNotify: default");
785+
log_d("BLECharacteristicCallbacks", "<< onNotify");
786+
} // onNotify
787+
788+
789+
/**
790+
* @brief Callback function to support a Notify/Indicate Status report.
791+
* @param [in] pCharacteristic The characteristic that is the source of the event.
792+
* @param [in] s Status of the notification/indication
793+
* @param [in] code Additional code of underlying errors
794+
*/
795+
void BLECharacteristicCallbacks::onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) {
796+
log_d("BLECharacteristicCallbacks", ">> onStatus: default");
797+
log_d("BLECharacteristicCallbacks", "<< onStatus");
798+
} // onStatus
799+
800+
757801
#endif /* CONFIG_BT_ENABLED */

libraries/BLE/src/BLECharacteristic.h

+15
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ class BLECharacteristic {
9090
static const uint32_t PROPERTY_INDICATE = 1<<4;
9191
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
9292

93+
static const uint32_t indicationTimeout = 1000;
94+
9395
private:
9496

9597
friend class BLEServer;
@@ -130,9 +132,22 @@ class BLECharacteristic {
130132
*/
131133
class BLECharacteristicCallbacks {
132134
public:
135+
typedef enum {
136+
SUCCESS_INDICATE,
137+
SUCCESS_NOTIFY,
138+
ERROR_INDICATE_DISABLED,
139+
ERROR_NOTIFY_DISABLED,
140+
ERROR_GATT,
141+
ERROR_NO_CLIENT,
142+
ERROR_INDICATE_TIMEOUT,
143+
ERROR_INDICATE_FAILURE
144+
}Status;
145+
133146
virtual ~BLECharacteristicCallbacks();
134147
virtual void onRead(BLECharacteristic* pCharacteristic);
135148
virtual void onWrite(BLECharacteristic* pCharacteristic);
149+
virtual void onNotify(BLECharacteristic* pCharacteristic);
150+
virtual void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code);
136151
};
137152
#endif /* CONFIG_BT_ENABLED */
138153
#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */

libraries/BLE/src/FreeRTOS.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,38 @@ uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
7878
return m_value;
7979
} // wait
8080

81+
/**
82+
* @brief Wait for a semaphore to be released in a given period of time by trying to take it and
83+
* then releasing it again. The value associated with the semaphore can be taken by value() call after return
84+
* @param [in] owner A debug tag.
85+
* @param [in] timeoutMs timeout to wait in ms.
86+
* @return True if we took the semaphore within timeframe.
87+
*/
88+
bool FreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) {
89+
log_v(">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
90+
91+
if (m_usePthreads && timeoutMs != portMAX_DELAY) {
92+
assert(false); // We apparently don't have a timed wait for pthreads.
93+
}
94+
95+
auto ret = pdTRUE;
96+
97+
if (m_usePthreads) {
98+
pthread_mutex_lock(&m_pthread_mutex);
99+
} else {
100+
ret = xSemaphoreTake(m_semaphore, timeoutMs);
101+
}
102+
103+
if (m_usePthreads) {
104+
pthread_mutex_unlock(&m_pthread_mutex);
105+
} else {
106+
xSemaphoreGive(m_semaphore);
107+
}
108+
109+
log_v("<< wait: Semaphore %s released: %d", toString().c_str(), ret);
110+
return ret;
111+
} // wait
112+
81113

82114
FreeRTOS::Semaphore::Semaphore(std::string name) {
83115
m_usePthreads = false; // Are we using pThreads or FreeRTOS?

libraries/BLE/src/FreeRTOS.h

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class FreeRTOS {
4040
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
4141
std::string toString();
4242
uint32_t wait(std::string owner = "<Unknown>");
43+
bool timedWait(std::string owner = "<Unknown>", uint32_t timeoutMs = portMAX_DELAY);
44+
uint32_t value(){ return m_value; };
4345

4446
private:
4547
SemaphoreHandle_t m_semaphore;

0 commit comments

Comments
 (0)