diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c index 8d504f6d7..7093723e8 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c @@ -916,6 +916,10 @@ void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) /* Dequeue the data, if it was enqueued */ if (p_clcb->p_q_cmd == p_data) { p_clcb->p_q_cmd = NULL; + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); } bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status, NULL); @@ -1012,7 +1016,6 @@ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_list) { /* release pending attribute list buffer */ - APPL_TRACE_DEBUG("+++++++++++++++++++++++++++++++++++++++++++++++++++++++= %p", p_clcb->p_srcb->p_srvc_list); osi_free(p_clcb->p_srcb->p_srvc_list); p_clcb->p_srcb->p_srvc_list = NULL; //osi_free_and_reset((void **)&p_clcb->p_srcb->p_srvc_list); @@ -1034,11 +1037,9 @@ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) * referenced by p_clcb->p_q_cmd */ if (p_q_cmd != p_clcb->p_q_cmd) { - APPL_TRACE_DEBUG("===================================================================="); osi_free(p_q_cmd); p_q_cmd = NULL; } - //osi_free_and_reset((void **)&p_q_cmd); } } /******************************************************************************* @@ -1067,6 +1068,10 @@ void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) /* Dequeue the data, if it was enqueued */ if (p_clcb->p_q_cmd == p_data) { p_clcb->p_q_cmd = NULL; + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); } bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL); @@ -1102,6 +1107,10 @@ void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) /* Dequeue the data, if it was enqueued */ if (p_clcb->p_q_cmd == p_data) { p_clcb->p_q_cmd = NULL; + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); } bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL); @@ -1142,6 +1151,10 @@ void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) /* Dequeue the data, if it was enqueued */ if (p_clcb->p_q_cmd == p_data) { p_clcb->p_q_cmd = NULL; + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); } bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_WRITE, status, NULL); @@ -1166,6 +1179,10 @@ void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) /* Dequeue the data, if it was enqueued */ if (p_clcb->p_q_cmd == p_data) { p_clcb->p_q_cmd = NULL; + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); } bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE, status, NULL); @@ -1232,9 +1249,12 @@ void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) event = p_clcb->p_q_cmd->api_read_multi.cmpl_evt; } cb_data.read.conn_id = p_clcb->bta_conn_id; - osi_free(p_clcb->p_q_cmd); - p_clcb->p_q_cmd = NULL; - //osi_free_and_reset((void **)&p_clcb->p_q_cmd); + //free the command data store in the queue. + bta_gattc_free_command_data(p_clcb); + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); /* read complete, callback */ ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); @@ -1265,9 +1285,12 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) } else { event = p_clcb->p_q_cmd->api_write.cmpl_evt; } - osi_free(p_clcb->p_q_cmd); - p_clcb->p_q_cmd = NULL; - //osi_free_and_reset((void **)&p_clcb->p_q_cmd); + //free the command data store in the queue. + bta_gattc_free_command_data(p_clcb); + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); cb_data.write.conn_id = p_clcb->bta_conn_id; /* write complete, callback */ ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); @@ -1285,9 +1308,12 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) { tBTA_GATTC cb_data; - osi_free(p_clcb->p_q_cmd); - p_clcb->p_q_cmd = NULL; - //osi_free_and_reset((void **)&p_clcb->p_q_cmd); + //free the command data store in the queue. + bta_gattc_free_command_data(p_clcb); + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); p_clcb->status = BTA_GATT_OK; /* execute complete, callback */ @@ -1310,10 +1336,12 @@ void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) { tBTA_GATTC cb_data; - osi_free(p_clcb->p_q_cmd); - p_clcb->p_q_cmd = NULL; - //osi_free_and_reset((void **)&p_clcb->p_q_cmd); - + //free the command data store in the queue. + bta_gattc_free_command_data(p_clcb); + /* Check if there has command pending in the command queue or not, + if there has command pending in the command queue, sent it to the state machine to decision + should be sent it to the remote device or not. */ + bta_gattc_pop_command_to_send(p_clcb); if (p_data->p_cmpl && p_data->status == BTA_GATT_OK) { p_clcb->p_srcb->mtu = p_data->p_cmpl->mtu; @@ -1456,10 +1484,62 @@ void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { bta_gattc_enqueue(p_clcb, p_data); } - +/******************************************************************************* +** +** Function bta_gattc_pop_command_to_send +** +** Description dequeue a command into control block. +** +** Returns None. +** +*******************************************************************************/ void bta_gattc_pop_command_to_send(tBTA_GATTC_CLCB *p_clcb) { - tBTA_GATTC_DATA *p_data = + if (!list_is_empty(p_clcb->p_cmd_list)) { + list_node_t *node = list_begin(p_clcb->p_cmd_list); + tBTA_GATTC_DATA *p_data = (tBTA_GATTC_DATA *)list_node(node); + if (p_data != NULL) { + /* execute pending operation of link block still present */ + if (l2cu_find_lcb_by_bd_addr(p_clcb->p_srcb->server_bda, BT_TRANSPORT_LE) != NULL) { + // The data to be sent to the gattc state machine for processing + if(bta_gattc_sm_execute(p_clcb, p_data->hdr.event, p_data)) { + list_remove(p_clcb->p_cmd_list, (void *)p_data); + } + } + } + } +} +/******************************************************************************* +** +** Function bta_gattc_free_command_data +** +** Description free the command data into control block. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_free_command_data(tBTA_GATTC_CLCB *p_clcb) +{ + //Check the list is empty or not. + if (!list_is_empty(p_clcb->p_cmd_list)) { + /* Traversal the command queue, check the p_q_cmd is point to the queue data or not, if the p_q_cmd point to the + command queue,should remove it from the list */ + for (list_node_t *node = list_begin(p_clcb->p_cmd_list); node != list_end(p_clcb->p_cmd_list); + node = list_next(node)) { + tBTA_GATTC_DATA *p_data = (tBTA_GATTC_DATA *)list_node(node); + if (p_data == p_clcb->p_q_cmd) { + list_remove(p_clcb->p_cmd_list, (void *)p_data); + p_clcb->p_q_cmd = NULL; + return; + } + } + + osi_free(p_clcb->p_q_cmd); + p_clcb->p_q_cmd = NULL; + } else { + osi_free(p_clcb->p_q_cmd); + p_clcb->p_q_cmd = NULL; + } } /******************************************************************************* diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c index 196acf049..a91d52329 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c @@ -306,6 +306,8 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) } osi_free(p_clcb->p_q_cmd); p_clcb->p_q_cmd = NULL; + // don't forget to clear the command queue before dealloc the clcb. + list_clear(p_clcb->p_cmd_list); //osi_free_and_reset((void **)&p_clcb->p_q_cmd); memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB)); } else { @@ -434,13 +436,29 @@ tBTA_GATTC_SERV *bta_gattc_srcb_alloc(BD_ADDR bda) BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { - if (p_clcb->p_q_cmd == NULL) - { + if (p_clcb->p_q_cmd == NULL) { p_clcb->p_q_cmd = p_data; return TRUE; - } else if (p_clcb->p_cmd_list) { - //store the command to the command list. - list_append(p_clcb->p_cmd_list, (void *)p_data); + } else if (p_data->hdr.event == BTA_GATTC_API_WRITE_EVT && + p_data->api_write.write_type == BTA_GATTC_WRITE_PREPARE && + p_data->api_write.handle == p_clcb->p_q_cmd->api_write.handle) { + APPL_TRACE_ERROR("There is a prepare write command still pending."); + tBTA_GATTC cb_data = {0}; + cb_data.write.status = BTA_GATT_CONGESTED; + cb_data.write.handle = p_data->api_write.handle; + cb_data.write.conn_id = p_clcb->bta_conn_id; + /* write complete, callback */ + ( *p_clcb->p_rcb->p_cback)(p_data->hdr.event, (tBTA_GATTC *)&cb_data); + return FALSE; + } + else if (p_clcb->p_cmd_list) { + void *cmd_data = osi_malloc(sizeof(tBTA_GATTC_DATA)); + if (cmd_data) { + memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA)); + memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA)); + //store the command to the command list. + list_append(p_clcb->p_cmd_list, cmd_data); + } return FALSE; } diff --git a/components/bt/bluedroid/bta/include/bta_gattc_int.h b/components/bt/bluedroid/bta/include/bta_gattc_int.h index 9903a0a05..48da7e116 100644 --- a/components/bt/bluedroid/bta/include/bta_gattc_int.h +++ b/components/bt/bluedroid/bta/include/bta_gattc_int.h @@ -425,6 +425,8 @@ extern void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_pop_command_to_send(tBTA_GATTC_CLCB *p_clcb); +extern void bta_gattc_free_command_data(tBTA_GATTC_CLCB *p_clcb); extern void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);