From 5fba60a8761b28adec2704dcbf69376ebde4f19b Mon Sep 17 00:00:00 2001 From: Zhihai Xu Date: Wed, 5 Feb 2014 20:04:48 -0800 Subject: [PATCH] resend discovery primary service ATT request with timeout This is to work around the problem with iphone. The iphone didn't respond with our first ATT request (read By group type Request for for primary service). the clockwork/phone host keep waiting for ATT response until disconnection from iphone due to timeout. The workaround is to resend discovery primary service before disconnection from remote device when response timeout happen. This workaround will be better for us to interop with remote BLE device. bug:12895830 Change-Id: I236af8eca9790f2dae7098061c74cec55348ca6d --- stack/gatt/att_protocol.c | 2 +- stack/gatt/gatt_api.c | 1 + stack/gatt/gatt_cl.c | 7 +++++-- stack/gatt/gatt_int.h | 7 +++++-- stack/gatt/gatt_utils.c | 44 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/stack/gatt/att_protocol.c b/stack/gatt/att_protocol.c index 9c715af6a..33485997c 100644 --- a/stack/gatt/att_protocol.c +++ b/stack/gatt/att_protocol.c @@ -495,7 +495,7 @@ UINT8 attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR /* do not enq cmd if handle value confirmation or set request */ if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) { - gatt_start_rsp_timer (p_tcb); + gatt_start_rsp_timer (clcb_idx); gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL); } } diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c index b53b7c5c8..232b191a9 100644 --- a/stack/gatt/gatt_api.c +++ b/stack/gatt/gatt_api.c @@ -1285,6 +1285,7 @@ void GATT_Deregister (tGATT_IF gatt_if) (p_clcb->p_reg->gatt_if == gatt_if) && (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) { + btu_stop_timer(&p_clcb->rsp_timer_ent); gatt_clcb_dealloc (p_clcb); break; } diff --git a/stack/gatt/gatt_cl.c b/stack/gatt/gatt_cl.c index b173be99e..7457dcb14 100644 --- a/stack/gatt/gatt_cl.c +++ b/stack/gatt/gatt_cl.c @@ -1096,7 +1096,7 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb) /* dequeue the request if is write command or sign write */ if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) { - gatt_start_rsp_timer (p_tcb); + gatt_start_rsp_timer (p_cmd->clcb_idx); } else { @@ -1153,7 +1153,10 @@ void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code, return; } else - btu_stop_timer (&p_tcb->rsp_timer_ent); + { + btu_stop_timer (&p_clcb->rsp_timer_ent); + p_clcb->retry_count = 0; + } } /* the size of the message may not be bigger than the local max PDU size*/ /* The message has to be smaller than the agreed MTU, len does not count op_code */ diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h index 48278c20e..1f81d6357 100644 --- a/stack/gatt/gatt_int.h +++ b/stack/gatt/gatt_int.h @@ -78,6 +78,8 @@ typedef UINT8 tGATT_SEC_ACTION; /* wait for ATT cmd response timeout value */ #define GATT_WAIT_FOR_RSP_TOUT 30 +#define GATT_WAIT_FOR_DISC_RSP_TOUT 5 +#define GATT_REQ_RETRY_LIMIT 2 /* characteristic descriptor type */ #define GATT_DESCR_EXT_DSCPTOR 1 /* Characteristic Extended Properties */ @@ -360,7 +362,6 @@ typedef struct UINT8 ind_count; tGATT_CMD_Q cl_cmd_q[GATT_CL_MAX_LCB]; - TIMER_LIST_ENT rsp_timer_ent; /* peer response timer */ TIMER_LIST_ENT ind_ack_timer_ent; /* local app confirm to indication timer */ UINT8 pending_cl_req; UINT8 next_slot_inq; /* index of next available slot in queue */ @@ -397,6 +398,8 @@ typedef struct BOOLEAN first_read_blob_after_read; tGATT_READ_INC_UUID128 read_uuid128; BOOLEAN in_use; + TIMER_LIST_ENT rsp_timer_ent; /* peer response timer */ + UINT8 retry_count; } tGATT_CLCB; typedef struct @@ -556,7 +559,7 @@ extern BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid, UINT16 len, UINT8 **p_ extern UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid); extern BOOLEAN gatt_uuid_compare(tBT_UUID src, tBT_UUID tar); extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, BOOLEAN le_conn, UINT8 *p_sec_flag, UINT8 *p_key_size); -extern void gatt_start_rsp_timer(tGATT_TCB *p_tcb); +extern void gatt_start_rsp_timer(UINT16 clcb_idx); extern void gatt_start_conf_timer(tGATT_TCB *p_tcb); extern void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle); extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle); diff --git a/stack/gatt/gatt_utils.c b/stack/gatt/gatt_utils.c index e15918c55..36f80a4d8 100644 --- a/stack/gatt/gatt_utils.c +++ b/stack/gatt/gatt_utils.c @@ -1116,11 +1116,18 @@ BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid_rec, UINT16 uuid_size, UINT8 * ** Returns TRUE if command sent, otherwise FALSE. ** *******************************************************************************/ -void gatt_start_rsp_timer(tGATT_TCB *p_tcb) +void gatt_start_rsp_timer(UINT16 clcb_idx) { - p_tcb->rsp_timer_ent.param = (TIMER_PARAM_TYPE)p_tcb; - btu_start_timer (&p_tcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP, - GATT_WAIT_FOR_RSP_TOUT); + tGATT_CLCB *p_clcb = &gatt_cb.clcb[clcb_idx]; + UINT32 timeout = GATT_WAIT_FOR_RSP_TOUT; + p_clcb->rsp_timer_ent.param = (TIMER_PARAM_TYPE)p_clcb; + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && + p_clcb->op_subtype == GATT_DISC_SRVC_ALL) + { + timeout = GATT_WAIT_FOR_DISC_RSP_TOUT; + } + btu_start_timer (&p_clcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP, + timeout); } /******************************************************************************* ** @@ -1165,8 +1172,32 @@ void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb) *******************************************************************************/ void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle) { + tGATT_CLCB *p_clcb = (tGATT_CLCB *)p_tle->param; + if (p_clcb == NULL || p_clcb->p_tcb == NULL) + { + GATT_TRACE_WARNING0("gatt_rsp_timeout clcb is already deleted"); + return; + } + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && + p_clcb->op_subtype == GATT_DISC_SRVC_ALL && + p_clcb->retry_count < GATT_REQ_RETRY_LIMIT) + { + UINT8 rsp_code; + GATT_TRACE_WARNING0("gatt_rsp_timeout retry discovery primary service"); + if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code)) + { + GATT_TRACE_ERROR0("gatt_rsp_timeout command queue out of sync, disconnect"); + } + else + { + p_clcb->retry_count++; + gatt_act_discovery(p_clcb); + return; + } + } + GATT_TRACE_WARNING0("gatt_rsp_timeout disconnecting..."); - gatt_disconnect (((tGATT_TCB *)p_tle->param)->peer_bda); + gatt_disconnect (p_clcb->p_tcb->peer_bda); } /******************************************************************************* @@ -2073,6 +2104,7 @@ void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data) operation = p_clcb->operation; conn_id = p_clcb->conn_id; + btu_stop_timer(&p_clcb->rsp_timer_ent); gatt_clcb_dealloc(p_clcb); @@ -2114,6 +2146,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason) p_clcb = &gatt_cb.clcb[i]; if (p_clcb->in_use && p_clcb->p_tcb == p_tcb) { + btu_stop_timer(&p_clcb->rsp_timer_ent); GATT_TRACE_DEBUG2 ("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id, p_clcb->clcb_idx); if (p_clcb->operation != GATTC_OPTYPE_NONE) gatt_end_operation(p_clcb, GATT_ERROR, NULL); @@ -2123,7 +2156,6 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason) } } - btu_stop_timer (&p_tcb->rsp_timer_ent); btu_stop_timer (&p_tcb->ind_ack_timer_ent); btu_stop_timer (&p_tcb->conf_timer_ent); gatt_free_pending_ind(p_tcb); -- 2.11.0