From 0b76c3615e64b88ff65eaba272335e428e94dbd5 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Thu, 8 Dec 2022 19:49:35 +0800 Subject: [PATCH] bluedroid: add internal GATT API for PTS --- .../host/bluedroid/bta/gatt/bta_gattc_act.c | 9 +- .../host/bluedroid/bta/gatt/bta_gattc_api.c | 104 ++++++++++++++ .../host/bluedroid/bta/gatt/bta_gattc_cache.c | 8 ++ .../host/bluedroid/bta/gatt/bta_gatts_api.c | 27 ++++ .../bta/gatt/include/bta_gattc_int.h | 1 + .../host/bluedroid/stack/gatt/att_protocol.c | 11 +- .../bt/host/bluedroid/stack/gatt/gatt_api.c | 82 ++++++++++- .../bt/host/bluedroid/stack/gatt/gatt_cl.c | 133 +++++++++++++++--- .../bt/host/bluedroid/stack/gatt/gatt_db.c | 69 ++++++++- .../bt/host/bluedroid/stack/gatt/gatt_main.c | 3 + .../bt/host/bluedroid/stack/gatt/gatt_sr.c | 132 ++++++++++++++++- .../bluedroid/stack/gatt/include/gatt_int.h | 3 + .../bluedroid/stack/include/stack/gatt_api.h | 53 ++++++- 13 files changed, 600 insertions(+), 35 deletions(-) diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index 78ac48d652..361955262b 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -126,6 +126,7 @@ static void bta_gattc_enable(tBTA_GATTC_CB *p_cb) if (p_cb->state == BTA_GATTC_STATE_DISABLED) { /* initialize control block */ memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB)); + bta_gattc_cb.auto_disc = true; p_cb->state = BTA_GATTC_STATE_ENABLED; } else { APPL_TRACE_DEBUG("GATTC is already enabled"); @@ -692,9 +693,11 @@ void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } else #endif { /* cache is building */ - p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; - /* cache load failure, start discovery */ - bta_gattc_start_discover(p_clcb, NULL); + if (bta_gattc_cb.auto_disc) { + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; + /* cache load failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } } } else { /* cache is building */ p_clcb->state = BTA_GATTC_DISCOVER_ST; diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c index f586db4c49..f5e17a977c 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c @@ -1103,4 +1103,108 @@ void BTA_GATTC_Broadcast(tBTA_GATTC_IF client_if, BOOLEAN start) return; } +/* Add For BLE PTS */ +uint8_t BTA_GATTC_AutoDiscoverEnable(uint8_t enable) +{ + APPL_TRACE_DEBUG("%s enable %d", __func__, enable); + + bta_gattc_cb.auto_disc = ((enable > 0) ? true : false); + GATTC_AutoDiscoverEnable(enable); + + return 0; +} + +typedef struct { + UINT16 len; + union { + UINT16 uuid16; + UINT32 uuid32; + UINT8 uuid128[LEN_UUID_128]; + } uuid; +} __attribute__((packed)) tAPP_UUID; + +uint8_t BTA_GATTC_Discover(uint8_t gatt_if, uint16_t conn_id, void *uuid, uint8_t disc_type, uint16_t s_handle, uint16_t e_handle) +{ + tGATT_STATUS status; + tGATT_DISC_PARAM param; + tAPP_UUID *app_uuid = (tAPP_UUID *)uuid; + + conn_id = (UINT16)((((UINT8)conn_id) << 8) | gatt_if); + memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); + + if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) { + param.s_handle = 1; + param.e_handle = 0xFFFF; + } else { + param.s_handle = s_handle; + param.e_handle = e_handle; + } + + if (app_uuid) { + param.service.len = app_uuid->len; + if (app_uuid->len == LEN_UUID_16) { + param.service.uu.uuid16 = app_uuid->uuid.uuid16; + } else if (app_uuid->len == LEN_UUID_32) { + param.service.uu.uuid32 = app_uuid->uuid.uuid32; + } else if (app_uuid->len == LEN_UUID_128) { + memcpy(param.service.uu.uuid128, app_uuid->uuid.uuid128, LEN_UUID_128); + } else { + APPL_TRACE_ERROR("%s invalid uuid len %u", __func__, app_uuid->len); + } + } + + status = GATTC_Discover (conn_id, disc_type, ¶m); + if (status != GATT_SUCCESS) { + APPL_TRACE_ERROR("%s status %x", __func__, status); + return -1; + } + + return 0; +} + +uint8_t BTA_GATTC_ReadLongChar(uint8_t gatt_if, uint16_t conn_id, uint16_t handle, uint16_t offset, uint8_t auth_req) +{ + tGATT_STATUS status; + tGATT_READ_PARAM read_param; + + conn_id = (UINT16)((((UINT8)conn_id) << 8) | gatt_if); + memset (&read_param, 0, sizeof(tGATT_READ_PARAM)); + read_param.partial.handle = handle; + read_param.partial.offset = offset; + read_param.partial.auth_req = auth_req; + + status = GATTC_Read(conn_id, GATT_READ_PARTIAL, &read_param); + if (status != GATT_SUCCESS) { + APPL_TRACE_ERROR("%s status %x", __func__, status); + return -1; + } + + return 0; +} + +uint8_t BTA_GATTC_ReadMultiVariableChar(uint8_t gatt_if, uint16_t conn_id, uint16_t num_handles, uint16_t *handles, uint8_t auth_req) +{ + tGATT_STATUS status; + tGATT_READ_PARAM read_param; + + if (num_handles > GATT_MAX_READ_MULTI_HANDLES) { + APPL_TRACE_ERROR("%s max read multi handlse %x", __func__, num_handles); + return -1; + } + + conn_id = (UINT16)((((UINT8)conn_id) << 8) | gatt_if); + memset (&read_param, 0, sizeof(tGATT_READ_PARAM)); + read_param.read_multiple.num_handles = num_handles; + memcpy(read_param.read_multiple.handles, handles, num_handles); + read_param.read_multiple.auth_req = auth_req; + + status = GATTC_Read(conn_id, GATT_READ_MULTIPLE_VAR, &read_param); + if (status != GATT_SUCCESS) { + APPL_TRACE_ERROR("%s status %x", __func__, status); + return -1; + } + + return 0; +} +/* End BLE PTS */ #endif /* defined(GATTC_INCLUDED) && (GATTC_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c index fb48cb9cfa..7af5e6beee 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c @@ -969,6 +969,10 @@ void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_ BOOLEAN pri_srvc; tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + if (bta_gattc_cb.auto_disc == FALSE) { + return; + } + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); if (p_srvc_cb != NULL && p_clcb != NULL && p_clcb->state == BTA_GATTC_DISCOVER_ST) { @@ -1042,6 +1046,10 @@ void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT tBTA_GATTC_SERV *p_srvc_cb; tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + if (bta_gattc_cb.auto_disc == FALSE) { + return; + } + if ( p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS) ) { if (status == GATT_SUCCESS) { p_clcb->status = status; diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c index cff4688cd4..03e584f12b 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c @@ -640,4 +640,31 @@ void BTA_GATTS_Listen(tBTA_GATTS_IF server_if, BOOLEAN start, BD_ADDR_PTR target return; } +uint8_t BTA_GATTS_SetServiceChangeMode(uint8_t mode) +{ + tGATT_STATUS status; + APPL_TRACE_DEBUG("%s mode %u", __func__, mode); + + status = GATTS_SetServiceChangeMode(mode); + if (status != GATT_SUCCESS) { + APPL_TRACE_ERROR("%s status %x", __func__, status); + return -1; + } + + return 0; +} + +uint8_t BTA_GATTS_SendMultiNotification(uint8_t gatt_if, uint16_t conn_id, void *tuples, uint16_t num_tuples) +{ + tGATT_STATUS status; + conn_id = (UINT16)((((UINT8)conn_id) << 8) | gatt_if); + + status = GATTS_HandleMultiValueNotification(conn_id, (tGATT_HLV *)tuples, num_tuples); + if (status != GATT_SUCCESS) { + APPL_TRACE_ERROR("%s status %x", __func__, status); + return -1; + } + + return 0; +} #endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/host/bluedroid/bta/gatt/include/bta_gattc_int.h b/components/bt/host/bluedroid/bta/gatt/include/bta_gattc_int.h index 874315028c..45caacf67b 100644 --- a/components/bt/host/bluedroid/bta/gatt/include/bta_gattc_int.h +++ b/components/bt/host/bluedroid/bta/gatt/include/bta_gattc_int.h @@ -394,6 +394,7 @@ enum { typedef struct { UINT8 state; + BOOLEAN auto_disc; /* internal use: true for auto discovering after connected */ tBTA_GATTC_CONN conn_track[BTA_GATTC_CONN_MAX]; tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX]; tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX]; diff --git a/components/bt/host/bluedroid/stack/gatt/att_protocol.c b/components/bt/host/bluedroid/stack/gatt/att_protocol.c index c6bb441105..310a9756ef 100644 --- a/components/bt/host/bluedroid/stack/gatt/att_protocol.c +++ b/components/bt/host/bluedroid/stack/gatt/att_protocol.c @@ -197,7 +197,7 @@ BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_ ** Returns None. ** *******************************************************************************/ -BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle) +BT_HDR *attp_build_read_multi_cmd(UINT8 op_code, UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle) { BT_HDR *p_buf = NULL; UINT8 *p, i = 0; @@ -208,7 +208,7 @@ BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 p_buf->offset = L2CAP_MIN_OFFSET; p_buf->len = 1; - UINT8_TO_STREAM (p, GATT_REQ_READ_MULTI); + UINT8_TO_STREAM (p, op_code); for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) { UINT16_TO_STREAM (p, *(p_handle + i)); @@ -304,7 +304,7 @@ BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle, UINT8_TO_STREAM (p, pair_len); p_buf->len += 1; } - if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) { + if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) { UINT16_TO_STREAM (p, handle); p_buf->len += 2; } @@ -391,6 +391,7 @@ BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg) case GATT_RSP_READ: case GATT_HANDLE_VALUE_NOTIF: case GATT_HANDLE_VALUE_IND: + case GATT_HANDLE_MULTI_VALUE_NOTIF: case GATT_RSP_ERROR: case GATT_RSP_MTU: /* Need to check the validation of parameter p_msg*/ @@ -417,6 +418,7 @@ BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg) case GATT_RSP_READ: case GATT_HANDLE_VALUE_NOTIF: case GATT_HANDLE_VALUE_IND: + case GATT_HANDLE_MULTI_VALUE_NOTIF: p_cmd = attp_build_value_cmd(p_tcb->payload_size, op_code, p_msg->attr_value.handle, @@ -613,7 +615,8 @@ tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, break; case GATT_REQ_READ_MULTI: - p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size, + case GATT_REQ_READ_MULTI_VAR: + p_cmd = attp_build_read_multi_cmd(op_code, p_tcb->payload_size, p_msg->read_multi.num_handles, p_msg->read_multi.handles); break; diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_api.c b/components/bt/host/bluedroid/stack/gatt/gatt_api.c index 6f1e5537d4..4c2917edd6 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_api.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_api.c @@ -413,7 +413,7 @@ BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_ osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf)); } else { gatt_update_for_database_change(); - if (GATTS_SEND_SERVICE_CHANGE_MODE == GATTS_SEND_SERVICE_CHANGE_AUTO) { + if (gatt_cb.srv_chg_mode == GATTS_SEND_SERVICE_CHANGE_AUTO) { gatt_proc_srv_chg(); } } @@ -526,7 +526,7 @@ tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle, &p_list->asgn_range.svc_uuid, p_list->asgn_range.svc_inst)) != NULL) { gatt_update_for_database_change(); - if (GATTS_SEND_SERVICE_CHANGE_MODE == GATTS_SEND_SERVICE_CHANGE_AUTO) { + if (gatt_cb.srv_chg_mode == GATTS_SEND_SERVICE_CHANGE_AUTO) { gatt_proc_srv_chg(); } /* remove the new service element after the srv changed processing is completed*/ @@ -996,6 +996,7 @@ tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID)); break; case GATT_READ_MULTIPLE: + case GATT_READ_MULTIPLE_VAR: p_clcb->s_handle = 0; /* copy multiple handles in CB */ p_read_multi = (tGATT_READ_MULTI *)osi_malloc(sizeof(tGATT_READ_MULTI)); @@ -1187,6 +1188,12 @@ tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle) return ret; } +tGATT_STATUS GATTC_AutoDiscoverEnable(UINT8 enable) +{ + gatt_cb.auto_disc = (enable > 0) ? TRUE : FALSE; + return GATT_SUCCESS; +} + #endif ///GATTC_INCLUDED == TRUE /*******************************************************************************/ @@ -1559,7 +1566,8 @@ tGATT_STATUS GATT_SendServiceChangeIndication (BD_ADDR bd_addr) tGATT_TCB *p_tcb; tBT_TRANSPORT transport; tGATT_STATUS status = GATT_NOT_FOUND; - if (GATTS_SEND_SERVICE_CHANGE_MODE == GATTS_SEND_SERVICE_CHANGE_AUTO) { + + if (gatt_cb.srv_chg_mode == GATTS_SEND_SERVICE_CHANGE_AUTO) { status = GATT_WRONG_STATE; GATT_TRACE_ERROR ("%s can't send service change indication manually, please configure the option through menuconfig", __func__); return status; @@ -1691,4 +1699,72 @@ BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr) return gatt_update_listen_mode(); } +tGATT_STATUS GATTS_SetServiceChangeMode(UINT8 mode) +{ + if (mode > GATTS_SEND_SERVICE_CHANGE_MANUAL) { + GATT_TRACE_ERROR("%s invalid service change mode %u", __func__, mode); + return GATT_VALUE_NOT_ALLOWED; + } + + gatt_cb.srv_chg_mode = mode; + return GATT_SUCCESS; +} + +tGATT_STATUS GATTS_HandleMultiValueNotification (UINT16 conn_id, tGATT_HLV *tuples, UINT16 num_tuples) +{ + tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; + BT_HDR *p_buf; + tGATT_VALUE notif; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + UINT8 *p = notif.value; + tGATT_HLV *p_hlv = tuples; + + GATT_TRACE_API ("GATTS_HandleMultiValueNotification"); + + if ( (p_reg == NULL) || (p_tcb == NULL)) { + GATT_TRACE_ERROR ("GATTS_HandleMultiValueNotification Unknown conn_id: %u \n", conn_id); + return (tGATT_STATUS) GATT_INVALID_CONN_ID; + } + + if (!gatt_check_connection_state_by_tcb(p_tcb)) { + GATT_TRACE_ERROR("connection not established\n"); + return GATT_WRONG_STATE; + } + + if (tuples == NULL) { + return GATT_ILLEGAL_PARAMETER; + } + + notif.len = 0; + + while (num_tuples) { + if (!GATT_HANDLE_IS_VALID (p_hlv->handle)) { + return GATT_ILLEGAL_PARAMETER; + } + + UINT16_TO_STREAM(p, p_hlv->handle); //handle + UINT16_TO_STREAM(p, p_hlv->length); //length + memcpy (p, p_hlv->value, p_hlv->length); //value + GATT_TRACE_DEBUG("%s handle %x, length %u", __func__, p_hlv->handle, p_hlv->length); + p += p_hlv->length; + notif.len += 4 + p_hlv->length; + num_tuples--; + p_hlv++; + } + + notif.auth_req = GATT_AUTH_REQ_NONE; + + p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_MULTI_VALUE_NOTIF, (tGATT_SR_MSG *)¬if); + if (p_buf != NULL) { + cmd_sent = attp_send_sr_msg (p_tcb, p_buf); + } else { + cmd_sent = GATT_NO_RESOURCES; + } + + return cmd_sent; +} + #endif diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c index ec046eadad..9fd0adf89a 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c @@ -53,6 +53,7 @@ static const UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] = { GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */ GATT_REQ_READ_BY_TYPE, /* GATT_DISC_INC_SRVC, */ GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR, */ + GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR_BY_UUID, */ GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */ }; @@ -65,6 +66,41 @@ static const UINT16 disc_type_to_uuid[GATT_DISC_MAX] = { 0 /* no type filtering for DISC_CHAR_DSCPT */ }; +// Use for GATTC discover infomation print +#define GATT_DISC_INFO(fmt, args...) {if (gatt_cb.auto_disc == FALSE) BT_PRINT_I("BT_GATT", fmt, ## args);} + +char *gatt_uuid_to_str(const tBT_UUID *uuid) +{ + static char dst[48] = {0}; + const uint8_t *u8p; + + memset(dst, 0, sizeof(dst)); + + switch (uuid->len) { + case LEN_UUID_16: + sprintf(dst, "0x%04x", uuid->uu.uuid16); + break; + case LEN_UUID_32: + sprintf(dst, "0x%08x", uuid->uu.uuid32); + break; + case LEN_UUID_128: + u8p = uuid->uu.uuid128; + + sprintf(dst, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + u8p[15], u8p[14], u8p[13], u8p[12], + u8p[11], u8p[10], u8p[9], u8p[8], + u8p[7], u8p[6], u8p[5], u8p[4], + u8p[3], u8p[2], u8p[1], u8p[0]); + break; + default: + dst[0] = '\0'; + break; + } + + return dst; +} + /******************************************************************************* ** @@ -107,6 +143,10 @@ void gatt_act_discovery(tGATT_CLCB *p_clcb) } } + if (p_clcb->op_subtype == GATT_DISC_CHAR_BY_UUID) { + memcpy(&cl_req.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID)); + } + st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req); if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) { @@ -181,6 +221,11 @@ void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset) memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI)); break; + case GATT_READ_MULTIPLE_VAR: + op_code = GATT_REQ_READ_MULTI_VAR; + memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI)); + break; + case GATT_READ_INC_SRV_UUID128: op_code = GATT_REQ_READ; msg.handle = p_clcb->s_handle; @@ -408,6 +453,7 @@ void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UIN while (len >= 4) { STREAM_TO_UINT16 (result.handle, p); STREAM_TO_UINT16 (result.value.group_value.e_handle, p); + GATT_DISC_INFO("%s handle %x, end handle %x", __func__, result.handle, result.value.group_value.e_handle); memcpy (&result.value.group_value.service_type, &p_clcb->uuid, sizeof(tBT_UUID)); len -= 4; @@ -474,6 +520,8 @@ void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_c len -= (uuid_len + 2); + GATT_DISC_INFO("%s handle %x, uuid %s", __func__, result.handle, gatt_uuid_to_str(&result.type)); + if (p_clcb->p_reg->app_cb.p_disc_res_cb) { (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result); } @@ -510,7 +558,7 @@ void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode case GATT_REQ_FIND_INFO: if (reason == GATT_NOT_FOUND) { status = GATT_SUCCESS; - GATT_TRACE_DEBUG("Discovery completed"); + GATT_DISC_INFO("Discovery completed"); } break; default: @@ -541,7 +589,7 @@ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, UNUSED(op_code); UNUSED(len); - GATT_TRACE_DEBUG("gatt_process_error_rsp "); + GATT_TRACE_DEBUG("%s", __func__); STREAM_TO_UINT8(opcode, p); STREAM_TO_UINT16(handle, p); STREAM_TO_UINT8(reason, p); @@ -634,7 +682,7 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 conn_id; tGATT_STATUS encrypt_status; UINT8 *p = p_data, i, - event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION; + event = (op_code == GATT_HANDLE_VALUE_IND) ? GATTC_OPTYPE_INDICATION: GATTC_OPTYPE_NOTIFICATION; GATT_TRACE_DEBUG("gatt_process_notification "); @@ -644,8 +692,6 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, } STREAM_TO_UINT16 (value.handle, p); - value.len = len - 2; - memcpy (value.value, p, value.len); if (!GATT_HANDLE_IS_VALID(value.handle)) { /* illegal handle, send ack now */ @@ -655,6 +701,28 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, return; } + if (op_code == GATT_HANDLE_MULTI_VALUE_NOTIF) { + if (len < GATT_NOTIFICATION_MIN_LEN + 2) { + GATT_TRACE_ERROR("illegal notification PDU length, discard"); + return; + } + + STREAM_TO_UINT16(value.len, p); + if (value.len > len - 4) { + return; + } + } else { + value.len = len - 2; + } + + if (value.len > GATT_MAX_ATTR_LEN) { + GATT_TRACE_ERROR("value length larger than GATT_MAX_ATTR_LEN, discard"); + return; + } + + memcpy(value.value, p, value.len); + p += value.len; + if (event == GATTC_OPTYPE_INDICATION) { if (p_tcb->ind_count) { /* this is an error case that receiving an indication but we @@ -665,19 +733,16 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count); } p_tcb->ind_count = 0; - } - /* should notify all registered client with the handle value notificaion/indication - Note: need to do the indication count and start timer first then do callback - */ - - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION)) { - p_tcb->ind_count++; + /* should notify all registered client with the handle value notificaion/indication + Note: need to do the indication count and start timer first then do callback + */ + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION)) { + p_tcb->ind_count++; + } } - } - if (event == GATTC_OPTYPE_INDICATION) { /* start a timer for app confirmation */ if (p_tcb->ind_count > 0) { gatt_start_ind_ack_timer(p_tcb); @@ -694,6 +759,33 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, } } + if (op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) { + return; + } + + if (len < (4 + value.len)) { + GATT_TRACE_ERROR("no remain data for multi notification"); + return; + } + + len -= (4 + value.len); + + while (len > 4) { + STREAM_TO_UINT16(value.handle, p); + STREAM_TO_UINT16(value.len, p); + len -= 4; + value.len = MIN(len, value.len); + memcpy(value.value, p, value.len); + p += value.len; + len -= value.len; + + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value); + } + } + } } /******************************************************************************* @@ -746,6 +838,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 while (len >= (handle_len + value_len)) { STREAM_TO_UINT16(handle, p); + GATT_DISC_INFO("%s op %x, handle %x", __func__, op_code, handle); if (!GATT_HANDLE_IS_VALID(handle)) { gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL); @@ -775,6 +868,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 break; } } + GATT_DISC_INFO("DISC ALL SVC end handle %x, uuid %s", record_value.group_value.e_handle, gatt_uuid_to_str(&record_value.group_value.service_type)); } /* discover included service */ else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC) { @@ -790,6 +884,8 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 if (value_len == 6) { STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p); record_value.incl_service.service_type.len = LEN_UUID_16; + GATT_DISC_INFO("DISC INC SVC start handle %x, end handle %x, uuid %s", + record_value.incl_service.s_handle, record_value.incl_service.e_handle, gatt_uuid_to_str(&record_value.incl_service.service_type)); } else if (value_len == 4) { p_clcb->s_handle = record_value.incl_service.s_handle; p_clcb->read_uuid128.wait_for_read_rsp = TRUE; @@ -797,7 +893,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result)); memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value)); p_clcb->op_subtype |= 0x90; - gatt_act_read(p_clcb, 0); + gatt_act_read(p_clcb, 0); // read 128-bit uuid of include service return; } else { GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len); @@ -937,6 +1033,9 @@ void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len); p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128; + tGATT_INCL_SRVC *inc_srvc = &p_clcb->read_uuid128.result.value.incl_service; + GATT_DISC_INFO("DISC INC SRVC start handle %x, end handle %x, uuid %s", + inc_srvc->s_handle, inc_srvc->e_handle, gatt_uuid_to_str(&inc_srvc->service_type)); if ( p_clcb->p_reg->app_cb.p_disc_res_cb) { (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result); } @@ -1133,6 +1232,7 @@ void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code, case GATT_RSP_READ: case GATT_RSP_READ_BLOB: case GATT_RSP_READ_MULTI: + case GATT_RSP_READ_MULTI_VAR: gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data); break; @@ -1154,6 +1254,7 @@ void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code, case GATT_HANDLE_VALUE_NOTIF: case GATT_HANDLE_VALUE_IND: + case GATT_HANDLE_MULTI_VALUE_NOTIF: gatt_process_notification(p_tcb, op_code, len, p_data); break; diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_db.c b/components/bt/host/bluedroid/stack/gatt/gatt_db.c index d18a0ccf3d..ed03d0453b 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_db.c @@ -35,6 +35,9 @@ #include "stack/l2c_api.h" #include "btm_int.h" +extern tGATT_STATUS gap_proc_read(tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp); +extern tGATT_STATUS gatt_proc_read(UINT16 conn_id, tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp); + /******************************************************************************** ** L O C A L F U N C T I O N P R O T O T Y P E S * *********************************************************************************/ @@ -764,6 +767,66 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, return GATT_SUCCESS; } +/******************************************************************************* +** +** Function gatts_get_attr_value_internal +** +** Description This function get the attribute value in gap service and gatt service +** +** Parameter attr_handle: the attribute handle +** length: the attribute value length +** value: the pointer to the data to be get to the attribute value in the database +** +** Returns Status of the operation. +** +*******************************************************************************/ +static tGATT_STATUS gatts_get_attr_value_internal(UINT16 attr_handle, UINT16 *length, UINT8 **value) +{ + UINT8 i; + tGATT_READ_REQ read_req; + tGATT_STATUS status = GATT_NOT_FOUND; + tGATT_SR_REG *p_rcb = gatt_cb.sr_reg; + UINT8 service_uuid[LEN_UUID_128] = {0}; + + // find the service by handle + for (i = 0; i < GATT_MAX_SR_PROFILES; i++, p_rcb++) { + if (p_rcb->in_use && p_rcb->s_hdl <= attr_handle && p_rcb->e_hdl >= attr_handle) { + break; + } + } + + // service cb not found + if (i == GATT_MAX_SR_PROFILES) { + return status; + } + + if (p_rcb->app_uuid.len != LEN_UUID_128) { + return status; + } + + memset(&read_req, 0, sizeof(tGATT_READ_REQ)); + read_req.handle = attr_handle; + + // read gatt service attribute value + memset(service_uuid, 0x81, LEN_UUID_128); + if (!memcmp(p_rcb->app_uuid.uu.uuid128, service_uuid, LEN_UUID_128)) { + status = gatt_proc_read(0, GATTS_REQ_TYPE_READ, &read_req, &gatt_cb.rsp); + } + + // read gap service attribute value + memset(service_uuid, 0x82, LEN_UUID_128); + if (!memcmp(p_rcb->app_uuid.uu.uuid128, service_uuid, LEN_UUID_128)) { + status = gap_proc_read(GATTS_REQ_TYPE_READ, &read_req, &gatt_cb.rsp); + } + + if (status == GATT_SUCCESS) { + *length = gatt_cb.rsp.attr_value.len; + *value = gatt_cb.rsp.attr_value.value; + } + + return status; +} + /******************************************************************************* ** ** Function gatts_get_attribute_value @@ -805,7 +868,11 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, return GATT_INVALID_PDU; } - p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; + if (gatts_get_attr_value_internal(attr_handle, length, value) == GATT_SUCCESS) { + return GATT_SUCCESS; + } + + p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; while (p_cur != NULL) { if (p_cur->handle == attr_handle) { diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_main.c b/components/bt/host/bluedroid/stack/gatt/gatt_main.c index 1a91639e2a..9f437f94c8 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_main.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_main.c @@ -103,6 +103,7 @@ void gatt_init (void) memset (&gatt_cb, 0, sizeof(tGATT_CB)); memset (&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG)); + gatt_cb.auto_disc = TRUE; gatt_cb.p_clcb_list = list_new(osi_free_func); gatt_cb.p_tcb_list = list_new(osi_free_func); #if defined(GATT_INITIAL_TRACE_LEVEL) @@ -114,6 +115,8 @@ void gatt_init (void) gatt_cb.sign_op_queue = fixed_queue_new(QUEUE_SIZE_MAX); gatt_cb.srv_chg_clt_q = fixed_queue_new(QUEUE_SIZE_MAX); gatt_cb.pending_new_srv_start_q = fixed_queue_new(QUEUE_SIZE_MAX); + gatt_cb.srv_chg_mode = GATTS_SEND_SERVICE_CHANGE_MODE; + /* First, register fixed L2CAP channel for ATT over BLE */ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE; fixed_reg.fixed_chnl_opts.max_transmit = 0xFF; diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c index 907b5c9aa4..1510f44871 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c @@ -277,6 +277,117 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, return (FALSE); } +static BOOLEAN process_read_multi_var_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, + tGATTS_RSP *p_msg, UINT16 mtu) +{ + UINT16 ii; + UINT16 total_len; + UINT16 len; + UINT8 *p; + + GATT_TRACE_DEBUG ("process_read_multi_var rsp status=%d mtu=%d", status, mtu); + + if (p_cmd->multi_rsp_q == NULL) { + p_cmd->multi_rsp_q = fixed_queue_new(QUEUE_SIZE_MAX); + } + + /* Enqueue the response */ + BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(tGATTS_RSP)); + if (p_buf == NULL) { + p_cmd->status = GATT_INSUF_RESOURCE; + return FALSE; + } + memcpy((void *)p_buf, (const void *)p_msg, sizeof(tGATTS_RSP)); + + fixed_queue_enqueue(p_cmd->multi_rsp_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); + + p_cmd->status = status; + if (status == GATT_SUCCESS) { + GATT_TRACE_DEBUG ("Multi var read count=%d num_hdls=%d", + fixed_queue_length(p_cmd->multi_rsp_q), + p_cmd->multi_req.num_handles); + /* Wait till we get all the responses */ + if (fixed_queue_length(p_cmd->multi_rsp_q) == p_cmd->multi_req.num_handles) { + len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu; + if ((p_buf = (BT_HDR *)osi_calloc(len)) == NULL) { + p_cmd->status = GATT_INSUF_RESOURCE; + return (TRUE); + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* First byte in the response is the opcode */ + *p++ = GATT_RSP_READ_MULTI_VAR; + p_buf->len = 1; + + /* Now walk through the buffers puting the data into the response in order */ + list_t *list = NULL; + const list_node_t *node = NULL; + if (! fixed_queue_is_empty(p_cmd->multi_rsp_q)) { + list = fixed_queue_get_list(p_cmd->multi_rsp_q); + } + for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) { + tGATTS_RSP *p_rsp = NULL; + if (list != NULL) { + if (ii == 0) { + node = list_begin(list); + } else { + node = list_next(node); + } + if (node != list_end(list)) { + p_rsp = (tGATTS_RSP *)list_node(node); + } + } + + if (p_rsp != NULL) { + + total_len = (p_buf->len + 2); // value length + + if (total_len > mtu) { + GATT_TRACE_DEBUG ("multi read variable overflow available len=%d val_len=%d", len, p_rsp->attr_value.len ); + break; + } + len = MIN(p_rsp->attr_value.len, (mtu - total_len)); // attribute value length + + if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) { + GATT_TRACE_DEBUG("%s handle %x len %u", __func__, p_rsp->attr_value.handle, p_rsp->attr_value.len); + UINT16_TO_STREAM(p, p_rsp->attr_value.len); + memcpy (p, p_rsp->attr_value.value, len); + p += len; + p_buf->len += (2+len); + } else { + p_cmd->status = GATT_NOT_FOUND; + break; + } + } else { + p_cmd->status = GATT_NOT_FOUND; + break; + } + + } /* loop through all handles*/ + + /* Sanity check on the buffer length */ + if (p_buf->len == 0) { + GATT_TRACE_ERROR("%s - nothing found!!", __func__); + p_cmd->status = GATT_NOT_FOUND; + osi_free (p_buf); + } else if (p_cmd->p_rsp_msg != NULL) { + osi_free (p_buf); + } else { + p_cmd->p_rsp_msg = p_buf; + } + + return (TRUE); + } + } else { /* any handle read exception occurs, return error */ + return (TRUE); + } + + /* If here, still waiting */ + return (FALSE); +} + /******************************************************************************* ** ** Function gatt_sr_process_app_rsp @@ -303,6 +414,10 @@ tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, if (!process_read_multi_rsp (&p_tcb->sr_cmd, status, p_msg, p_tcb->payload_size)) { return (GATT_SUCCESS); } + } else if (op_code == GATT_REQ_READ_MULTI_VAR) { + if (!process_read_multi_var_rsp(&p_tcb->sr_cmd, status, p_msg, p_tcb->payload_size)) { + return (GATT_SUCCESS); + } } else { if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS) { gatt_sr_update_prep_cnt(p_tcb, gatt_if, TRUE, FALSE); @@ -514,7 +629,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U sec_flag, key_size)) != GATT_SUCCESS) { - GATT_TRACE_DEBUG("read permission denied : 0x%02x", err); + GATT_TRACE_ERROR("read permission denied : 0x%02x", err); break; } } else { @@ -525,13 +640,15 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U ll -= 2; } - if (ll != 0) { - GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request."); - err = GATT_INVALID_HANDLE; - } + if (err == GATT_SUCCESS) { + if (ll != 0) { + GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request."); + err = GATT_INVALID_HANDLE; + } - if (p_tcb->sr_cmd.multi_req.num_handles == 0) { - err = GATT_INVALID_HANDLE; + if (p_tcb->sr_cmd.multi_req.num_handles == 0) { + err = GATT_INVALID_HANDLE; + } } if (err == GATT_SUCCESS) { @@ -1765,6 +1882,7 @@ void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code, break; case GATT_REQ_READ_MULTI: + case GATT_REQ_READ_MULTI_VAR: gatt_process_read_multi_req (p_tcb, op_code, len, p_data); break; diff --git a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h index 4583eda447..e31bbd0c5e 100644 --- a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h +++ b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h @@ -553,6 +553,9 @@ typedef struct { tGATT_HDL_CFG hdl_cfg; tGATT_BG_CONN_DEV bgconn_dev[GATT_MAX_BG_CONN_DEV]; + BOOLEAN auto_disc; /* internal use: true for auto discovering after connected */ + UINT8 srv_chg_mode; /* internal use: service change mode */ + tGATTS_RSP rsp; /* use to read internal service attribute */ } tGATT_CB; typedef struct{ diff --git a/components/bt/host/bluedroid/stack/include/stack/gatt_api.h b/components/bt/host/bluedroid/stack/include/stack/gatt_api.h index f8a3143c76..441bb12250 100644 --- a/components/bt/host/bluedroid/stack/include/stack/gatt_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/gatt_api.h @@ -110,8 +110,11 @@ typedef UINT8 tGATT_STATUS; #define GATT_HANDLE_VALUE_NOTIF 0x1B #define GATT_HANDLE_VALUE_IND 0x1D #define GATT_HANDLE_VALUE_CONF 0x1E +#define GATT_REQ_READ_MULTI_VAR 0x20 +#define GATT_RSP_READ_MULTI_VAR 0x21 +#define GATT_HANDLE_MULTI_VALUE_NOTIF 0x23 #define GATT_SIGN_CMD_WRITE 0xD2 /* changed in V4.0 1101-0010 (signed write) see write cmd above*/ -#define GATT_OP_CODE_MAX GATT_HANDLE_VALUE_CONF + 1 /* 0x1E = 30 + 1 = 31*/ +#define GATT_OP_CODE_MAX GATT_HANDLE_MULTI_VALUE_NOTIF + 1 /* 0x1E = 30 + 1 = 31*/ #define GATT_COMMAND_FLAG 0x40 /* Command Flag: set to one means command */ @@ -415,6 +418,7 @@ enum { GATT_DISC_SRVC_BY_UUID, /* discover service of a special type */ GATT_DISC_INC_SRVC, /* discover the included service within a service */ GATT_DISC_CHAR, /* discover characteristics of a service with/without type requirement */ + GATT_DISC_CHAR_BY_UUID, /* discover characteristic with type requirement */ GATT_DISC_CHAR_DSCPT, /* discover characteristic descriptors of a character */ GATT_DISC_MAX /* maximnun discover type */ }; @@ -434,6 +438,7 @@ enum { GATT_READ_BY_TYPE = 1, GATT_READ_BY_HANDLE, GATT_READ_MULTIPLE, + GATT_READ_MULTIPLE_VAR, GATT_READ_CHAR_VALUE, GATT_READ_PARTIAL, GATT_READ_MAX @@ -657,6 +662,12 @@ typedef struct { tGATTS_NV_SRV_CHG_CBACK *p_srv_chg_callback; } tGATT_APPL_INFO; +typedef struct { + UINT16 handle; + UINT16 length; + UINT8 *value; +} tGATT_HLV; + /* *********************** End Handle Management Definitions **********************/ @@ -1034,6 +1045,18 @@ extern tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute); *******************************************************************************/ extern tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle); +/******************************************************************************* +** +** Function GATTC_AutoDiscoverEnable +** +** Description This function is called to enable/disable auto discover. +** +** Parameters enable: 0 for disable, otherwise enable. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_AutoDiscoverEnable(UINT8 enable); /******************************************************************************* ** @@ -1228,6 +1251,34 @@ extern BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr extern void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable, tBT_TRANSPORT transport); +/******************************************************************************* +** +** Function GATTS_SetServiceChangeMode +** +** Description Configure service change indication mode +** +** Parameters mode: service change mode +** +** Returns Status. +** +*******************************************************************************/ +extern tGATT_STATUS GATTS_SetServiceChangeMode(UINT8 mode); + +/******************************************************************************* +** +** Function GATTS_HandleMultiValueNotification +** +** Description This function sends multiple handle value notification to a client. +** +** Parameter conn_id: connection identifier. +** tuples: Pointer to handle-length-value tuple list. +** num_tuples: Number of tuples. +** +** Returns GATT_SUCCESS if successfully sent; otherwise error code. +** +*******************************************************************************/ +extern tGATT_STATUS GATTS_HandleMultiValueNotification (UINT16 conn_id, tGATT_HLV *tuples, UINT16 num_tuples); + #ifdef __cplusplus }