component/bt : Optimize Gatt attr table and fix some bugs

1. Optimize GATT attribute table structure
2. fix read/write bugs
3. add docs
This commit is contained in:
Island 2017-01-12 00:48:48 +08:00 committed by Tian Hao
parent d512d6100c
commit 9f151d745e
12 changed files with 284 additions and 223 deletions

View file

@ -286,13 +286,14 @@ typedef enum {
* @brief Attribute description (used to create database)
*/
typedef struct
{
esp_bt_uuid_t uuid; /*!< Element UUID */
{
uint16_t uuid_length; /*!< UUID length */
uint8_t *uuid_p; /*!< UUID value */
uint16_t perm; /*!< Attribute permission */
uint16_t max_length; /*!< Maximum length of the element*/
uint16_t length; /*!< Current length of the element*/
uint8_t* value; /*!< Element value array*/
}esp_attr_desc_t;
uint8_t *value; /*!< Element value array*/
} esp_attr_desc_t;
/**
@ -303,7 +304,7 @@ typedef struct
#define ESP_GATT_RSP_BY_APP 0
#define ESP_GATT_AUTO_RSP 1
uint8_t auto_rsp; /*!< need the app response to the client if need_rsp set to 1*/
}esp_attr_control_t;
} esp_attr_control_t;
/**
@ -312,8 +313,8 @@ typedef struct
typedef struct
{
esp_attr_control_t attr_control; /*!< The attribue control type*/
esp_attr_desc_t att_desc; /*!< The attribue type*/
}esp_gatts_attr_db_t;
esp_attr_desc_t att_desc; /*!< The attribue type*/
} esp_gatts_attr_db_t;
/**
@ -323,8 +324,8 @@ typedef struct
{
uint16_t attr_max_len; /*!< attribute max value length */
uint16_t attr_len; /*!< attribute current value length */
uint8_t *attr_value; /*!< the pointer to attribute value */
}esp_attr_value_t;
uint8_t *attr_value; /*!< the pointer to attribute value */
} esp_attr_value_t;
/**
@ -335,7 +336,7 @@ typedef struct
uint16_t start_hdl; /*!< Gatt start handle value of included service */
uint16_t end_hdl; /*!< Gatt end handle value of included service */
uint16_t uuid; /*!< Gatt attribute value UUID of included service */
}esp_gatts_incl_svc_desc_t; /*!< Gatt include service entry element */
} esp_gatts_incl_svc_desc_t; /*!< Gatt include service entry element */
/**
* @brief Gatt include 128 bit service entry element
@ -344,18 +345,9 @@ typedef struct
{
uint16_t start_hdl; /*!< Gatt start handle value of included 128 bit service */
uint16_t end_hdl; /*!< Gatt end handle value of included 128 bit service */
}esp_gatts_incl128_svc_desc_t; /*!< Gatt include 128 bit service entry element */
} esp_gatts_incl128_svc_desc_t; /*!< Gatt include 128 bit service entry element */
/**
* @brief Gatt characteristic entry element
*/
typedef struct
{
uint8_t prop; /*!< Gatt attribute properties */
uint16_t attr_hdl; /*!< Gatt attribute handle */
esp_bt_uuid_t attr_uuid; /*!< Gatt attribute uuid typedle */
}esp_gatts_char_desc_t; /*!< Gatt characteristic value descriptor */
/// Gatt attribute value

View file

