Ble notification/indication status and timeout (#2998)
* add timed wait * Added Notification/Indication data and status callbacks * imply null-object pattern for BLE callback
This commit is contained in:
parent
03066e42ef
commit
5137fc5c80
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#define NULL_HANDLE (0xffff)
|
#define NULL_HANDLE (0xffff)
|
||||||
|
|
||||||
|
static BLECharacteristicCallbacks defaultCallback; //null-object-pattern
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
@ -40,7 +41,7 @@ BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) {
|
|||||||
m_bleUUID = uuid;
|
m_bleUUID = uuid;
|
||||||
m_handle = NULL_HANDLE;
|
m_handle = NULL_HANDLE;
|
||||||
m_properties = (esp_gatt_char_prop_t)0;
|
m_properties = (esp_gatt_char_prop_t)0;
|
||||||
m_pCallbacks = nullptr;
|
m_pCallbacks = &defaultCallback;
|
||||||
|
|
||||||
setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
||||||
setReadProperty((properties & PROPERTY_READ) != 0);
|
setReadProperty((properties & PROPERTY_READ) != 0);
|
||||||
@ -220,9 +221,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
|||||||
case ESP_GATTS_EXEC_WRITE_EVT: {
|
case ESP_GATTS_EXEC_WRITE_EVT: {
|
||||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
||||||
m_value.commit();
|
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 {
|
} else {
|
||||||
m_value.cancel();
|
m_value.cancel();
|
||||||
}
|
}
|
||||||
@ -307,7 +306,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
|||||||
}
|
}
|
||||||
} // Response needed
|
} // 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.
|
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||||
}
|
}
|
||||||
} // Match on handles.
|
} // Match on handles.
|
||||||
@ -378,9 +377,9 @@ void BLECharacteristic::handleGATTServerEvent(
|
|||||||
}
|
}
|
||||||
} else { // read.is_long == false
|
} 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
|
// 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.
|
// Invoke the read callback.
|
||||||
}
|
m_pCallbacks->onRead(this);
|
||||||
|
|
||||||
std::string value = m_value.getValue();
|
std::string value = m_value.getValue();
|
||||||
|
|
||||||
@ -480,10 +479,13 @@ void BLECharacteristic::notify(bool is_notification) {
|
|||||||
assert(getService() != nullptr);
|
assert(getService() != nullptr);
|
||||||
assert(getService()->getServer() != 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());
|
GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length());
|
||||||
|
|
||||||
if (getService()->getServer()->getConnectedCount() == 0) {
|
if (getService()->getServer()->getConnectedCount() == 0) {
|
||||||
log_v("<< notify: No connected clients.");
|
log_v("<< notify: No connected clients.");
|
||||||
|
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NO_CLIENT, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,12 +496,14 @@ void BLECharacteristic::notify(bool is_notification) {
|
|||||||
if(is_notification) {
|
if(is_notification) {
|
||||||
if (p2902 != nullptr && !p2902->getNotifications()) {
|
if (p2902 != nullptr && !p2902->getNotifications()) {
|
||||||
log_v("<< notifications disabled; ignoring");
|
log_v("<< notifications disabled; ignoring");
|
||||||
|
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NOTIFY_DISABLED, 0); // Invoke the notify callback.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (p2902 != nullptr && !p2902->getIndications()) {
|
if (p2902 != nullptr && !p2902->getIndications()) {
|
||||||
log_v("<< indications disabled; ignoring");
|
log_v("<< indications disabled; ignoring");
|
||||||
|
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED, 0); // Invoke the notify callback.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -510,7 +514,7 @@ void BLECharacteristic::notify(bool is_notification) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t length = m_value.getValue().length();
|
size_t length = m_value.getValue().length();
|
||||||
if(!is_notification)
|
if(!is_notification) // is indication
|
||||||
m_semaphoreConfEvt.take("indicate");
|
m_semaphoreConfEvt.take("indicate");
|
||||||
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
|
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
|
||||||
getService()->getServer()->getGattsIf(),
|
getService()->getServer()->getGattsIf(),
|
||||||
@ -519,10 +523,23 @@ void BLECharacteristic::notify(bool is_notification) {
|
|||||||
if (errRc != ESP_OK) {
|
if (errRc != ESP_OK) {
|
||||||
log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
|
log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
|
||||||
m_semaphoreConfEvt.give();
|
m_semaphoreConfEvt.give();
|
||||||
|
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_GATT, errRc); // Invoke the notify callback.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!is_notification)
|
if(!is_notification){ // is indication
|
||||||
m_semaphoreConfEvt.wait("indicate");
|
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");
|
log_v("<< notify");
|
||||||
} // Notify
|
} // Notify
|
||||||
@ -551,7 +568,11 @@ void BLECharacteristic::setBroadcastProperty(bool value) {
|
|||||||
*/
|
*/
|
||||||
void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
|
void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
|
||||||
log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
|
log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
|
||||||
|
if (pCallbacks != nullptr){
|
||||||
m_pCallbacks = pCallbacks;
|
m_pCallbacks = pCallbacks;
|
||||||
|
} else {
|
||||||
|
m_pCallbacks = &defaultCallback;
|
||||||
|
}
|
||||||
log_v("<< setCallbacks");
|
log_v("<< setCallbacks");
|
||||||
} // setCallbacks
|
} // setCallbacks
|
||||||
|
|
||||||
@ -754,4 +775,27 @@ void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) {
|
|||||||
log_d("BLECharacteristicCallbacks", "<< onWrite");
|
log_d("BLECharacteristicCallbacks", "<< onWrite");
|
||||||
} // 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 */
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
|
@ -90,6 +90,8 @@ public:
|
|||||||
static const uint32_t PROPERTY_INDICATE = 1<<4;
|
static const uint32_t PROPERTY_INDICATE = 1<<4;
|
||||||
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
||||||
|
|
||||||
|
static const uint32_t indicationTimeout = 1000;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class BLEServer;
|
friend class BLEServer;
|
||||||
@ -130,9 +132,22 @@ private:
|
|||||||
*/
|
*/
|
||||||
class BLECharacteristicCallbacks {
|
class BLECharacteristicCallbacks {
|
||||||
public:
|
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 ~BLECharacteristicCallbacks();
|
||||||
virtual void onRead(BLECharacteristic* pCharacteristic);
|
virtual void onRead(BLECharacteristic* pCharacteristic);
|
||||||
virtual void onWrite(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 /* CONFIG_BT_ENABLED */
|
||||||
#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */
|
#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */
|
||||||
|
@ -78,6 +78,38 @@ uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
|
|||||||
return m_value;
|
return m_value;
|
||||||
} // wait
|
} // 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) {
|
FreeRTOS::Semaphore::Semaphore(std::string name) {
|
||||||
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
|
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
|
||||||
|
@ -40,6 +40,8 @@ public:
|
|||||||
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
|
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
|
||||||
std::string toString();
|
std::string toString();
|
||||||
uint32_t wait(std::string owner = "<Unknown>");
|
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:
|
private:
|
||||||
SemaphoreHandle_t m_semaphore;
|
SemaphoreHandle_t m_semaphore;
|
||||||
|
Loading…
Reference in New Issue
Block a user