360e04fa36
* BLERemoteChar: fix descriptor 2902 write for characteristic notifications When registering a notification on a characteristic, the 2902 descriptor (CCCD) value is set to 1 (or 2 for indication). According to the BLUETOOTH CORE SPECIFICATION Version 5.2, Revision Date 2019-12-31, section 4.12.3 "Write Characteristic Descriptors" (page 1588), the characteristic descriptor write must expect a response. Currently, the descriptor write is performed without expecting a reponse, which prevents the notification to be functional with some BLE stacks. This commit modify the write to expect the response. Signed-off-by: Jimmy Durand Wesolowski <jimmy.durand.wesolowski@commsolid.com> * BLERemoteChar: forward GATT client event to characteristic descriptors This commits prevents a permanent wait when calling BLERemoteDescriptor readValue function, on the m_semaphoreReadDescrEvt semaphore. ESP32 BLE stack calls to remote characteristic - notification, - value read - value write and remote characteristic descriptor - value read are asynchronous. When such a call is performed by this library, a semaphore is taken prior to the BLE stack read or write operation, and waited on after it. Releasing the semaphore is done by the characteristic event handling function (gattClientEventHandler), when the appropriate event is received. However, the characteristic descriptor events are discarded, and the value read semaphore is never released. This commits forwards the GATT client events from the remote characteristic down to their remote characteristic descriptor, and implements their event handling. Adding a semaphore for the remote characteristic descriptor value write will be done in a separate commit. Signed-off-by: Jimmy Durand Wesolowski <jimmy.durand.wesolowski@commsolid.com> * BLERemoteDescriptor: add semaphore to characteristic descriptor write This adds a semaphore to characteristic descriptor value write, to mimic the value read function, and to ensure completion of the operation before we carry on. Signed-off-by: Jimmy Durand Wesolowski <jimmy.durand.wesolowski@commsolid.com> Co-authored-by: Jimmy Durand Wesolowski <jimmy.durand.wesolowski@commsolid.com>
205 lines
5.7 KiB
C++
205 lines
5.7 KiB
C++
/*
|
|
* BLERemoteDescriptor.cpp
|
|
*
|
|
* Created on: Jul 8, 2017
|
|
* Author: kolban
|
|
*/
|
|
#include "sdkconfig.h"
|
|
#if defined(CONFIG_BT_ENABLED)
|
|
#include <sstream>
|
|
#include "BLERemoteDescriptor.h"
|
|
#include "GeneralUtils.h"
|
|
#include "esp32-hal-log.h"
|
|
|
|
BLERemoteDescriptor::BLERemoteDescriptor(
|
|
uint16_t handle,
|
|
BLEUUID uuid,
|
|
BLERemoteCharacteristic* pRemoteCharacteristic) {
|
|
|
|
m_handle = handle;
|
|
m_uuid = uuid;
|
|
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
|
m_auth = ESP_GATT_AUTH_REQ_NONE;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Retrieve the handle associated with this remote descriptor.
|
|
* @return The handle associated with this remote descriptor.
|
|
*/
|
|
uint16_t BLERemoteDescriptor::getHandle() {
|
|
return m_handle;
|
|
} // getHandle
|
|
|
|
|
|
/**
|
|
* @brief Get the characteristic that owns this descriptor.
|
|
* @return The characteristic that owns this descriptor.
|
|
*/
|
|
BLERemoteCharacteristic* BLERemoteDescriptor::getRemoteCharacteristic() {
|
|
return m_pRemoteCharacteristic;
|
|
} // getRemoteCharacteristic
|
|
|
|
|
|
/**
|
|
* @brief Retrieve the UUID associated this remote descriptor.
|
|
* @return The UUID associated this remote descriptor.
|
|
*/
|
|
BLEUUID BLERemoteDescriptor::getUUID() {
|
|
return m_uuid;
|
|
} // getUUID
|
|
|
|
void BLERemoteDescriptor::gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) {
|
|
switch(event) {
|
|
case ESP_GATTC_READ_DESCR_EVT:
|
|
if (evtParam->read.handle != getHandle())
|
|
break;
|
|
m_semaphoreReadDescrEvt.give();
|
|
break;
|
|
|
|
case ESP_GATTC_WRITE_DESCR_EVT:
|
|
if (evtParam->write.handle != getHandle())
|
|
break;
|
|
m_semaphoreWriteDescrEvt.give();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string BLERemoteDescriptor::readValue() {
|
|
log_v(">> readValue: %s", toString().c_str());
|
|
|
|
// Check to see that we are connected.
|
|
if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) {
|
|
log_e("Disconnected");
|
|
return std::string();
|
|
}
|
|
|
|
m_semaphoreReadDescrEvt.take("readValue");
|
|
|
|
// Ask the BLE subsystem to retrieve the value for the remote hosted characteristic.
|
|
esp_err_t errRc = ::esp_ble_gattc_read_char_descr(
|
|
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
|
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(), // The connection ID to the BLE server
|
|
getHandle(), // The handle of this characteristic
|
|
m_auth); // Security
|
|
|
|
if (errRc != ESP_OK) {
|
|
log_e("esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
|
return "";
|
|
}
|
|
|
|
// Block waiting for the event that indicates that the read has completed. When it has, the std::string found
|
|
// in m_value will contain our data.
|
|
m_semaphoreReadDescrEvt.wait("readValue");
|
|
|
|
log_v("<< readValue(): length: %d", m_value.length());
|
|
return m_value;
|
|
} // readValue
|
|
|
|
|
|
uint8_t BLERemoteDescriptor::readUInt8() {
|
|
std::string value = readValue();
|
|
if (value.length() >= 1) {
|
|
return (uint8_t) value[0];
|
|
}
|
|
return 0;
|
|
} // readUInt8
|
|
|
|
|
|
uint16_t BLERemoteDescriptor::readUInt16() {
|
|
std::string value = readValue();
|
|
if (value.length() >= 2) {
|
|
return *(uint16_t*) value.data();
|
|
}
|
|
return 0;
|
|
} // readUInt16
|
|
|
|
|
|
uint32_t BLERemoteDescriptor::readUInt32() {
|
|
std::string value = readValue();
|
|
if (value.length() >= 4) {
|
|
return *(uint32_t*) value.data();
|
|
}
|
|
return 0;
|
|
} // readUInt32
|
|
|
|
|
|
/**
|
|
* @brief Return a string representation of this BLE Remote Descriptor.
|
|
* @retun A string representation of this BLE Remote Descriptor.
|
|
*/
|
|
std::string BLERemoteDescriptor::toString() {
|
|
char val[6];
|
|
snprintf(val, sizeof(val), "%d", getHandle());
|
|
std::string res = "handle: ";
|
|
res += val;
|
|
res += ", uuid: " + getUUID().toString();
|
|
return res;
|
|
} // toString
|
|
|
|
|
|
/**
|
|
* @brief Write data to the BLE Remote Descriptor.
|
|
* @param [in] data The data to send to the remote descriptor.
|
|
* @param [in] length The length of the data to send.
|
|
* @param [in] response True if we expect a response.
|
|
*/
|
|
void BLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response) {
|
|
log_v(">> writeValue: %s", toString().c_str());
|
|
// Check to see that we are connected.
|
|
if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) {
|
|
log_e("Disconnected");
|
|
return;
|
|
}
|
|
|
|
m_semaphoreWriteDescrEvt.take("writeValue");
|
|
|
|
esp_err_t errRc = ::esp_ble_gattc_write_char_descr(
|
|
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
|
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(),
|
|
getHandle(),
|
|
length, // Data length
|
|
data, // Data
|
|
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP,
|
|
m_auth
|
|
);
|
|
if (errRc != ESP_OK) {
|
|
log_e("esp_ble_gattc_write_char_descr: %d", errRc);
|
|
}
|
|
|
|
m_semaphoreWriteDescrEvt.wait("writeValue");
|
|
log_v("<< writeValue");
|
|
} // writeValue
|
|
|
|
|
|
/**
|
|
* @brief Write data represented as a string to the BLE Remote Descriptor.
|
|
* @param [in] newValue The data to send to the remote descriptor.
|
|
* @param [in] response True if we expect a response.
|
|
*/
|
|
void BLERemoteDescriptor::writeValue(std::string newValue, bool response) {
|
|
writeValue((uint8_t*) newValue.data(), newValue.length(), response);
|
|
} // writeValue
|
|
|
|
|
|
/**
|
|
* @brief Write a byte value to the Descriptor.
|
|
* @param [in] The single byte to write.
|
|
* @param [in] True if we expect a response.
|
|
*/
|
|
void BLERemoteDescriptor::writeValue(uint8_t newValue, bool response) {
|
|
writeValue(&newValue, 1, response);
|
|
} // writeValue
|
|
|
|
/**
|
|
* @brief Set authentication request type for characteristic
|
|
* @param [in] auth Authentication request type.
|
|
*/
|
|
void BLERemoteDescriptor::setAuth(esp_gatt_auth_req_t auth) {
|
|
m_auth = auth;
|
|
}
|
|
|
|
#endif /* CONFIG_BT_ENABLED */
|