@ -74,8 +74,10 @@ typedef union {
uint16_t handle; /*!< The attribute handle */
uint16_t offset; /*!< Offset of the value, if the value is too long */
bool is_long; /*!< The value is too long or not */
bool need_rsp; /*!< The read operation need to do response */
} read; /*!< Gatt server callback param of ESP_GATTS_READ_EVT */
/**
* @brief ESP_GATTS_WRITE_EVT
*/
@ -227,7 +229,7 @@ typedef union {
* @brief ESP_GATTS_RESPONSE_EVT
*/
struct gatts_rsp_evt_param {
esp_gatt_status_t status; /*!< Operation status */
esp_gatt_status_t status; /*!< Operation status */
uint16_t handle; /*!< Attribute handle which send response */
} rsp; /*!< Gatt server callback param of ESP_GATTS_RESPONSE_EVT */

View file

@ -403,16 +403,18 @@ void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
UINT16 attr_id = 0;
tBTA_GATTS cb_data;
tGATT_ATTR_VAL *p_attr_val = NULL;
tGATT_ATTR_VAL *p_attr_val = NULL;
tGATTS_ATTR_CONTROL *p_control = NULL;
if (p_msg->api_add_char_descr.attr_val.attr_max_len != 0) {
p_attr_val = &p_msg->api_add_char_descr.attr_val;
if(p_msg->api_add_char.attr_val.attr_max_len != 0){
p_attr_val = &p_msg->api_add_char.attr_val;
}
if (p_msg->api_add_char_descr.control.auto_rsp != 0) {
p_control = &p_msg->api_add_char_descr.control;
if(p_msg->api_add_char.control.auto_rsp != 0){
p_control = &p_msg->api_add_char.control;
}
attr_id = GATTS_AddCharacteristic(p_msg->api_add_char.hdr.layer_specific,
&p_msg->api_add_char.char_uuid,
p_msg->api_add_char.perm,
@ -429,6 +431,9 @@ void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
} else {
cb_data.add_result.status = BTA_GATT_ERROR;
}
if((p_attr_val != NULL) && (p_attr_val->attr_val != NULL)){
GKI_freebuf(p_attr_val->attr_val);
}
if (p_rcb->p_cback) {
(*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_EVT, &cb_data);
@ -476,6 +481,9 @@ void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
} else {
cb_data.add_result.status = BTA_GATT_ERROR;
}
if((p_attr_val != NULL) && (p_attr_val->attr_val != NULL)){
GKI_freebuf(p_attr_val->attr_val);
}
if (p_rcb->p_cback) {
(*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_DESCR_EVT, &cb_data);

View file

@ -274,47 +274,54 @@ void BTA_GATTS_AddCharDescriptor (UINT16 service_id,
tBTA_GATTS_ATTR_CONTROL *control)
{
tBTA_GATTS_API_ADD_DESCR *p_buf;
UINT16 len = 0;
if(attr_val != NULL) {
len = sizeof(tBTA_GATTS_API_ADD_DESCR) + attr_val->attr_len;
} else {
len = sizeof(tBTA_GATTS_API_ADD_DESCR);
}
UINT16 value_len = 0;
if ((p_buf = (tBTA_GATTS_API_ADD_DESCR *) GKI_getbuf(len)) != NULL) {
memset(p_buf, 0, len);
if ((p_buf = (tBTA_GATTS_API_ADD_DESCR *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_DESCR))) != NULL) {
memset(p_buf, 0, sizeof(tBTA_GATTS_API_ADD_DESCR));
p_buf->hdr.event = BTA_GATTS_API_ADD_DESCR_EVT;
p_buf->hdr.layer_specific = service_id;
p_buf->perm = perm;
if(control != NULL){
p_buf->control.auto_rsp = control->auto_rsp;
}
if (p_descr_uuid) {
memcpy(&p_buf->descr_uuid, p_descr_uuid, sizeof(tBT_UUID));
}
if(attr_val->attr_len != 0) {
if(attr_val != NULL){
p_buf->attr_val.attr_len = attr_val->attr_len;
p_buf->attr_val.attr_max_len= attr_val->attr_max_len;
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len);
p_buf->attr_val.attr_max_len = attr_val->attr_max_len;
value_len = attr_val->attr_len;
if (value_len != 0){
p_buf->attr_val.attr_val = (uint8_t*)GKI_getbuf(value_len);
if(p_buf->attr_val.attr_val != NULL){
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, value_len);
}
else{
APPL_TRACE_ERROR("Allocate fail for %s\n", __func__);
}
}
}
if(control != NULL) {
p_buf->control.auto_rsp = control->auto_rsp;
}
bta_sys_sendmsg(p_buf);
}
return;
}
/*******************************************************************************
**
** Function BTA_GATTS_DeleteService
**
** Description This function is called to delete a service. When this is done,
** a callback event BTA_GATTS_DELETE_EVT is report with the status.
**
** Parameters service_id: service_id to be deleted.
**
**
** Function BTA_GATTS_DeleteService
**
** Description This function is called to delete a service. When this is done,
** a callback event BTA_GATTS_DELETE_EVT is report with the status.
**
** Parameters service_id: service_id to be deleted.
**
** Returns returns none.
**
*******************************************************************************/

View file

@ -47,6 +47,25 @@ static inline void btc_gatts_cb_to_app(esp_gatts_cb_event_t event, esp_gatt_if_t
}
}
static inline void btc_gatts_uuid_format_convert(esp_bt_uuid_t* dest_uuid, uint16_t src_uuid_len, uint8_t* src_uuid_p)
{
dest_uuid->len = src_uuid_len;
if(src_uuid_len == ESP_UUID_LEN_16){
dest_uuid->uuid.uuid16 = src_uuid_p[0] + (src_uuid_p[1]<<8);
}
else if(src_uuid_len == ESP_UUID_LEN_32){
dest_uuid->uuid.uuid32 = src_uuid_p[0] + (src_uuid_p[1]<<8) + (src_uuid_p[2]<<16) + (src_uuid_p[3]<<24);
}
else if(src_uuid_len == ESP_UUID_LEN_128){
memcpy(dest_uuid->uuid.uuid128, src_uuid_p, src_uuid_len);
}
else{
LOG_ERROR("%s wrong uuid length %d\n", __func__, src_uuid_len);
}
}
void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
btc_ble_gatts_args_t *dst = (btc_ble_gatts_args_t *) p_dest;
@ -167,8 +186,8 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
btc_creat_tab_env.is_tab_creat_svc = true;
btc_creat_tab_env.num_handle = max_nb_attr;
for(int i = 0; i < max_nb_attr; i++){
if(gatts_attr_db[i].att_desc.uuid.len == ESP_UUID_LEN_16){
uuid = gatts_attr_db[i].att_desc.uuid.uuid.uuid16;
if(gatts_attr_db[i].att_desc.uuid_length== ESP_UUID_LEN_16){
uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]);
}
future_p = future_new();
if (future_p == NULL) {
@ -184,8 +203,10 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
esp_gatt_srvc_id_t esp_srvc_id;
esp_srvc_id.id.inst_id = srvc_inst_id;
memcpy(&esp_srvc_id.id.uuid, &gatts_attr_db[i].att_desc.uuid, sizeof(esp_bt_uuid_t));
btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.uuid_length,
gatts_attr_db[i].att_desc.uuid_p);
btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid,
srvc_inst_id, max_nb_attr, true);
@ -200,8 +221,9 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
esp_gatt_srvc_id_t esp_srvc_id;
esp_srvc_id.id.inst_id = srvc_inst_id;
memcpy(&esp_srvc_id.id.uuid, &gatts_attr_db[i].att_desc.uuid, sizeof(esp_bt_uuid_t));
btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.uuid_length,
gatts_attr_db[i].att_desc.uuid_p);
btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid,
srvc_inst_id, max_nb_attr, false);
if (future_await(future_p) == FUTURE_FAIL) {
@ -230,27 +252,33 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
uint16_t svc_hal = 0;
tBT_UUID bta_char_uuid;
tGATT_ATTR_VAL attr_val;
esp_bt_uuid_t uuid_temp;
tBTA_GATT_PERM perm;
tBTA_GATTS_ATTR_CONTROL control;
uint8_t char_property;
if(btc_creat_tab_env.svc_start_hdl != 0){
svc_hal = btc_creat_tab_env.svc_start_hdl;
esp_gatts_char_desc_t *char_desc = (esp_gatts_char_desc_t *)gatts_attr_db[i].att_desc.value;
if(char_desc != NULL){
if((gatts_attr_db[i].att_desc.value) == NULL){
LOG_ERROR("%s Characteristic declaration should not be NULL\n", __func__);
}
else{
char_property = (uint8_t)(*(uint8_t*)(gatts_attr_db[i].att_desc.value));
perm = gatts_attr_db[i+1].att_desc.perm;
attr_val.attr_len = gatts_attr_db[i+1].att_desc.length;
attr_val.attr_max_len = gatts_attr_db[i+1].att_desc.max_length;
btc_to_bta_uuid(&bta_char_uuid, &char_desc->attr_uuid);
btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i+1].att_desc.uuid_length,gatts_attr_db[i+1].att_desc.uuid_p);
btc_to_bta_uuid(&bta_char_uuid, &uuid_temp);
attr_val.attr_val = gatts_attr_db[i+1].att_desc.value;
control.auto_rsp = gatts_attr_db[i+1].attr_control.auto_rsp;
BTA_GATTS_AddCharacteristic (svc_hal, &bta_char_uuid,
perm, char_desc->prop, &attr_val, &control);
perm, char_property, &attr_val, &control);
if (future_await(future_p) == FUTURE_FAIL) {
LOG_ERROR("%s failed\n", __func__);
return;
}
}
}
}
break;
@ -266,6 +294,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
case ESP_GATT_UUID_RPT_REF_DESCR:{
uint16_t svc_hal = btc_creat_tab_env.svc_start_hdl;
tBT_UUID bta_char_uuid;
esp_bt_uuid_t uuid_temp;
tGATT_ATTR_VAL attr_val;
tBTA_GATT_PERM perm = gatts_attr_db[i].att_desc.perm;
tBTA_GATTS_ATTR_CONTROL control;
@ -274,7 +303,9 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
attr_val.attr_len = gatts_attr_db[i].att_desc.length;
attr_val.attr_max_len = gatts_attr_db[i].att_desc.max_length;
attr_val.attr_val = gatts_attr_db[i].att_desc.value;
btc_to_bta_uuid(&bta_char_uuid, &gatts_attr_db[i].att_desc.uuid);
btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i].att_desc.uuid_length,
gatts_attr_db[i].att_desc.uuid_p);
btc_to_bta_uuid(&bta_char_uuid, &uuid_temp);
control.auto_rsp = gatts_attr_db[i].attr_control.auto_rsp;
BTA_GATTS_AddCharDescriptor(svc_hal, perm, &bta_char_uuid, &attr_val, &control);
@ -573,6 +604,7 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
param.read.offset = p_data->req_data.p_data->read_req.offset;
param.read.is_long = p_data->req_data.p_data->read_req.is_long;
param.read.need_rsp = p_data->req_data.p_data->read_req.need_rsp;
btc_gatts_cb_to_app(ESP_GATTS_READ_EVT, gatts_if, &param);
break;
}

