一、应用层传下来的消息到GATT层:
a) 死循环等待蓝牙开启:event = GKI_wait (0xFFFF, 0); 直到出现BT_EVT_PRELOAD_CMPL
b) btu_init_core()
c) BTE_InitStack();bta_sys_init();BTE_InitTraceLevels();
d) GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);通知启动事件
e) 等待消息的来临后处理
f) bta_sys_event(p_msg); //处理上层传来的消息
//external\bluetooth\bluedroid\stack\btu\btu_task.c
BTU_API UINT32 btu_task (UINT32 param)
{
UINT16 event;
BT_HDR *p_msg;
UINT8 i;
UINT16 mask;
BOOLEAN handled;
UNUSED(param);
#if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
/* wait an event that HCISU is ready */
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
"btu_task pending for preload complete event");
for (;;)
{
event = GKI_wait (0xFFFF, 0);
if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
{
/* indicates BT ENABLE abort */
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
"btu_task start abort!");
return (0);
}
else if (event & BT_EVT_PRELOAD_CMPL)
{
break;
}
else
{
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
"btu_task ignore evt %04x while pending for preload complete",
event);
}
}
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
"btu_task received preload complete event");
#endif
/* Initialize the mandatory core stack control blocks
(BTU, BTM, L2CAP, and SDP)
*/
btu_init_core();
/* Initialize any optional stack components */
BTE_InitStack();
#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
bta_sys_init();
#endif
/* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
* reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
*/
#if ( BT_USE_TRACES==TRUE )
BTE_InitTraceLevels();
#endif
/* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);
prctl(PR_SET_NAME, (unsigned long)"BTU TASK", 0, 0, 0);
raise_priority_a2dp(TASK_HIGH_BTU);
/* Wait for, and process, events */
for (;;)
{
event = GKI_wait (0xFFFF, 0);
if (event & TASK_MBOX_0_EVT_MASK)
{
/* Process all messages in the queue */
while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
{
/* Determine the input message type. */
switch (p_msg->event & BT_EVT_MASK)
{
case BT_EVT_TO_BTU_HCI_ACL:
/* All Acl Data goes to L2CAP */
l2c_rcv_acl_data (p_msg);
break;
case BT_EVT_TO_BTU_L2C_SEG_XMIT:
/* L2CAP segment transmit complete */
l2c_link_segments_xmitted (p_msg);
break;
case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
btm_route_sco_data (p_msg);
break;
#endif
case BT_EVT_TO_BTU_HCI_EVT:
btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
GKI_freebuf(p_msg);
#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
/* If host receives events which it doesn't response to, */
/* host should start idle timer to enter sleep mode. */
btu_check_bt_sleep ();
#endif
break;
case BT_EVT_TO_BTU_HCI_CMD:
btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
break;
#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
case BT_EVT_TO_OBX_SR_MSG:
obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_OBX_SR_L2C_MSG:
obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
#endif
#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
case BT_EVT_TO_OBX_CL_MSG:
obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_OBX_CL_L2C_MSG:
obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
GKI_freebuf (p_msg);
break;
#endif
#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
case BT_EVT_TO_BIP_CMDS :
bip_proc_btu_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif /* BIP */
#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
case BT_EVT_TO_BPP_PR_CMDS:
bpp_pr_proc_event(p_msg);
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_BPP_SND_CMDS:
bpp_snd_proc_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif /* BPP */
#endif /* OBX */
#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
case BT_EVT_TO_BTU_SAP :
sap_proc_btu_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif /* SAP */
#if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE)
case BT_EVT_TO_GAP_MSG :
gap_proc_btu_event(p_msg);
GKI_freebuf (p_msg);
break;
#endif
case BT_EVT_TO_START_TIMER :
/* Start free running 1 second timer for list management */
GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_STOP_TIMER:
if (GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
GKI_stop_timer(TIMER_0);
}
GKI_freebuf (p_msg);
break;
case BT_EVT_TO_START_TIMER_ONESHOT:
if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
// Start non-repeating timer.
GKI_start_timer(TIMER_3, tle->ticks, FALSE);
} else {
BTM_TRACE_WARNING("Oneshot timer queue empty when received start request");
}
GKI_freebuf(p_msg);
break;
case BT_EVT_TO_STOP_TIMER_ONESHOT:
if (GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
GKI_stop_timer(TIMER_3);
} else {
BTM_TRACE_WARNING("Oneshot timer queue not empty when received stop request");
}
GKI_freebuf (p_msg);
break;
#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
case BT_EVT_TO_START_QUICK_TIMER :
GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE);
GKI_freebuf (p_msg);
break;
#endif
default:
i = 0;
mask = (UINT16) (p_msg->event & BT_EVT_MASK);
handled = FALSE;
for (; !handled && i < BTU_MAX_REG_EVENT; i++)
{
if (btu_cb.event_reg[i].event_cb == NULL)
continue;
if (mask == btu_cb.event_reg[i].event_range)
{
if (btu_cb.event_reg[i].event_cb)
{
btu_cb.event_reg[i].event_cb(p_msg);
handled = TRUE;
}
}
}
if (handled == FALSE)
GKI_freebuf (p_msg);
break;
}
}
}
if (event & TIMER_0_EVT_MASK) {
GKI_update_timer_list (&btu_cb.timer_queue, 1);
while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue);
if (p_tle->ticks != 0)
break;
GKI_remove_from_timer_list(&btu_cb.timer_queue, p_tle);
switch (p_tle->event) {
case BTU_TTYPE_BTM_DEV_CTL:
btm_dev_timeout(p_tle);
break;
case BTU_TTYPE_BTM_ACL:
btm_acl_timeout(p_tle);
break;
case BTU_TTYPE_L2CAP_LINK:
case BTU_TTYPE_L2CAP_CHNL:
case BTU_TTYPE_L2CAP_HOLD:
case BTU_TTYPE_L2CAP_INFO:
case BTU_TTYPE_L2CAP_FCR_ACK:
l2c_process_timeout (p_tle);
break;
case BTU_TTYPE_SDP:
sdp_conn_timeout ((tCONN_CB *)p_tle->param);
break;
case BTU_TTYPE_BTM_RMT_NAME:
btm_inq_rmt_name_failed();
break;
#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
case BTU_TTYPE_RFCOMM_MFC:
case BTU_TTYPE_RFCOMM_PORT:
rfcomm_process_timeout (p_tle);
break;
#endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */
#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE))
case BTU_TTYPE_BNEP:
bnep_process_timeout(p_tle);
break;
#endif
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
case BTU_TTYPE_AVDT_CCB_RET:
case BTU_TTYPE_AVDT_CCB_RSP:
case BTU_TTYPE_AVDT_CCB_IDLE:
case BTU_TTYPE_AVDT_SCB_TC:
avdt_process_timeout(p_tle);
break;
#endif
#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
case BTU_TTYPE_OBX_CLIENT_TO:
obx_cl_timeout(p_tle);
break;
#endif
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
case BTU_TTYPE_OBX_SERVER_TO:
obx_sr_timeout(p_tle);
break;
case BTU_TTYPE_OBX_SVR_SESS_TO:
obx_sr_sess_timeout(p_tle);
break;
#endif
#endif
#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
case BTU_TTYPE_SAP_TO:
sap_process_timeout(p_tle);
break;
#endif
case BTU_TTYPE_BTU_CMD_CMPL:
btu_hcif_cmd_timeout((UINT8)(p_tle->event - BTU_TTYPE_BTU_CMD_CMPL));
break;
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
case BTU_TTYPE_HID_HOST_REPAGE_TO :
hidh_proc_repage_timeout(p_tle);
break;
#endif
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_INQUIRY:
case BTU_TTYPE_BLE_GAP_LIM_DISC:
case BTU_TTYPE_BLE_GAP_FAST_ADV:
case BTU_TTYPE_BLE_OBSERVE:
btm_ble_timeout(p_tle);
break;
case BTU_TTYPE_ATT_WAIT_FOR_RSP:
gatt_rsp_timeout(p_tle);
break;
case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK:
gatt_ind_ack_timeout(p_tle);
break;
#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
case BTU_TTYPE_SMP_PAIRING_CMD:
smp_rsp_timeout(p_tle);
break;
#endif
#endif
#if (MCA_INCLUDED == TRUE)
case BTU_TTYPE_MCA_CCB_RSP:
mca_process_timeout(p_tle);
break;
#endif
case BTU_TTYPE_USER_FUNC:
{
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
(*p_uf)(p_tle);
}
break;
default:
i = 0;
handled = FALSE;
for (; !handled && i < BTU_MAX_REG_TIMER; i++)
{
if (btu_cb.timer_reg[i].timer_cb == NULL)
continue;
if (btu_cb.timer_reg[i].p_tle == p_tle)
{
btu_cb.timer_reg[i].timer_cb(p_tle);
handled = TRUE;
}
}
break;
}
}
/* if timer list is empty stop periodic GKI timer */
if (btu_cb.timer_queue.p_first == NULL)
{
GKI_stop_timer(TIMER_0);
}
}
#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
if (event & TIMER_2_EVT_MASK)
{
btu_process_quick_timer_evt();
}
#endif
#if (RPC_INCLUDED == TRUE)
/* if RPC message queue event */
if (event & RPCGEN_MSG_EVT)
{
if ((p_msg = (BT_HDR *) GKI_read_mbox(RPCGEN_MSG_MBOX)) != NULL)
RPCT_RpcgenMsg(p_msg); /* handle RPC message queue */
}
#endif
#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
if (event & TASK_MBOX_2_EVT_MASK)
{
while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
{
bta_sys_event(p_msg); //处理上层传来的消息
}
}
if (event & TIMER_1_EVT_MASK)
{
bta_sys_timer_update();
}
#endif
if (event & TIMER_3_EVT_MASK) {
BTM_TRACE_API("Received oneshot timer event complete");
if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
INT32 ticks_since_last_update = GKI_timer_ticks_getinitial(GKI_timer_getfirst(&btu_cb.timer_queue_oneshot));
GKI_update_timer_list(&btu_cb.timer_queue_oneshot, ticks_since_last_update);
}
while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
if (p_tle->ticks != 0)
break;
GKI_remove_from_timer_list(&btu_cb.timer_queue_oneshot, p_tle);
switch (p_tle->event) {
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_RANDOM_ADDR:
btm_ble_timeout(p_tle);
break;
#endif
case BTU_TTYPE_USER_FUNC:
{
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
(*p_uf)(p_tle);
}
break;
default:
// FAIL
BTM_TRACE_WARNING("Received unexpected oneshot timer event:0x%x\n",
p_tle->event);
break;
}
}
/* Update GKI timer with new tick value from first timer. */
if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
if (p_tle->ticks > 0)
GKI_start_timer(TIMER_3, p_tle->ticks, FALSE);
} else {
GKI_stop_timer(TIMER_3);
}
}
if (event & EVENT_MASK(APPL_EVT_7))
break;
}
return(0);
}
二、应用层注册的回调函数被调用bta_sys_event:
注意这里有一堆的回调函数:(*bta_sys_cb.reg[id]->evt_hdlr), 不同的id仅处理各自id的消息回调
BTA_API void bta_sys_event(BT_HDR *p_msg)
{
UINT8 id;
BOOLEAN freebuf = TRUE;
APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event); //event = BTA_HH_API_WRITE_DEV_EVT
/* get subsystem id from event */
id = (UINT8) (p_msg->event >> 8);
/* verify id and call subsystem event handler */
if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
{
freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); //Id为0x17,即BTA_ID_HH,回调函数为bta_hh_hdl_event,前面已分析
//Id为0x1f,即为BTA_ID_GATTC,回调函数为bta_gattc_hdl_event,继续往后看
}
else
{
APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
}
if (freebuf)
{
GKI_freebuf(p_msg);
}
}
三、GATT回调函数处理
最后调用的事件处理:rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg);
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
tBTA_GATTC_CLCB *p_clcb = NULL;
tBTA_GATTC_RCB *p_clreg;
BOOLEAN rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event));
#endif
switch (p_msg->event)
{
case BTA_GATTC_API_DISABLE_EVT:
bta_gattc_disable(p_cb);
break;
case BTA_GATTC_API_REG_EVT:
bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_INT_START_IF_EVT:
bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_DEREG_EVT:
p_clreg = bta_gattc_cl_get_regcb(((tBTA_GATTC_DATA *)p_msg)->api_dereg.client_if);
bta_gattc_deregister(p_cb, p_clreg);
break;
case BTA_GATTC_API_OPEN_EVT:
bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_CANCEL_OPEN_EVT:
bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_REFRESH_EVT:
bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
#if BLE_INCLUDED == TRUE
case BTA_GATTC_API_LISTEN_EVT:
bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
case BTA_GATTC_API_BROADCAST_EVT:
bta_gattc_broadcast(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
#endif
case BTA_GATTC_ENC_CMPL_EVT:
bta_gattc_process_enc_cmpl(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
default:
if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA *) p_msg);
else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA *) p_msg);
else
p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
if (p_clcb != NULL)
{
rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); //事件处理
}
else
{
APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
}
break;
}
return rt;
}
3.1、gatt client事件处理状态机
根据gatt的状态机处理对应的事件:(*bta_gattc_action[action])(p_clcb, p_data);
处理事件最终执行的就是 bta_gattc_write
BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC_ST_TBL state_table;
UINT8 action;
int i;
BOOLEAN rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
tBTA_GATTC_STATE in_state = p_clcb->state;
UINT16 in_event = event;
APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
gattc_state_code(in_state),
in_event,
gattc_evt_code(in_event));
#endif
/* look up the state table for the current state */
state_table = bta_gattc_st_tbl[p_clcb->state];
event &= 0x00FF;
/* set next state */
p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
/* execute action functions */
for (i = 0; i < BTA_GATTC_ACTIONS; i++)
{
if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
{
(*bta_gattc_action[action])(p_clcb, p_data); //执行bta_gattc_write,
if (p_clcb->p_q_cmd == p_data) {
/* buffer is queued, don't free in the bta dispatcher.
* we free it ourselves when a completion event is received.
*/
rt = FALSE;
}
}
else
{
break;
}
}
#if BTA_GATT_DEBUG == TRUE
if (in_state != p_clcb->state)
{
APPL_TRACE_DEBUG("GATTC [%d] State Change: [%s] -> [%s] after Event [%s]",p_clcb->bta_conn_id,
gattc_state_code(in_state),
gattc_state_code(p_clcb->state),
gattc_evt_code(in_event));
}
#endif
return rt;
}
3.2、事件处理函数bta_gattc_write
真正写函数:status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
UINT16 handle = 0;
tGATT_VALUE attr = {0};
tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATT_STATUS status = BTA_GATT_OK;
if (bta_gattc_enqueue(p_clcb, p_data))
{
if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
&p_data->api_write.srvc_id,
&p_data->api_write.char_id,
p_data->api_write.p_descr_type)) == 0)
{
status = BTA_GATT_ERROR;
}
else
{
attr.handle= handle;
attr.offset = p_data->api_write.offset;
attr.len = p_data->api_write.len;
attr.auth_req = p_data->api_write.auth_req;
if (p_data->api_write.p_value)
memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
}
/* write fail */
if (status != BTA_GATT_OK)
{
memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
op_cmpl.status = status;
op_cmpl.op_code = GATTC_OPTYPE_WRITE;
op_cmpl.p_cmpl = NULL;
bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
}
}
}
3.3、写函数GATTC_Write
- 会调用安全性检查函数gatt_security_check_start
- 写函数会依次调用:gatt_send_write_msg、attp_send_cl_msg 、attp_build_value_cmd、- attp_cl_send_cmd、attp_send_msg_to_l2cap、L2CA_SendFixedChnlData
- l2c_enqueue_peer_data :让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。
- l2cu_check_channel_congestion: 检查是否可以写
- l2c_link_check_send_pkts : L2CAP层发送数据包
tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
{
tGATT_STATUS status = GATT_SUCCESS;
tGATT_CLCB *p_clcb;
tGATT_VALUE *p;
tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
{
GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
return GATT_ILLEGAL_PARAMETER;
}
if (gatt_is_clcb_allocated(conn_id))
{
GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
return GATT_BUSY;
}
if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
{
p_clcb->operation = GATTC_OPTYPE_WRITE;
p_clcb->op_subtype = type;
p_clcb->auth_req = p_write->auth_req;
if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
{
memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
p = (tGATT_VALUE *)p_clcb->p_attr_buf;
if (type == GATT_WRITE_PREPARE)
{
p_clcb->start_offset = p_write->offset;
p->offset = 0;
}
if (gatt_security_check_start(p_clcb) == FALSE)
{
status = GATT_NO_RESOURCES;
}
}
else
{
status = GATT_NO_RESOURCES;
}
if (status == GATT_NO_RESOURCES)
gatt_clcb_dealloc(p_clcb);
}
else
{
status = GATT_NO_RESOURCES;
}
return status;
}
3.4、安全检查 gatt_security_check_start
BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
{
tGATT_TCB *p_tcb = p_clcb->p_tcb;
tGATT_SEC_ACTION gatt_sec_act;
tBTM_BLE_SEC_ACT btm_ble_sec_act;
BOOLEAN status = TRUE;
tBTM_STATUS btm_status;
tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
gatt_sec_act = gatt_determine_sec_act(p_clcb);
if (sec_act_old == GATT_SEC_NONE)
gatt_set_sec_act(p_tcb, gatt_sec_act);
switch (gatt_sec_act )
{
case GATT_SEC_SIGN_DATA:
GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
gatt_sign_data(p_clcb);
break;
case GATT_SEC_ENCRYPT:
case GATT_SEC_ENCRYPT_NO_MITM:
case GATT_SEC_ENCRYPT_MITM:
if (sec_act_old < GATT_SEC_ENCRYPT)
{
GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
{
GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
status = FALSE;
}
}
if (status)
gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
break;
case GATT_SEC_ENC_PENDING:
gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
/* wait for link encrypotion to finish */
break;
default:
gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
break;
}
if (status == FALSE)
{
gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
}
return status;
}
3.5、写蓝牙(动作)结束
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
{
if (p_clcb && p_clcb->p_tcb && GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
if (!sec_check_ok)
{
gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
}
else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
{
gatt_act_write(p_clcb, sec_act);
}
else if (p_clcb->operation == GATTC_OPTYPE_READ)
{
gatt_act_read(p_clcb, p_clcb->counter);
}
}
四、最终处理函数:l2c_link_send_to_lower
最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:
- 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
- 如果当前数据包 p_buf 的长度大于 ACL 包的最大值,先看看能分成几个分包(为了求的几个窗口能容下),然后窗口值减掉这些分包个数,然后将整个数据包交给 L2C_LINK_SEND_ACL_DATA (大于ACL包长度),具体分包发送由 H5(串口) 部分来负责。
static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
{
UINT16 num_segs;
UINT16 xmit_window, acl_data_size;
if ((p_buf->len <= btu_cb.hcit_acl_pkt_size
#if (BLE_INCLUDED == TRUE)
&& (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
((p_lcb->transport == BT_TRANSPORT_LE) && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size))
#else
)
#endif
)
{
if (p_lcb->link_xmit_quota == 0)
{
#if (BLE_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_LE)
l2cb.ble_round_robin_unacked++;
else
#endif
l2cb.round_robin_unacked++;
}
p_lcb->sent_not_acked++;
p_buf->layer_specific = 0;
#if (BLE_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_LE)
{
l2cb.controller_le_xmit_window--;
L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
}
else
#endif
{
l2cb.controller_xmit_window--;
L2C_LINK_SEND_ACL_DATA (p_buf);
}
}
else
{
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
{
acl_data_size = btu_cb.hcit_ble_acl_data_size;
xmit_window = l2cb.controller_le_xmit_window;
}
else
#endif
{
acl_data_size = btu_cb.hcit_acl_data_size;
xmit_window = l2cb.controller_xmit_window;
}
num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
/* If doing round-robin, then only 1 segment each time */
if (p_lcb->link_xmit_quota == 0)
{
num_segs = 1;
p_lcb->partial_segment_being_sent = TRUE;
}
else
{
/* Multi-segment packet. Make sure it can fit */
if (num_segs > xmit_window)
{
num_segs = xmit_window;
p_lcb->partial_segment_being_sent = TRUE;
}
if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
{
num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
p_lcb->partial_segment_being_sent = TRUE;
}
}
p_buf->layer_specific = num_segs;
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
{
l2cb.controller_le_xmit_window -= num_segs;
if (p_lcb->link_xmit_quota == 0)
l2cb.ble_round_robin_unacked += num_segs;
}
else
#endif
{
l2cb.controller_xmit_window -= num_segs;
if (p_lcb->link_xmit_quota == 0)
l2cb.round_robin_unacked += num_segs;
}
p_lcb->sent_not_acked += num_segs;
#if BLE_INCLUDED == TRUE
if (p_lcb->transport == BT_TRANSPORT_LE)
{
L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
}
else
#endif
{
L2C_LINK_SEND_ACL_DATA (p_buf);
}
}
#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
#if (BLE_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_LE)
{
L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
l2cb.controller_le_xmit_window,
p_lcb->handle,
p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked);
}
else
#endif
{
L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
l2cb.controller_xmit_window,
p_lcb->handle,
p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
l2cb.round_robin_quota, l2cb.round_robin_unacked);
}
#endif
return TRUE;
}
五、hci层处理发送数据函数
l2c_link_send_to_lower 把数据交给了 L2C_LINK_SEND_ACL_DATA,L2C_LINK_SEND_ACL_DATA 其实是 bte_main_hci_send 函数,bte_main_hci_send 函数通过调用 hci 的接口 transmit_buf 来转送数据包。transmit_buf 函数作用比较简单,将此数据包入 tx_q 队列,串口(H5)的守护线程 bt_hc_worker_thread 会从 tx_q 队列中获取数据包,并将其发送。
void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
{
UINT16 sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */
p_msg->event = event;
OS_PRINTF("bte_main_hci_send event 0x%2x\n",event);
if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
(sub_event == LOCAL_BLE_CONTROLLER_ID))
{
if (bt_hc_if)
bt_hc_if->transmit_buf((TRANSAC)p_msg, \
(char *) (p_msg + 1), \
p_msg->len);
else
GKI_freebuf(p_msg);
}
else
{
APPL_TRACE_ERROR("Invalid Controller ID. Discarding message.");
GKI_freebuf(p_msg);
}
}
//在hci中,数据被写入bt driver中
static int transmit_buf(TRANSAC transac, char *p_buf, int len)
{
utils_enqueue(&tx_q, (void *) transac);
bthc_signal_event(HC_EVENT_TX);
return BT_HC_STATUS_SUCCESS;
}
六、hci层处理事件
bt_hc_worker_thread负责处理hci事件
a) 循环从队列中发送数据:p_hci_if->send(sending_msg_que[i]);
b) 发送完后,退出进程
c) 发送函数:userial_write
//external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
static void *bt_hc_worker_thread(void *arg)
{
uint16_t events;
HC_BT_HDR *p_msg, *p_next_msg;
ALOGI("bt_hc_worker_thread started");
prctl(PR_SET_NAME, (unsigned long)"bt_hc_worker", 0, 0, 0);
tx_cmd_pkts_pending = FALSE;
raise_priority_a2dp(TASK_HIGH_HCI_WORKER);
while (lib_running)
{
pthread_mutex_lock(&hc_cb.mutex);
while (ready_events == 0)
{
pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
}
events = ready_events;
ready_events = 0;
pthread_mutex_unlock(&hc_cb.mutex);
#ifndef HCI_USE_MCT
if (events & HC_EVENT_RX)
{
p_hci_if->rcv();
if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
{
/* Got HCI Cmd Credits from Controller.
* Prepare to send prior pending Cmd packets in the
* following HC_EVENT_TX session.
*/
events |= HC_EVENT_TX;
}
}
#endif
if (events & HC_EVENT_PRELOAD)
{
userial_open(USERIAL_PORT_1);
/* Calling vendor-specific part */
if (bt_vnd_if)
{
bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL);
}
else
{
if (bt_hc_cbacks)
bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL);
}
}
if (events & HC_EVENT_POSTLOAD)
{
/* Start from SCO related H/W configuration, if SCO configuration
* is required. Then, follow with reading requests of getting
* ACL data length for both BR/EDR and LE.
*/
int result = -1;
/* Calling vendor-specific part */
if (bt_vnd_if)
result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL);
if (result == -1)
p_hci_if->get_acl_max_len();
}
if (events & HC_EVENT_TX)
{
/*
* We will go through every packets in the tx queue.
* Fine to clear tx_cmd_pkts_pending.
*/
tx_cmd_pkts_pending = FALSE;
HC_BT_HDR * sending_msg_que[64];
int sending_msg_count = 0;
int sending_hci_cmd_pkts_count = 0;
utils_lock();
p_next_msg = tx_q.p_first;
while (p_next_msg && sending_msg_count <
(int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0]))
{
if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
{
/*
* if we have used up controller's outstanding HCI command
* credits (normally is 1), skip all HCI command packets in
* the queue.
* The pending command packets will be sent once controller
* gives back us credits through CommandCompleteEvent or
* CommandStatusEvent.
*/
if ((tx_cmd_pkts_pending == TRUE) ||
(sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
{
tx_cmd_pkts_pending = TRUE;
p_next_msg = utils_getnext(p_next_msg);
continue;
}
sending_hci_cmd_pkts_count++;
}
p_msg = p_next_msg;
p_next_msg = utils_getnext(p_msg);
utils_remove_from_queue_unlocked(&tx_q, p_msg);
sending_msg_que[sending_msg_count++] = p_msg;
}
utils_unlock();
int i;
for(i = 0; i < sending_msg_count; i++)
p_hci_if->send(sending_msg_que[i]);
if (tx_cmd_pkts_pending == TRUE)
BTHCDBG("Used up Tx Cmd credits");
}
if (events & HC_EVENT_LPM_ENABLE)
{
lpm_enable(TRUE);
}
if (events & HC_EVENT_LPM_DISABLE)
{
lpm_enable(FALSE);
}
if (events & HC_EVENT_LPM_IDLE_TIMEOUT)
{
lpm_wake_deassert();
}
if (events & HC_EVENT_LPM_ALLOW_SLEEP)
{
lpm_allow_bt_device_sleep();
}
if (events & HC_EVENT_LPM_WAKE_DEVICE)
{
lpm_wake_assert();
}
if (events & HC_EVENT_EPILOG)
{
/* Calling vendor-specific part */
if (bt_vnd_if)
bt_vnd_if->op(BT_VND_OP_EPILOG, NULL);
else
break; // equivalent to HC_EVENT_EXIT
}
if (events & HC_EVENT_EXIT)
break;
}
ALOGI("bt_hc_worker_thread exiting");
lib_running = 0;
pthread_exit(NULL);
return NULL; // compiler friendly
}
七、驱动层调用:
最终write 系统调操作driver的 fops 操作接口集:
//userial.c
uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
{
int ret, total = 0;
while(len != 0)
{
#if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE)
log_userial_tx_timing(len);
#endif
ret = write(userial_cb.fd, p_data+total, len);
total += ret;
len -= ret;
}
return ((uint16_t)total);
}
完~~
文 | 力卉编程
网友评论