Merge branch 'bugfix/btdm_gattc_command_queue_fix' into 'master'

Bugfix/btdm gattc command queue fix

See merge request !1317
pull/1278/merge
Jiang Jiang Jian 2017-11-15 10:54:02 +08:00
commit ec9d93f4fc
6 zmienionych plików z 206 dodań i 22 usunięć

Wyświetl plik

@ -64,6 +64,7 @@ typedef enum {
ESP_GATTC_CONNECT_EVT = 40, /*!< When the ble physical connection is set up, the event comes */
ESP_GATTC_DISCONNECT_EVT = 41, /*!< When the ble physical connection disconnected, the event comes */
ESP_GATTC_READ_MUTIPLE_EVT = 42, /*!< When the ble characteristic or descriptor mutiple complete, the event comes */
ESP_GATTC_QUEUE_FULL_EVT = 43, /*!< When the gattc command queue full, the event comes */
} esp_gattc_cb_event_t;
@ -145,6 +146,7 @@ typedef union {
esp_gatt_status_t status; /*!< Operation status */
uint16_t conn_id; /*!< Connection id */
uint16_t handle; /*!< The Characteristic or descriptor handle */
uint16_t offset; /*!< The prepare write offset, this value is valid only when prepare write */
} write; /*!< Gatt client callback param of ESP_GATTC_WRITE_DESCR_EVT */
/**
@ -214,6 +216,15 @@ typedef union {
esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */
} disconnect; /*!< Gatt client callback param of ESP_GATTC_DISCONNECT_EVT */
/**
* @brief ESP_GATTC_QUEUE_FULL_EVT
*/
struct gattc_queue_full_evt_param {
esp_gatt_status_t status; /*!< Operation status */
uint16_t conn_id; /*!< Connection id */
bool is_full; /*!< The gattc command queue is full or not */
} queue_full; /*!< Gatt client callback param of ESP_GATTC_QUEUE_FULL_EVT */
} esp_ble_gattc_cb_param_t; /*!< GATT client callback parameter union type */
/**

Wyświetl plik

@ -59,6 +59,7 @@ static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS
static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op,
tBTA_GATT_STATUS status,
tGATT_CL_COMPLETE *p_data);
static void bta_gattc_pop_command_to_send(tBTA_GATTC_CLCB *p_clcb);
static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg);
static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda);
@ -916,6 +917,7 @@ 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;
bta_gattc_pop_command_to_send(p_clcb);
}
bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status, NULL);
@ -1012,7 +1014,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 +1035,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 +1066,7 @@ 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;
bta_gattc_pop_command_to_send(p_clcb);
}
bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL);
@ -1102,6 +1102,7 @@ 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;
bta_gattc_pop_command_to_send(p_clcb);
}
bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL);
@ -1142,6 +1143,7 @@ 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;
bta_gattc_pop_command_to_send(p_clcb);
}
bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_WRITE, status, NULL);
@ -1166,6 +1168,7 @@ 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;
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 +1235,9 @@ 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);
bta_gattc_pop_command_to_send(p_clcb);
/* read complete, callback */
( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data);
@ -1265,9 +1268,9 @@ 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);
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 +1288,9 @@ 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);
bta_gattc_pop_command_to_send(p_clcb);
p_clcb->status = BTA_GATT_OK;
/* execute complete, callback */
@ -1310,10 +1313,9 @@ 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);
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,6 +1458,78 @@ 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.
** 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.
**
** Returns None.
**
*******************************************************************************/
static void bta_gattc_pop_command_to_send(tBTA_GATTC_CLCB *p_clcb)
{
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);
}
if (p_clcb->is_full) {
tBTA_GATTC cb_data = {0};
p_clcb->is_full = FALSE;
cb_data.status = GATT_SUCCESS;
cb_data.queue_full.conn_id = p_clcb->bta_conn_id;
cb_data.queue_full.is_full = FALSE;
if (p_clcb->p_rcb->p_cback != NULL) {
( *p_clcb->p_rcb->p_cback)(BTA_GATTC_QUEUE_FULL_EVT, (tBTA_GATTC *)&cb_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)
{
assert(p_clcb->p_cmd_list);
//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;
}
}
/*******************************************************************************
**

Wyświetl plik

@ -48,6 +48,8 @@ static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x0
static const BD_ADDR dummy_bda = {0, 0, 0, 0, 0, 0};
#define GATTC_COMMAND_QUEUE_SIZE_MAX 30
/*******************************************************************************
**
** Function bta_gatt_convert_uuid16_to_uuid128
@ -230,6 +232,7 @@ tBTA_GATTC_CLCB *bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bd
bdcpy(p_clcb->bda, remote_bda);
p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if);
p_clcb->p_cmd_list = list_new(osi_free_func);
if ((p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) {
p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda);
@ -305,6 +308,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 {
@ -421,6 +426,24 @@ tBTA_GATTC_SERV *bta_gattc_srcb_alloc(BD_ADDR bda)
}
return p_tcb;
}
static BOOLEAN bta_gattc_has_prepare_command_in_queue(tBTA_GATTC_CLCB *p_clcb)
{
assert(p_clcb != NULL);
for(list_node_t *sn = list_begin(p_clcb->p_cmd_list);
sn != list_end(p_clcb->p_cmd_list); sn = list_next(sn)) {
tBTA_GATTC_DATA *cmd_data = (tBTA_GATTC_DATA *)list_node(sn);
if (cmd_data != NULL && ((cmd_data->hdr.event == BTA_GATTC_API_WRITE_EVT &&
cmd_data->api_write.write_type == BTA_GATTC_WRITE_PREPARE) ||
cmd_data->hdr.event == BTA_GATTC_API_EXEC_EVT)) {
return TRUE;
}
}
return FALSE;
}
/*******************************************************************************
**
** Function bta_gattc_enqueue
@ -432,15 +455,70 @@ tBTA_GATTC_SERV *bta_gattc_srcb_alloc(BD_ADDR bda)
*******************************************************************************/
BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data = {0};
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_data->hdr.event == BTA_GATTC_API_WRITE_EVT &&
p_data->api_write.write_type == BTA_GATTC_WRITE_PREPARE) &&
((p_clcb->p_q_cmd->hdr.event == BTA_GATTC_API_WRITE_EVT &&
p_clcb->p_q_cmd->api_write.write_type == BTA_GATTC_WRITE_PREPARE) ||
bta_gattc_has_prepare_command_in_queue(p_clcb))) {
APPL_TRACE_DEBUG("%s(), prepare offset = %d", __func__, p_data->api_write.offset);
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;
cb_data.write.offset = p_data->api_write.offset;
/* write complete, callback */
if (p_clcb->p_rcb->p_cback != NULL) {
( *p_clcb->p_rcb->p_cback)(BTA_GATTC_PREP_WRITE_EVT, (tBTA_GATTC *)&cb_data);
}
return FALSE;
}
else if (p_clcb->p_cmd_list) {
UINT16 len = 0;
tBTA_GATTC_DATA *cmd_data = NULL;
if (list_length(p_clcb->p_cmd_list) >= GATTC_COMMAND_QUEUE_SIZE_MAX) {
APPL_TRACE_ERROR("%s(), the gattc command queue is full.", __func__);
cb_data.status = GATT_BUSY;
cb_data.queue_full.conn_id = p_clcb->bta_conn_id;
cb_data.queue_full.is_full = TRUE;
p_clcb->is_full = TRUE;
if (p_clcb->p_rcb->p_cback != NULL) {
( *p_clcb->p_rcb->p_cback)(BTA_GATTC_QUEUE_FULL_EVT, (tBTA_GATTC *)&cb_data);
}
return FALSE;
}
if (p_data->hdr.event == BTA_GATTC_API_WRITE_EVT) {
len = p_data->api_write.len;
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA) + len)) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA) + len);
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA));
cmd_data->api_write.p_value = (UINT8 *)(cmd_data + 1);
memcpy(cmd_data->api_write.p_value, p_data->api_write.p_value, len);
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memery.", __func__, __LINE__);
return FALSE;
}
} else {
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA))) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA));
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memery.", __func__, __LINE__);
return FALSE;
}
}
//store the command to the command list.
list_append(p_clcb->p_cmd_list, (void *)cmd_data);
return FALSE;
}
APPL_TRACE_ERROR ("%s: already has a pending command!!", __func__);
/* skip the callback now. ----- need to send callback ? */
return FALSE;
}