View file

@ -45,7 +45,7 @@ static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 le
static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri);
static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
UINT16 handle, UINT16 offset, UINT32 trans_id);
UINT16 handle, UINT16 offset, UINT32 trans_id, BOOLEAN need_rsp);
/*******************************************************************************
**
@ -268,16 +268,12 @@ static tGATT_STATUS read_attr_value (void *p_attr,
status = GATT_SUCCESS;
}
} else { /* characteristic description or characteristic value */
if (p_attr16->control.auto_rsp == GATT_RSP_BY_STACK) {
GATT_TRACE_DEBUG("before characteristic description or characteristic value\n");
if (p_attr16->p_value != NULL && p_attr16->p_value->attr_val.attr_val != NULL) {
uint8_t *value = p_attr16->p_value->attr_val.attr_val + offset;
GATT_TRACE_DEBUG("after characteristic description or characteristic value\n");
if (mtu >= p_attr16->p_value->attr_val.attr_len) {
ARRAY_TO_STREAM(p, value, p_attr16->p_value->attr_val.attr_len);
} else {
ARRAY_TO_STREAM(p, value, mtu);
}
len = (mtu >= p_attr16->p_value->attr_val.attr_len) ? (p_attr16->p_value->attr_val.attr_len) : mtu;
ARRAY_TO_STREAM(p, value, len);
}
status = GATT_STACK_RSP;
@ -357,7 +353,8 @@ tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb,
status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len - 2), &len, sec_flag, key_size);
if (status == GATT_PENDING || status == GATT_STACK_RSP) {
status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id);
BOOLEAN need_rsp = (status != GATT_STACK_RSP);
status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id, need_rsp);
/* one callback at a time */
break;
@ -630,7 +627,7 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
UINT16 length, UINT8 *value)
{
tGATT_ATTR16 *p_cur, *p_next;
tGATT_ATTR16 *p_cur;
if (p_db == NULL) {
GATT_TRACE_DEBUG("gatts_set_attribute_value Fail:p_db is NULL.\n");
@ -642,19 +639,21 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
}
p_cur = (tGATT_ATTR16 *) p_db->p_attr_list;
p_next = (tGATT_ATTR16 *) p_cur->p_next;
for (; p_cur != NULL; p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next) {
while (p_cur != NULL) {
if (p_cur->handle == attr_handle) {
if (p_cur->uuid_type == GATT_ATTR_UUID_TYPE_16) {
switch (p_cur->uuid) {
case GATT_UUID_PRI_SERVICE:
case GATT_UUID_SEC_SERVICE:
case GATT_UUID_CHAR_DECLARE:
case GATT_UUID_INCLUDE_SERVICE:
return GATT_NOT_FOUND;
default:
if (p_cur->p_value->attr_val.attr_max_len < length) {
GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length");
return GATT_INVALID_ATTR_LEN;
} else {
memcpy(p_cur->p_value->attr_val.attr_val, value, length);
p_cur->p_value->attr_val.attr_len = length;
@ -668,9 +667,14 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
memcpy(p_cur->p_value->attr_val.attr_val, value, length);
p_cur->p_value->attr_val.attr_len = length;
}
}
break;
}
p_cur = p_cur->p_next;
}
return GATT_SUCCESS;
@ -694,7 +698,7 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
UINT16 *length, UINT8 **value)
{
tGATT_ATTR16 *p_cur, *p_next;
tGATT_ATTR16 *p_cur;
GATT_TRACE_DEBUG("***********%s*************\n", __func__);
GATT_TRACE_DEBUG("attr_handle = %x\n", attr_handle);
if (p_db == NULL) {
@ -707,10 +711,8 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
}
p_cur = (tGATT_ATTR16 *) p_db->p_attr_list;
p_next = (tGATT_ATTR16 *) p_cur->p_next;
for (; p_cur != NULL; p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next) {
while (p_cur != NULL) {
LOG_ERROR("p_ur->handle = %x\n", p_cur->handle);
if (p_cur->handle == attr_handle) {
@ -736,7 +738,7 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
*value = p_cur->p_value->attr_val.attr_val;
return GATT_SUCCESS;
} else {
GATT_TRACE_ERROR("gatts_get_attribute_vaule failt:the value length is 0");
GATT_TRACE_ERROR("gatts_get_attribute_vaule failed:the value length is 0");
return GATT_INVALID_ATTR_LEN;
}
@ -747,9 +749,10 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
}
p_cur = p_cur->p_next;
}
return GATT_SUCCESS;
return GATT_NOT_FOUND;
}
BOOLEAN gatts_is_auto_response(UINT16 attr_handle)
@ -839,8 +842,9 @@ tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,
(BOOLEAN)(op_code == GATT_REQ_READ_BLOB),
mtu, p_len, sec_flag, key_size);
if (status == GATT_PENDING) {
status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id);
if ((status == GATT_PENDING) || (status == GATT_STACK_RSP)) {
BOOLEAN need_rsp = (status != GATT_STACK_RSP);
status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id, need_rsp);
}
break;
}
@ -848,6 +852,7 @@ tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,
}
}
return status;
}
@ -867,7 +872,7 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db,
return GATT_APP_RSP;
}
if (p_attr->p_value != NULL && (p_attr->p_value->attr_val.attr_max_len >
if (p_attr->p_value != NULL && (p_attr->p_value->attr_val.attr_max_len >=
offset + len)) {
memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len);
p_attr->p_value->attr_val.attr_len = len + offset;
@ -1301,7 +1306,7 @@ static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db)
**
*******************************************************************************/
static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
UINT16 handle, UINT16 offset, UINT32 trans_id)
UINT16 handle, UINT16 offset, UINT32 trans_id, BOOLEAN need_rsp)
{
tGATTS_DATA sr_data;
UINT8 i_rcb;
@ -1323,6 +1328,7 @@ static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
sr_data.read_req.handle = handle;
sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB);
sr_data.read_req.offset = offset;
sr_data.read_req.need_rsp = need_rsp;
gatt_sr_send_req_callback(conn_id,
trans_id, GATTS_REQ_TYPE_READ, &sr_data);

