#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include <sstream>
#include <string.h>
#include <iomanip>
#include <stdlib.h>
#include "sdkconfig.h"
#include <esp_log.h>
#include <esp_err.h>
#include "BLEService.h"
#include "BLEDescriptor.h"
#include "GeneralUtils.h"
#ifdef ARDUINO_ARCH_ESP32
#include "esp32-hal-log.h"
#endif
static const char* LOG_TAG = "BLEDescriptor";
#define NULL_HANDLE (0xffff)
BLEDescriptor::BLEDescriptor(const char* uuid) : BLEDescriptor(BLEUUID(uuid)) {
}
BLEDescriptor::BLEDescriptor(BLEUUID uuid) {
m_bleUUID = uuid;
m_value.attr_value = (uint8_t *)malloc(ESP_GATT_MAX_ATTR_LEN);
m_value.attr_len = 0;
m_value.attr_max_len = ESP_GATT_MAX_ATTR_LEN;
m_handle = NULL_HANDLE;
m_pCharacteristic = nullptr;
m_pCallback = nullptr;
}
BLEDescriptor::~BLEDescriptor() {
free(m_value.attr_value);
}
void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) {
ESP_LOGD(LOG_TAG, ">> executeCreate(): %s", toString().c_str());
if (m_handle != NULL_HANDLE) {
ESP_LOGE(LOG_TAG, "Descriptor already has a handle.");
return;
}
m_pCharacteristic = pCharacteristic;
esp_attr_control_t control;
control.auto_rsp = ESP_GATT_RSP_BY_APP;
m_semaphoreCreateEvt.take("executeCreate");
esp_err_t errRc = ::esp_ble_gatts_add_char_descr(
pCharacteristic->getService()->getHandle(),
getUUID().getNative(),
(esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE),
&m_value,
&control);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
m_semaphoreCreateEvt.wait("executeCreate");
ESP_LOGD(LOG_TAG, "<< executeCreate");
}
uint16_t BLEDescriptor::getHandle() {
return m_handle;
}
size_t BLEDescriptor::getLength() {
return m_value.attr_len;
}
BLEUUID BLEDescriptor::getUUID() {
return m_bleUUID;
}
uint8_t* BLEDescriptor::getValue() {
return m_value.attr_value;
}
void BLEDescriptor::handleGATTServerEvent(
esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t *param) {
switch(event) {
case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
if (m_pCharacteristic != nullptr &&
m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid)) &&
m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle &&
m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) {
setHandle(param->add_char_descr.attr_handle);
m_semaphoreCreateEvt.give();
}
break;
}
case ESP_GATTS_WRITE_EVT: {
if (param->write.handle == m_handle) {
setValue(param->write.value, param->write.len);
esp_gatt_rsp_t rsp;
rsp.attr_value.len = getLength();
rsp.attr_value.handle = m_handle;
rsp.attr_value.offset = 0;
rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len);
esp_err_t errRc = ::esp_ble_gatts_send_response(
gatts_if,
param->write.conn_id,
param->write.trans_id,
ESP_GATT_OK,
&rsp);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
}
if (m_pCallback != nullptr) {
m_pCallback->onWrite(this);
}
}
break;
}
case ESP_GATTS_READ_EVT: {
if (param->read.handle == m_handle) {
if (m_pCallback != nullptr) {
m_pCallback->onRead(this);
}
if (param->read.need_rsp) {
ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)");
esp_gatt_rsp_t rsp;
rsp.attr_value.len = getLength();
rsp.attr_value.handle = param->read.handle;
rsp.attr_value.offset = 0;
rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len);
esp_err_t errRc = ::esp_ble_gatts_send_response(
gatts_if,
param->read.conn_id,
param->read.trans_id,
ESP_GATT_OK,
&rsp);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
}
}
}
break;
}
default: {
break;
}
}
}
void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks* pCallback) {
ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t)pCallback);
m_pCallback = pCallback;
ESP_LOGD(LOG_TAG, "<< setCallbacks");
}
void BLEDescriptor::setHandle(uint16_t handle) {
ESP_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle);
m_handle = handle;
ESP_LOGD(LOG_TAG, "<< setHandle()");
}
void BLEDescriptor::setValue(uint8_t* data, size_t length) {
if (length > ESP_GATT_MAX_ATTR_LEN) {
ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN);
return;
}
m_value.attr_len = length;
memcpy(m_value.attr_value, data, length);
}
void BLEDescriptor::setValue(std::string value) {
setValue((uint8_t *)value.data(), value.length());
}
std::string BLEDescriptor::toString() {
std::stringstream stringstream;
stringstream << std::hex << std::setfill('0');
stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle;
return stringstream.str();
}
BLEDescriptorCallbacks::~BLEDescriptorCallbacks() {}
void BLEDescriptorCallbacks::onRead(BLEDescriptor* pDescriptor) {
ESP_LOGD("BLEDescriptorCallbacks", ">> onRead: default");
ESP_LOGD("BLEDescriptorCallbacks", "<< onRead");
}
void BLEDescriptorCallbacks::onWrite(BLEDescriptor* pDescriptor) {
ESP_LOGD("BLEDescriptorCallbacks", ">> onWrite: default");
ESP_LOGD("BLEDescriptorCallbacks", "<< onWrite");
}
#endif