Wyświetl plik

@ -182,6 +182,7 @@ typedef UINT8 tBTA_GATT_STATUS;
#define BTA_GATTC_CONNECT_EVT 35 /* GATTC CONNECT event */
#define BTA_GATTC_DISCONNECT_EVT 36 /* GATTC DISCONNECT event */
#define BTA_GATTC_READ_MUTIPLE_EVT 37 /* GATTC Read mutiple event */
#define BTA_GATTC_QUEUE_FULL_EVT 38 /* GATTC queue full event */
typedef UINT8 tBTA_GATTC_EVT;
@ -298,6 +299,7 @@ typedef struct {
UINT16 conn_id;
tBTA_GATT_STATUS status;
UINT16 handle;
UINT16 offset;
}tBTA_GATTC_WRITE;
typedef struct {
@ -354,6 +356,12 @@ typedef struct {
BOOLEAN congested; /* congestion indicator */
} tBTA_GATTC_CONGEST;
typedef struct {
tBTA_GATT_STATUS status;
UINT16 conn_id;
BOOLEAN is_full;
} tBTA_GATTC_QUEUE_FULL;
typedef struct {
tBTA_GATT_STATUS status;
tBTA_GATTC_IF client_if;
@ -399,6 +407,7 @@ typedef union {
BD_ADDR remote_bda; /* service change event */
tBTA_GATTC_CFG_MTU cfg_mtu; /* configure MTU operation */
tBTA_GATTC_CONGEST congest;
tBTA_GATTC_QUEUE_FULL queue_full;
} tBTA_GATTC;
/* GATTC enable callback function */

Wyświetl plik

@ -310,7 +310,8 @@ typedef struct {
tBTA_GATTC_RCB *p_rcb; /* pointer to the registration CB */
tBTA_GATTC_SERV *p_srcb; /* server cache CB */
tBTA_GATTC_DATA *p_q_cmd; /* command in queue waiting for execution */
list_t *p_cmd_list; /* The list to store the command to be sent */
BOOLEAN is_full; /* The gattc command queue is full or not */
#define BTA_GATTC_NO_SCHEDULE 0
#define BTA_GATTC_DISC_WAITING 0x01
#define BTA_GATTC_REQ_WAITING 0x10
@ -425,6 +426,7 @@ 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_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);

Wyświetl plik

@ -253,7 +253,7 @@ static void btc_gattc_fill_gatt_db_conversion(uint16_t count, uint16_t num, esp_
}
case ESP_GATT_DB_DESCRIPTOR: {
esp_gattc_descr_elem_t *descr_result = (esp_gattc_descr_elem_t *)result;
for (int i = 0; i < (num - offset); i++) {
for (int i = 0; i < db_size; i++) {
descr_result->handle = db[offset + i].attribute_handle;
btc128_to_bta_uuid(&bta_uuid, db[offset + i].uuid.uu);
bta_to_btc_uuid(&descr_result->uuid, &bta_uuid);
@ -770,6 +770,7 @@ void btc_gattc_cb_handler(btc_msg_t *msg)
param.write.conn_id = BTC_GATT_GET_CONN_ID(write->conn_id);
param.write.status = write->status;
param.write.handle = write->handle;
param.write.offset = write->offset;
btc_gattc_cb_to_app(ret_evt, gattc_if, &param);
break;
}
@ -917,6 +918,15 @@ void btc_gattc_cb_handler(btc_msg_t *msg)
btc_gattc_cb_to_app(ESP_GATTC_SRVC_CHG_EVT, ESP_GATT_IF_NONE, &param);
break;
}
case BTA_GATTC_QUEUE_FULL_EVT: {
tBTA_GATTC_QUEUE_FULL *queue_full = &arg->queue_full;
gattc_if = BTC_GATT_GET_GATT_IF(queue_full->conn_id);
param.queue_full.conn_id = BTC_GATT_GET_CONN_ID(queue_full->conn_id);
param.queue_full.status = arg->status;
param.queue_full.is_full = queue_full->is_full;
btc_gattc_cb_to_app(ESP_GATTC_QUEUE_FULL_EVT, gattc_if, &param);
break;
}
default:
LOG_DEBUG("%s: Unhandled event (%d)!", __FUNCTION__, msg->act);
break;