arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.cpp
Jimmy Durand Wesolowski 360e04fa36
Fixing BLE GATT Characteristic notification and Characteristic Descriptor read (#4464)
* 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>
2020-11-02 18:36:25 +02:00

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 */