mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
bluedroid: add internal GATT API for PTS
This commit is contained in:
parent
69b8b587c9
commit
0b76c3615e
@ -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,10 +693,12 @@ void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
|
||||
} else
|
||||
#endif
|
||||
{ /* cache is building */
|
||||
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;
|
||||
}
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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,6 +868,10 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
|
||||
return GATT_INVALID_PDU;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
|
@ -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,6 +640,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
ll -= 2;
|
||||
}
|
||||
|
||||
if (err == GATT_SUCCESS) {
|
||||
if (ll != 0) {
|
||||
GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request.");
|
||||
err = GATT_INVALID_HANDLE;
|
||||
@ -533,6 +649,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
if (p_tcb->sr_cmd.multi_req.num_handles == 0) {
|
||||
err = GATT_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == GATT_SUCCESS) {
|
||||
if ((trans_id = gatt_sr_enqueue_cmd (p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0])) != 0) {
|
||||
@ -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;
|
||||
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user