Skip to content

Commit

Permalink
Ble notification/indication status and timeout (#2998)
Browse files Browse the repository at this point in the history
* add timed wait

* Added Notification/Indication data and status callbacks

* imply null-object pattern for BLE callback
  • Loading branch information
romansavrulin authored and me-no-dev committed Aug 20, 2019
1 parent 03066e4 commit 5137fc5
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 12 deletions.
68 changes: 56 additions & 12 deletions libraries/BLE/src/BLECharacteristic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#define NULL_HANDLE (0xffff)

static BLECharacteristicCallbacks defaultCallback; //null-object-pattern

/**
* @brief Construct a characteristic
Expand All @@ -40,7 +41,7 @@ BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) {
m_bleUUID = uuid;
m_handle = NULL_HANDLE;
m_properties = (esp_gatt_char_prop_t)0;
m_pCallbacks = nullptr;
m_pCallbacks = &defaultCallback;

setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
setReadProperty((properties & PROPERTY_READ) != 0);
Expand Down Expand Up @@ -220,9 +221,7 @@ void BLECharacteristic::handleGATTServerEvent(
case ESP_GATTS_EXEC_WRITE_EVT: {
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
m_value.commit();
if (m_pCallbacks != nullptr) {
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
}
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
} else {
m_value.cancel();
}
Expand Down Expand Up @@ -307,7 +306,7 @@ void BLECharacteristic::handleGATTServerEvent(
}
} // Response needed

if (m_pCallbacks != nullptr && param->write.is_prep != true) {
if (param->write.is_prep != true) {
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
}
} // Match on handles.
Expand Down Expand Up @@ -378,9 +377,9 @@ void BLECharacteristic::handleGATTServerEvent(
}
} else { // read.is_long == false

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

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

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

m_pCallbacks->onNotify(this); // Invoke the notify callback.

GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length());

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

Expand All @@ -494,12 +496,14 @@ void BLECharacteristic::notify(bool is_notification) {
if(is_notification) {
if (p2902 != nullptr && !p2902->getNotifications()) {
log_v("<< notifications disabled; ignoring");
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NOTIFY_DISABLED, 0); // Invoke the notify callback.
return;
}
}
else{
if (p2902 != nullptr && !p2902->getIndications()) {
log_v("<< indications disabled; ignoring");
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED, 0); // Invoke the notify callback.
return;
}
}
Expand All @@ -510,7 +514,7 @@ void BLECharacteristic::notify(bool is_notification) {
}

size_t length = m_value.getValue().length();
if(!is_notification)
if(!is_notification) // is indication
m_semaphoreConfEvt.take("indicate");
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
getService()->getServer()->getGattsIf(),
Expand All @@ -519,10 +523,23 @@ void BLECharacteristic::notify(bool is_notification) {
if (errRc != ESP_OK) {
log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
m_semaphoreConfEvt.give();
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_GATT, errRc); // Invoke the notify callback.
return;
}
if(!is_notification)
m_semaphoreConfEvt.wait("indicate");
if(!is_notification){ // is indication
if(!m_semaphoreConfEvt.timedWait("indicate", indicationTimeout)){
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, 0); // Invoke the notify callback.
} else {
auto code = (esp_gatt_status_t) m_semaphoreConfEvt.value();
if(code == ESP_GATT_OK) {
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_INDICATE, code); // Invoke the notify callback.
} else {
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, code);
}
}
} else {
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0); // Invoke the notify callback.
}
}
log_v("<< notify");
} // Notify
Expand Down Expand Up @@ -551,7 +568,11 @@ void BLECharacteristic::setBroadcastProperty(bool value) {
*/
void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
m_pCallbacks = pCallbacks;
if (pCallbacks != nullptr){
m_pCallbacks = pCallbacks;
} else {
m_pCallbacks = &defaultCallback;
}
log_v("<< setCallbacks");
} // setCallbacks

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


/**
* @brief Callback function to support a Notify request.
* @param [in] pCharacteristic The characteristic that is the source of the event.
*/
void BLECharacteristicCallbacks::onNotify(BLECharacteristic* pCharacteristic) {
log_d("BLECharacteristicCallbacks", ">> onNotify: default");
log_d("BLECharacteristicCallbacks", "<< onNotify");
} // onNotify


/**
* @brief Callback function to support a Notify/Indicate Status report.
* @param [in] pCharacteristic The characteristic that is the source of the event.
* @param [in] s Status of the notification/indication
* @param [in] code Additional code of underlying errors
*/
void BLECharacteristicCallbacks::onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) {
log_d("BLECharacteristicCallbacks", ">> onStatus: default");
log_d("BLECharacteristicCallbacks", "<< onStatus");
} // onStatus


#endif /* CONFIG_BT_ENABLED */
15 changes: 15 additions & 0 deletions libraries/BLE/src/BLECharacteristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class BLECharacteristic {
static const uint32_t PROPERTY_INDICATE = 1<<4;
static const uint32_t PROPERTY_WRITE_NR = 1<<5;

static const uint32_t indicationTimeout = 1000;

private:

friend class BLEServer;
Expand Down Expand Up @@ -130,9 +132,22 @@ class BLECharacteristic {
*/
class BLECharacteristicCallbacks {
public:
typedef enum {
SUCCESS_INDICATE,
SUCCESS_NOTIFY,
ERROR_INDICATE_DISABLED,
ERROR_NOTIFY_DISABLED,
ERROR_GATT,
ERROR_NO_CLIENT,
ERROR_INDICATE_TIMEOUT,
ERROR_INDICATE_FAILURE
}Status;

virtual ~BLECharacteristicCallbacks();
virtual void onRead(BLECharacteristic* pCharacteristic);
virtual void onWrite(BLECharacteristic* pCharacteristic);
virtual void onNotify(BLECharacteristic* pCharacteristic);
virtual void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code);
};
#endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */
32 changes: 32 additions & 0 deletions libraries/BLE/src/FreeRTOS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,38 @@ uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
return m_value;
} // wait

/**
* @brief Wait for a semaphore to be released in a given period of time by trying to take it and
* then releasing it again. The value associated with the semaphore can be taken by value() call after return
* @param [in] owner A debug tag.
* @param [in] timeoutMs timeout to wait in ms.
* @return True if we took the semaphore within timeframe.
*/
bool FreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) {
log_v(">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());

if (m_usePthreads && timeoutMs != portMAX_DELAY) {
assert(false); // We apparently don't have a timed wait for pthreads.
}

auto ret = pdTRUE;

if (m_usePthreads) {
pthread_mutex_lock(&m_pthread_mutex);
} else {
ret = xSemaphoreTake(m_semaphore, timeoutMs);
}

if (m_usePthreads) {
pthread_mutex_unlock(&m_pthread_mutex);
} else {
xSemaphoreGive(m_semaphore);
}

log_v("<< wait: Semaphore %s released: %d", toString().c_str(), ret);
return ret;
} // wait


FreeRTOS::Semaphore::Semaphore(std::string name) {
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
Expand Down
2 changes: 2 additions & 0 deletions libraries/BLE/src/FreeRTOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class FreeRTOS {
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
std::string toString();
uint32_t wait(std::string owner = "<Unknown>");
bool timedWait(std::string owner = "<Unknown>", uint32_t timeoutMs = portMAX_DELAY);
uint32_t value(){ return m_value; };

private:
SemaphoreHandle_t m_semaphore;
Expand Down

0 comments on commit 5137fc5

Please sign in to comment.