View file

@ -987,14 +987,14 @@ void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len,
void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
UINT8 op_code, UINT16 len, UINT8 *p_data)
{
UINT16 buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
tGATTS_DATA sr_data;
UINT32 trans_id;
tGATT_STATUS status;
UINT8 sec_flag, key_size, *p = p_data, *p_m;
tGATT_SR_REG *p_sreg;
UINT16 conn_id, offset = 0;
BT_HDR *p_msg = NULL;
UINT16 buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
tGATTS_DATA sr_data;
UINT32 trans_id;
tGATT_STATUS status;
UINT8 sec_flag, key_size, *p = p_data, *p_m;
tGATT_SR_REG *p_sreg;
UINT16 conn_id, offset = 0;
BT_HDR *p_msg = NULL;
memset(&sr_data, 0, sizeof(tGATTS_DATA));
if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) {
@ -1011,10 +1011,10 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
case GATT_REQ_PREPARE_WRITE:
sr_data.write_req.is_prep = TRUE;
STREAM_TO_UINT16(sr_data.write_req.offset, p);
UINT16_TO_STREAM(p_m, sr_data.write_req.is_prep);
offset = sr_data.write_req.offset;
UINT16_TO_STREAM(p_m, sr_data.write_req.is_prep);
offset = sr_data.write_req.offset;
len -= 2;
/* fall through */
/* fall through */
case GATT_SIGN_CMD_WRITE:
if (op_code == GATT_SIGN_CMD_WRITE) {
GATT_TRACE_DEBUG("Write CMD with data sigining" );
@ -1025,16 +1025,16 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
case GATT_REQ_WRITE:
if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE) {
sr_data.write_req.need_rsp = TRUE;
if(op_code == GATT_REQ_PREPARE_WRITE){
memcpy(p_m, p, len);
p_msg->len += len;
}
if(op_code == GATT_REQ_PREPARE_WRITE){
memcpy(p_m, p, len);
p_msg->len += len;
}
}
sr_data.write_req.handle = handle;
sr_data.write_req.len = len;
if (len != 0 && p != NULL) {
memcpy (sr_data.write_req.value, p, len);
}
break;
}
@ -1053,24 +1053,31 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
sec_flag,
key_size);
p_msg->len += len;
if (status == GATT_SUCCESS) {
if ((trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle)) != 0) {
p_sreg = &gatt_cb.sr_reg[i_rcb];
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
status = gatts_write_attr_value_by_handle(gatt_cb.sr_reg[i_rcb].p_db,
handle, offset, p, len);
status = gatts_write_attr_value_by_handle(gatt_cb.sr_reg[i_rcb].p_db,
handle, offset, p, len);
if((sr_data.write_req.need_rsp == TRUE) && (status == GATT_APP_RSP)){
sr_data.write_req.need_rsp = TRUE;
status = GATT_PENDING;
}
else{
sr_data.write_req.need_rsp = FALSE;
}
gatt_sr_send_req_callback(conn_id,
trans_id,
GATTS_REQ_TYPE_WRITE,
&sr_data);
if(status == GATT_SUCCESS){
attp_send_sr_msg(p_tcb, p_msg);
}else if(status == GATT_NOT_LONG){
gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE);
}
status = GATT_PENDING;
trans_id,
GATTS_REQ_TYPE_WRITE,
&sr_data);
if(status == GATT_SUCCESS){
attp_send_sr_msg(p_tcb, p_msg);
gatt_dequeue_sr_cmd(p_tcb);
}
} else {
GATT_TRACE_ERROR("max pending command, send error\n");
status = GATT_BUSY; /* max pending command, application error */
@ -1078,23 +1085,24 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
}
/* in theroy BUSY is not possible(should already been checked), protected check */
if (status != GATT_PENDING && status != GATT_BUSY &&
if (status != GATT_PENDING && status != GATT_BUSY && status != GATT_SUCCESS &&
(op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) {
gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE);
gatt_dequeue_sr_cmd(p_tcb);
}
return;
}
/*******************************************************************************
**
** Function gatts_process_read_req
**
** Description This function is called to process the read request
** from client.
**
** Returns void
**
*******************************************************************************/
**
** Function gatts_process_read_req
**
** Description This function is called to process the read request
** from client.
**
** Returns void
**
*******************************************************************************/
static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8 op_code,
UINT16 handle, UINT16 len, UINT8 *p_data)
{
@ -1140,7 +1148,8 @@ static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8
p_msg->len += value_len;
}
if (reason != GATT_SUCCESS && reason != GATT_PENDING) {
if (reason != GATT_SUCCESS && reason != GATT_PENDING && reason != GATT_STACK_RSP) {
if (p_msg) {
GKI_freebuf(p_msg);
}
@ -1148,9 +1157,11 @@ static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8
/* in theroy BUSY is not possible(should already been checked), protected check */
if (reason != GATT_BUSY) {
gatt_send_error_rsp (p_tcb, reason, op_code, handle, FALSE);
gatt_dequeue_sr_cmd(p_tcb);
}
} else {
attp_send_sr_msg(p_tcb, p_msg);
gatt_dequeue_sr_cmd(p_tcb);
}
}
@ -1376,24 +1387,24 @@ void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code,
/* otherwise, ignore the pkt */
} else {
switch (op_code) {
case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
gatts_process_primary_service_req (p_tcb, op_code, len, p_data);
break;
case GATT_REQ_FIND_INFO: /* discover char descrptor */
case GATT_REQ_FIND_INFO: /* discover char descrptor */
gatts_process_find_info(p_tcb, op_code, len, p_data);
break;
case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor value */
case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor value */
/* discover characteristic, discover char by UUID */
gatts_process_read_by_type_req(p_tcb, op_code, len, p_data);
break;
case GATT_REQ_READ: /* read char/char descriptor value */
case GATT_REQ_READ: /* read char/char descriptor value */
case GATT_REQ_READ_BLOB:
case GATT_REQ_WRITE: /* write char/char descriptor value */
case GATT_REQ_WRITE: /* write char/char descriptor value */
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
case GATT_REQ_PREPARE_WRITE:

View file

@ -349,6 +349,7 @@ typedef struct {
UINT16 handle;
UINT16 offset;
BOOLEAN is_long;
BOOLEAN need_rsp;
} tGATT_READ_REQ;
/* write request data */

View file

@ -25,6 +25,29 @@ Header Files
Macros
^^^^^^
.. doxygendefine:: ESP_GATT_UUID_IMMEDIATE_ALERT_SVC
.. doxygendefine:: ESP_GATT_UUID_LINK_LOSS_SVC
.. doxygendefine:: ESP_GATT_UUID_TX_POWER_SVC
.. doxygendefine:: ESP_GATT_UUID_CURRENT_TIME_SVC
.. doxygendefine:: ESP_GATT_UUID_REF_TIME_UPDATE_SVC
.. doxygendefine:: ESP_GATT_UUID_NEXT_DST_CHANGE_SVC
.. doxygendefine:: ESP_GATT_UUID_GLUCOSE_SVC
.. doxygendefine:: ESP_GATT_UUID_HEALTH_THERMOM_SVC
.. doxygendefine:: ESP_GATT_UUID_DEVICE_INFO_SVC
.. doxygendefine:: ESP_GATT_UUID_HEART_RATE_SVC
.. doxygendefine:: ESP_GATT_UUID_PHONE_ALERT_STATUS_SVC
.. doxygendefine:: ESP_GATT_UUID_BATTERY_SERVICE_SVC
.. doxygendefine:: ESP_GATT_UUID_BLOOD_PRESSURE_SVC
.. doxygendefine:: ESP_GATT_UUID_ALERT_NTF_SVC
.. doxygendefine:: ESP_GATT_UUID_HID_SVC
.. doxygendefine:: ESP_GATT_UUID_SCAN_PARAMETERS_SVC
.. doxygendefine:: ESP_GATT_UUID_RUNNING_SPEED_CADENCE_SVC
.. doxygendefine:: ESP_GATT_UUID_CYCLING_SPEED_CADENCE_SVC
.. doxygendefine:: ESP_GATT_UUID_CYCLING_POWER_SVC
.. doxygendefine:: ESP_GATT_UUID_LOCATION_AND_NAVIGATION_SVC
.. doxygendefine:: ESP_GATT_UUID_USER_DATA_SVC
.. doxygendefine:: ESP_GATT_UUID_WEIGHT_SCALE_SVC
.. doxygendefine:: ESP_GATT_UUID_PRI_SERVICE
.. doxygendefine:: ESP_GATT_UUID_SEC_SERVICE
.. doxygendefine:: ESP_GATT_UUID_INCLUDE_SERVICE
@ -74,6 +97,9 @@ Macros
.. doxygendefine:: ESP_GATT_UUID_HID_BT_KB_INPUT
.. doxygendefine:: ESP_GATT_UUID_HID_BT_KB_OUTPUT
.. doxygendefine:: ESP_GATT_UUID_HID_BT_MOUSE_INPUT
.. doxygendefine:: ESP_GATT_HEART_RATE_MEAS
.. doxygendefine:: ESP_GATT_BODY_SENSOR_LOCATION
.. doxygendefine:: ESP_GATT_HEART_RATE_CNTL_POINT
.. doxygendefine:: ESP_GATT_UUID_BATTERY_LEVEL
.. doxygendefine:: ESP_GATT_UUID_SC_CONTROL_POINT
.. doxygendefine:: ESP_GATT_UUID_SENSOR_LOCATION
@ -87,6 +113,8 @@ Macros
.. doxygendefine:: ESP_GATT_ILLEGAL_HANDLE
.. doxygendefine:: ESP_GATT_ATTR_HANDLE_MAX
.. doxygendefine:: ESP_GATT_MAX_ATTR_LEN
.. doxygendefine:: ESP_GATT_RSP_BY_APP
.. doxygendefine:: ESP_GATT_AUTO_RSP
.. doxygendefine:: ESP_GATT_IF_NONE
Type Definitions
@ -126,9 +154,6 @@ Structures
.. doxygenstruct:: esp_gatts_incl128_svc_desc_t
:members:
.. doxygenstruct:: esp_gatts_char_desc_t
:members:
.. doxygenstruct:: esp_gatt_value_t
:members:

View file

@ -80,9 +80,6 @@ Structures
.. doxygenstruct:: esp_ble_gatts_cb_param_t::gatts_add_char_descr_evt_param
:members:
.. doxygenstruct:: esp_ble_gatts_cb_param_t::gatts_add_attr_tab_evt_param
:members:
.. doxygenstruct:: esp_ble_gatts_cb_param_t::gatts_delete_evt_param
:members:
@ -104,6 +101,9 @@ Structures
.. doxygenstruct:: esp_ble_gatts_cb_param_t::gatts_rsp_evt_param
:members:
.. doxygenstruct:: esp_ble_gatts_cb_param_t::gatts_add_attr_tab_evt_param
:members:
.. doxygenstruct:: esp_ble_gatts_cb_param_t::gatts_set_attr_val_evt_param
:members:

View file

@ -117,64 +117,6 @@ static struct gatts_profile_inst heart_rate_profile_tab[HEART_PROFILE_NUM] = {
****************************************************************************************
*/
/// Full HRS Database Description - Used to add attributes into the database
const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
{
// Heart Rate Service Declaration
[HRS_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_UUID_PRI_SERVICE}},
ESP_GATT_PERM_READ,
sizeof(heart_rate_svc),
sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}},
// Heart Rate Measurement Characteristic Declaration
[HRS_IDX_HR_MEAS_CHAR] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_UUID_CHAR_DECLARE}},
ESP_GATT_PERM_READ,
sizeof(heart_rate_meas_char),
sizeof(heart_rate_meas_char), (uint8_t *)&heart_rate_meas_char}},
// Heart Rate Measurement Characteristic Value
[HRS_IDX_HR_MEAS_VAL] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_HEART_RATE_MEAS}},
ESP_GATT_PERM_READ,
HRPS_HT_MEAS_MAX_LEN,
0, NULL}},
// Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor
[HRS_IDX_HR_MEAS_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_UUID_CHAR_SRVR_CONFIG}},
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),
0, NULL}},
// Body Sensor Location Characteristic Declaration
[HRS_IDX_BOBY_SENSOR_LOC_CHAR] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_UUID_CHAR_DECLARE}},
ESP_GATT_PERM_READ,
sizeof(heart_rate_body_sensor_loc_char),
sizeof(heart_rate_body_sensor_loc_char), (uint8_t *)&heart_rate_body_sensor_loc_char}},
// Body Sensor Location Characteristic Value
[HRS_IDX_BOBY_SENSOR_LOC_VAL] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_BODY_SENSOR_LOCATION}},
ESP_GATT_PERM_READ,
sizeof(uint8_t),
0, NULL}},
// Heart Rate Control Point Characteristic Declaration
[HRS_IDX_HR_CTNL_PT_CHAR] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_UUID_CHAR_DECLARE}},
ESP_GATT_PERM_READ,
sizeof(heart_rate_cntl_point_char),
sizeof(heart_rate_cntl_point_char), (uint8_t *)&heart_rate_cntl_point_char}},
// Heart Rate Control Point Characteristic Value
[HRS_IDX_HR_CTNL_PT_VAL] = {{ESP_GATT_AUTO_RSP}, {
{ESP_UUID_LEN_16, {ESP_GATT_HEART_RATE_CNTL_POINT}},
ESP_GATT_PERM_WRITE,
sizeof(uint8_t),
0, NULL}},
};
/*
* Heart Rate PROFILE ATTRIBUTES
@ -182,31 +124,75 @@ const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
*/
/// Heart Rate Sensor Service
const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC;
static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC;
/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic
const esp_gatts_char_desc_t heart_rate_meas_char =
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_READ;
/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify
static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS;
static const uint8_t heart_measurement_ccc[2] ={ 0x00, 0x00};
/// Heart Rate Sensor Service -Body Sensor Location characteristic, read
static const uint16_t body_sensor_location_uuid = ESP_GATT_BODY_SENSOR_LOCATION;
static const uint8_t body_sensor_loc_val[1] = {0x00};
/// Heart Rate Sensor Service - Heart Rate Control Point characteristic, write&read
static const uint16_t heart_rate_ctrl_point = ESP_GATT_HEART_RATE_CNTL_POINT;
static const uint8_t heart_ctrl_point[1] = {0x00};
/// Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
{
.prop = ESP_GATT_CHAR_PROP_BIT_NOTIFY,
.attr_hdl = 0,
.attr_uuid = {ESP_UUID_LEN_16, {ESP_GATT_HEART_RATE_MEAS}},
// Heart Rate Service Declaration
[HRS_IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(uint16_t), sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}},
// Heart Rate Measurement Characteristic Declaration
[HRS_IDX_HR_MEAS_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
// Heart Rate Measurement Characteristic Value
[HRS_IDX_HR_MEAS_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_meas_uuid, ESP_GATT_PERM_READ,
HRPS_HT_MEAS_MAX_LEN,0, NULL}},
// Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor
[HRS_IDX_HR_MEAS_NTF_CFG] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
// Body Sensor Location Characteristic Declaration
[HRS_IDX_BOBY_SENSOR_LOC_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
// Body Sensor Location Characteristic Value
[HRS_IDX_BOBY_SENSOR_LOC_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&body_sensor_location_uuid, ESP_GATT_PERM_READ,
sizeof(uint8_t), sizeof(body_sensor_loc_val), (uint8_t *)body_sensor_loc_val}},
// Heart Rate Control Point Characteristic Declaration
[HRS_IDX_HR_CTNL_PT_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}},
// Heart Rate Control Point Characteristic Value
[HRS_IDX_HR_CTNL_PT_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_ctrl_point, ESP_GATT_PERM_WRITE|ESP_GATT_PERM_READ,
sizeof(uint8_t), sizeof(heart_ctrl_point), (uint8_t *)heart_ctrl_point}},
};
/// Heart Rate Sensor Service -Body Sensor Location characteristic
const esp_gatts_char_desc_t heart_rate_body_sensor_loc_char =
{
.prop = ESP_GATT_CHAR_PROP_BIT_READ,
.attr_hdl = 0,
.attr_uuid = {ESP_UUID_LEN_16, {ESP_GATT_BODY_SENSOR_LOCATION}},
};
/// Heart Rate Sensor Service - Heart Rate Control Point characteristic
const esp_gatts_char_desc_t heart_rate_cntl_point_char =
{
.prop = ESP_GATT_CHAR_PROP_BIT_WRITE,
.attr_hdl = 0,
.attr_uuid = {ESP_UUID_LEN_16, {ESP_GATT_HEART_RATE_CNTL_POINT}},
};
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
@ -223,7 +209,7 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
{
LOG_ERROR("event = %x\n",event);
switch (event) {
case ESP_GATTS_REG_EVT:

View file

@ -46,12 +46,3 @@ enum
HRS_IDX_NB,
};
extern const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB];
/// Heart Rate Sensor Service - only one instance for now
extern const uint16_t heart_rate_svc;
extern const esp_gatts_char_desc_t heart_rate_meas_char;
extern const esp_gatts_char_desc_t heart_rate_body_sensor_loc_char;
extern const esp_gatts_char_desc_t heart_rate_cntl_point_char;