蓝牙inquiry流程之Inquiry Complete处理
inquiry流程一般持续有12s多,当inquiry完成的时候,设备端会上报一个Event: Inquiry Complete 上来,那协议栈是如何把这个事件上传到应用层的呢?本篇文章来分析一下其具体的流程。
void btu_hcif_process_event (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_msg)
{
UINT8 *p = (UINT8 *)(p_msg + ) + p_msg->offset;
UINT8 hci_evt_code, hci_evt_len;
STREAM_TO_UINT8 (hci_evt_code, p);
STREAM_TO_UINT8 (hci_evt_len, p);
switch (hci_evt_code)
{
case HCI_INQUIRY_COMP_EVT:
btu_hcif_inquiry_comp_evt (p);
break;
...
看btu_hcif_inquiry_comp_evt 的实现:
static void btu_hcif_inquiry_comp_evt (UINT8 *p)
{
UINT8 status;
STREAM_TO_UINT8 (status, p);
/* Tell inquiry processing that we are done */
btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
}
继续看btm_process_inq_complete 的实现:
其中:
#define BTM_BR_INQUIRY_MASK (BTM_GENERAL_INQUIRY | BTM_LIMITED_INQUIRY)
btm_process_inq_complete 其实现在btm_inq.c里面:
void btm_process_inq_complete (UINT8 status, UINT8 mode)
{
tBTM_CMPL_CB *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;//保存回调函数指针
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
...
#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
p_inq->inqparms.mode &= ~(mode);
#endif btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);//向上传递
/* Ignore any stray or late complete messages if the inquiry is not active */
if (p_inq->inq_active)
{
p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING); /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */
if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == )//mode前面已经置0
{
#if BLE_INCLUDED == TRUE
btm_clear_all_pending_le_entry();//清除还没有活动scan response的设备消息
#endif
p_inq->state = BTM_INQ_INACTIVE_STATE;//设置inquiry的状态 /* Increment so the start of a next inquiry has a new count */
p_inq->inq_counter++;//增加搜索的计数 btm_clr_inq_result_flt(); if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) &&
controller_get_interface()->supports_rssi_with_inquiry_results())
{
btm_sort_inq_result();//根据rssi排序
} /* Clear the results callback if set */
p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
p_inq->inq_active = BTM_INQUIRY_INACTIVE;//设置0
p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; if (p_inq_cb)//执行回调函数,在bta_dm_search_start 进行注册bta_dm_inq_cmpl_cb
(p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
}
}
if(p_inq->inqparms.mode == && p_inq->scan_type == INQ_GENERAL)//this inquiry is complete
{
p_inq->scan_type = INQ_NONE;//scan_type置0
#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
/* check if the LE observe is pending */
if(p_inq->p_inq_ble_results_cb != NULL)//==NULL
{
BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan");
BTM_BleObserve(,, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb);
}
#endif
} }
这里主要分三部分:
- btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); 向上层汇报状态
- 清各种状态标志位
- (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
我们主要看一下第一部分和第三部分:
1.btm_acl_update_busy_level
其实现btm_acl.c:
void btm_acl_update_busy_level (tBTM_BLI_EVENT event)
{
tBTM_BL_UPDATE_DATA evt;
UINT8 busy_level;
BTM_TRACE_DEBUG ("btm_acl_update_busy_level");
BOOLEAN old_inquiry_state = btm_cb.is_inquiry;
switch (event)
{
...
case BTM_BLI_INQ_DONE_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_INQ_DONE_EVT");
btm_cb.is_inquiry = FALSE;
evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
break;
}
...
if ((busy_level != btm_cb.busy_level) ||(old_inquiry_state != btm_cb.is_inquiry))
{
evt.event = BTM_BL_UPDATE_EVT;
evt.busy_level = busy_level;
btm_cb.busy_level = busy_level;
if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK))
{
(*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
}
}
}
可以看出,主要做的事情是组建一个evt:
evt.event = BTM_BL_UPDATE_EVT;
evt.busy_level = busy_level;
evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
然后调用 (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
看看这个回调函数是在哪里注册的呢?
在btm_acl.c有个注册函数:
tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level,
tBTM_BL_EVENT_MASK evt_mask)
{
...
btm_cb.bl_evt_mask = evt_mask;
...
btm_cb.p_bl_changed_cb = p_cb;//保存回调
return(BTM_SUCCESS);
}
发现该函数是在bta_dm_sys_hw_cback里面注册的:
BTM_RegBusyLevelNotif (bta_dm_bl_change_cback, NULL, BTM_BL_UPDATE_MASK|BTM_BL_ROLE_CHG_MASK);
我们发现这个回调函数就是bta_dm_bl_change_cback ,其实现在bta_dm_act.c中:
根据上面的分析,我们知道这次传入的event = BTM_BL_UPDATE_EVT;
static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data)
{
tBTA_DM_ACL_CHANGE * p_msg;
if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL)
{
p_msg->event = p_data->event;.//继承上面event
p_msg->is_new = FALSE;//is_new = false
switch(p_msg->event)
{
...
case BTM_BL_UPDATE_EVT:
p_msg->busy_level = p_data->update.busy_level;
p_msg->busy_level_flags = p_data->update.busy_level_flags;
break;
...
}
p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
bta_sys_sendmsg(p_msg);
} }
观其实现,还是组建了一个 tBTA_DM_ACL_CHANGE 这样的事件,然后发送到btu 线程:
p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
p_msg->event = p_data->event = BTM_BL_UPDATE_EVT;
p_msg->is_new = FALSE;
这边追踪一下代码,处理这个BTA_DM_ACL_CHANGE_EVT的函数是:
/*******************************************************************************
**
** Function bta_dm_acl_change
**
** Description Process BTA_DM_ACL_CHANGE_EVT
**
**
** Returns void
**
*******************************************************************************/
void bta_dm_acl_change(tBTA_DM_MSG *p_data)
{
UINT8 i;
UINT8 *p;
tBTA_DM_SEC conn;
BOOLEAN is_new = p_data->acl_change.is_new;
BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr;
BOOLEAN need_policy_change = FALSE;
BOOLEAN issue_unpair_cb = FALSE; tBTA_DM_PEER_DEVICE *p_dev;
memset(&conn, , sizeof(tBTA_DM_SEC)); switch(p_data->acl_change.event)
{
case BTM_BL_UPDATE_EVT: /* busy level update */
if( bta_dm_cb.p_sec_cback )
{
conn.busy_level.level = p_data->acl_change.busy_level;
conn.busy_level.level_flags = p_data->acl_change.busy_level_flags;
bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);//回调到上层
}
return;
...
这边的核心代码还是组建事件往上层回调,:
conn.busy_level.level = p_data->acl_change.busy_level;
conn.busy_level.level_flags = p_data->acl_change.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);
那我们现在看看bta_dm_cb.p_sec_cback 这个回调函数是在哪里注册的:
void bta_dm_enable(tBTA_DM_MSG *p_data){
...
/* first, register our callback to SYS HW manager */
bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback );
bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback;//注册回调
...
}
发现是在bta_dm_enable 里面注册的,也就是在tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback) 传入的回调函数:
void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param) {
BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
#if (BLE_INCLUDED == TRUE)
btif_dm_load_ble_local_keys();
#endif
BTA_EnableBluetooth(bte_dm_evt);//这里注册
}
那我们知道上面回调的内容如下:
conn.busy_level.level = p_data->acl_change.busy_level;
conn.busy_level.level_flags = p_data->acl_change.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
bte_dm_evt(BTA_DM_BUSY_LEVEL_EVT, &conn);
,下面继续分析bte_dm_evt:
void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data)
{
/* switch context to btif task context (copy full union size for convenience) */
bt_status_t status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event,
(void*)p_data, sizeof(tBTA_DM_SEC), btif_dm_data_copy); /* catch any failed context transfers */
ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
}
发现该函数就是一个中转,他把事件交与bt_jni_workqueue_thread 线程中的btif_dm_upstreams_evt 函数去执行了。event从btu task 转换到了bt_jni_workqueue_thread ,我们也能感受到,事件正在一层一层往上面走,
看看btif_dm_upstreams_evt 的实现,这里面肯定也是会去处理各种不同的event:我们这种case 要处理的event = BTA_DM_BUSY_LEVEL_EVT,
/*******************************************************************************
**
** Function btif_dm_upstreams_cback
**
** Description Executes UPSTREAMS events in btif context
**
** Returns void
**
*******************************************************************************/
static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
{
tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param;
tBTA_SERVICE_MASK service_mask;
uint32_t i;
bt_bdaddr_t bd_addr;
switch (event)
{
case BTA_DM_BUSY_LEVEL_EVT:
{
if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK)
{
if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_STARTED)
{
HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
BT_DISCOVERY_STARTED);
btif_dm_inquiry_in_progress = TRUE;
}
else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED)
{
HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
BT_DISCOVERY_STOPPED);
btif_dm_inquiry_in_progress = FALSE;
}
else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_COMPLETE)
{
btif_dm_inquiry_in_progress = FALSE;//设置了这个值
}
}
}
从上面的代码分析,这里做的最重要的一件事就是:
btif_dm_inquiry_in_progress = FALSE;
第一部分的分析到此结束,下面开始看inquiry结束之后的回调函数:
3.(p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info) = bta_dm_inq_cmpl_cb
这个回调函数的注册是在 进行搜索的时候:
void bta_dm_search_start (tBTA_DM_MSG *p_data){
...
result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params,
bta_dm_inq_results_cb,
(tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);
...
}
我们看看bta_dm_inq_cmpl_cb的实现:
/*******************************************************************************
**
** Function bta_dm_inq_cmpl_cb
**
** Description Inquiry complete callback from BTM
**
** Returns void
**
*******************************************************************************/
static void bta_dm_inq_cmpl_cb (void * p_result)
{
tBTA_DM_MSG * p_msg;
if (bta_dm_search_cb.cancel_pending == FALSE)
{
p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG));
p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp;
bta_sys_sendmsg(p_msg);
}
这里发现是组建了一个msg,然后发送到btu 线程:
p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp;
BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH),
BTA_DM_API_SEARCH_CANCEL_EVT,
BTA_DM_API_DISCOVER_EVT,
BTA_DM_INQUIRY_CMPL_EVT,//0x203
...
处理该event 是handler是:
static const tBTA_SYS_REG bta_dm_search_reg =
{
bta_dm_search_sm_execute,
bta_dm_search_sm_disable
};
bta_dm_search_sm_execute:
BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg)
{
tBTA_DM_ST_TBL state_table;
UINT8 action;
int i;
/* look up the state table for the current state */
state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];
bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];
/* execute action functions */
for (i = ; i < BTA_DM_SEARCH_ACTIONS; i++)
{
if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE)
{
(*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg);
}
}
return TRUE;
}
他的处理流程是先找到该状态的table,然后赋值下一个状态,然后根据event 在table中查找该事件应该执行的action,这些action 有函数和他们一一对应,执行这些函数就行。
我们当前的状态是bta_dm_search_search_active_st_table,需要执行的action = BTA_DM_INQUIRY_CMPL,下一个状态依然是BTA_DM_SEARCH_ACTIVE
我们看看BTA_DM_INQUIRY_CMPL 对应的函数是什么?
/* action function list */
const tBTA_DM_ACTION bta_dm_search_action[] =
{ bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */
bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */
bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */
bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */
bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */
看看 回调函数的具体实现:
/*******************************************************************************
**
** Function bta_dm_inq_cmpl
**
** Description Process the inquiry complete event from BTM
**
** Returns void
**
*******************************************************************************/
void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data)
{
tBTA_DM_MSG * p_msg;
tBTA_DM_SEARCH data; APPL_TRACE_DEBUG("bta_dm_inq_cmpl"); data.inq_cmpl.num_resps = p_data->inq_cmpl.num;
bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);//执行回调,向上层通知 if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL)//如果搜索到设备了,对设备做discover的动作
{
/* start name and service discovery from the first device on inquiry result */
bta_dm_search_cb.name_discover_done = FALSE;
bta_dm_search_cb.peer_name[] = ;
bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
}
else //否则结束,向上层传 BTA_DM_SEARCH_CMPL_EVT;
{
/* no devices, search complete */
bta_dm_search_cb.services = ; if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
{
p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
bta_sys_sendmsg(p_msg);
}
}
}
这一部分的内容也可以分为三部分:
- bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
- 有搜索到设备,进行discovery
- 没有搜索到设备,上报BTA_DM_SEARCH_CMPL_EVT
首先来看看 第一部分:
3.1 bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
bta_dm_search_cb.p_search_cback 在BTA_DmSearch 中赋值的,为bte_search_devices_evt ,我们看看其实现:
/*******************************************************************************
**
** Function bte_search_devices_evt
**
** Description Switches context from BTE to BTIF for DM search events
**
** Returns void
**
*******************************************************************************/
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{
UINT16 param_len = ;
...
btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
}
发现其直接被transfer 到btif线程 中执行btif_dm_search_devices_evt:
/******************************************************************************
**
** Function btif_dm_search_devices_evt
**
** Description Executes search devices callback events in btif context
**
** Returns void
**
******************************************************************************/
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_search_data;
BTIF_TRACE_EVENT("%s event=%s", __FUNCTION__, dump_dm_search_event(event)); switch (event)
{
...
case BTA_DM_INQ_CMPL_EVT://并没有进一步去通知上层
{
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;
memset(&adv_filt_param, , sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_DELETE, , &adv_filt_param, NULL,
bte_scan_filt_param_cfg_evt, );
#endif
}
break;
case BTA_DM_DISC_CMPL_EVT:
{
HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED);//如果是BTA_DM_DISC_CMPL_EVT:会进一步通知上层
}
break;
这里发现,BTA_DM_INQ_CMPL_EVT:并不会一直往上面传,而 BTA_DM_DISC_CMPL_EVT:则是会上报给上层。那如果一直搜索不到设备就不会给上层答复吗?我们看看第三部分的行为。
3.2 有搜索到设备,进行discovery
再次贴上代码:
if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL)
{
/* start name and service discovery from the first device on inquiry result */
bta_dm_search_cb.name_discover_done = FALSE;
bta_dm_search_cb.peer_name[] = ;
bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
}
看代码的注释,是开始名字和service 的discovery 的工作。看看 这个函数的实现:
首先简述一下该函数的作用:
- 判断是否需要去获取对端设备的名字。不需要跳过,需要就去获取名字并返回,这里猜想服务方面的搜索肯定是在获取名字返回的函数里面进行。
- 判断是否需要进行服务的搜索,需要则 进行,从开始 的discovery的接口看,应该是不需要进行服务的搜索。
- 发出服务完成的event,发送到btu 线程。
下面看代码:
/*******************************************************************************
**
** Function bta_dm_discover_device
**
** Description Starts name and service discovery on the device
**
** Returns void
**
*******************************************************************************/
static void bta_dm_discover_device(BD_ADDR remote_bd_addr)
{
tBTA_DM_MSG * p_msg;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
#if BLE_INCLUDED == TRUE
if (bta_dm_search_cb.transport == BTA_TRANSPORT_UNKNOWN)//一开始都是unkown,会BTM_ReadDevInfo来判断transport
{
tBT_DEVICE_TYPE dev_type;
tBLE_ADDR_TYPE addr_type; BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type);
if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM)
transport = BT_TRANSPORT_LE;
} else {
transport = bta_dm_search_cb.transport;
}
#endif /* Reset transport state for next discovery */
bta_dm_search_cb.transport = BTA_TRANSPORT_UNKNOWN;//reset bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr); if (bta_dm_search_cb.p_btm_inq_info)
{
APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__,
bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);//显示app是否已经知道名字,这是inquiry db里面的数据
} if((bta_dm_search_cb.p_btm_inq_info)
&& (bta_dm_search_cb.p_btm_inq_info->results.device_type == BT_DEVICE_TYPE_BLE)
&& (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE))
{
/* Do not perform RNR for LE devices at inquiry complete*/
bta_dm_search_cb.name_discover_done = TRUE; //不要去查找LE 设备的名字
} /* if name discovery is not done and application needs remote name */
if ((!bta_dm_search_cb.name_discover_done)
&& (( bta_dm_search_cb.p_btm_inq_info == NULL )
||(bta_dm_search_cb.p_btm_inq_info && (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name))))//需要名字则进行名字的搜索
{
if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, transport) == TRUE)
return;//返回 /* starting name discovery failed */
bta_dm_search_cb.name_discover_done = TRUE;
}
/* if application wants to discover service */
if ( bta_dm_search_cb.services )//一般是0
{
/* initialize variables */
bta_dm_search_cb.service_index = ;
bta_dm_search_cb.services_found = ;
bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
#endif
if ((bta_dm_search_cb.p_btm_inq_info != NULL) &&
bta_dm_search_cb.services != BTA_USER_SERVICE_MASK
&&(bta_dm_search_cb.sdp_search == FALSE))
{
/* check if EIR provides the information of supported services */
bta_dm_eir_search_services( &bta_dm_search_cb.p_btm_inq_info->results,
&bta_dm_search_cb.services_to_search,
&bta_dm_search_cb.services_found );
} /* if seaching with EIR is not completed */
if(bta_dm_search_cb.services_to_search)
{
/* check whether connection already exists to the device
if connection exists, we don't have to wait for ACL
link to go down to start search on next device */
if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR))
bta_dm_search_cb.wait_disc = FALSE;
else
bta_dm_search_cb.wait_disc = TRUE; #if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
if ( bta_dm_search_cb.p_btm_inq_info )
{
APPL_TRACE_DEBUG("%s p_btm_inq_info 0x%x results.device_type 0x%x services_to_search 0x%x",
__func__,
bta_dm_search_cb.p_btm_inq_info,
bta_dm_search_cb.p_btm_inq_info->results.device_type,
bta_dm_search_cb.services_to_search);
} if (transport == BT_TRANSPORT_LE)
{
if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK)
{
//set the raw data buffer here
memset(g_disc_raw_data_buf, , sizeof(g_disc_raw_data_buf));
bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf; bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF;
bta_dm_search_cb.ble_raw_used = ; /* start GATT for service discovery */
btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
return;
}
}
else
#endif
{
bta_dm_search_cb.sdp_results = FALSE;
bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
return;
}
}
} /* name discovery and service discovery are done for this device */
if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
{
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;//发送event到btu 线程
/* initialize the data structure - includes p_raw_data and raw_data_size */
memset(&(p_msg->disc_result.result), , sizeof(tBTA_DM_DISC_RES));
p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME),
(char*)bta_dm_search_cb.peer_name, (BD_NAME_LEN-)); /* make sure the string is terminated */
p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-] = ; bta_sys_sendmsg(p_msg);
}
}
服务方面 ok了之后是 会向btu 线程发送event:
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
BTA_DM_DISCOVERY_RESULT_EVT = 0x207
执行的action = BTA_DM_SEARCH_RESULT,对应的函数是bta_dm_search_result,看看其具体的实现:
/*******************************************************************************
**
** Function bta_dm_search_result
**
** Description Service discovery result while searching for devices
**
** Returns void
**
*******************************************************************************/
void bta_dm_search_result (tBTA_DM_MSG *p_data)
{
/* call back if application wants name discovery or found services that application is searching */
if (( !bta_dm_search_cb.services )
||(( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services )))
{
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result);//回调
} /* if searching did not initiate to create link */
if(!bta_dm_search_cb.wait_disc )//如果没有pending
{
/* if service searching is done with EIR, don't search next device */
if( bta_dm_search_cb.p_btm_inq_info )
bta_dm_discover_next_device();//去搜索下一个设备的服务
}
else
{
/* wait until link is disconnected or timeout */
bta_dm_search_cb.sdp_results = TRUE;
bta_dm_search_cb.search_timer.p_cback = (TIMER_CBACK*)&bta_dm_search_timer_cback;
bta_sys_start_timer(&bta_dm_search_cb.search_timer, , *(L2CAP_LINK_INACTIVITY_TOUT+) );//如果pending了,那么设置定时器,并且在回调函数里面继续执行搜索下一个设备的服务
} }
这里简单分析两点:
- bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result)
- bta_dm_discover_next_device,如果有数据库里面还有设备的话,那么继续搜索服务,如果没有设备的话,向上面传:BTA_DM_SEARCH_CMPL_EVT,最终也会上报到java层。前面已经分析过。‘
分析一下bta_dm_search_cb.p_search_cback,我们又遇到这个函数了,其实是bte_search_devices_evt-->btif_dm_search_devices_evt:
/******************************************************************************
**
** Function btif_dm_search_devices_evt
**
** Description Executes search devices callback events in btif context
**
** Returns void
**
******************************************************************************/
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_search_data;
switch (event)
{
case BTA_DM_DISC_RES_EVT:
{
p_search_data = (tBTA_DM_SEARCH *)p_param;
/* Remote name update */
if (strlen((const char *) p_search_data->disc_res.bd_name))//如果早先已经知道了名字,这里的名字的长度0
{
bt_property_t properties[];
bt_bdaddr_t bdaddr;
bt_status_t status; properties[].type = BT_PROPERTY_BDNAME;
properties[].val = p_search_data->disc_res.bd_name;
properties[].len = strlen((char *)p_search_data->disc_res.bd_name);
bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr); status = btif_storage_set_remote_device_property(&bdaddr, &properties[]);
ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
status, &bdaddr, , properties);
}
现在简单看下:bta_dm_discover_next_device:
/*******************************************************************************
**
** Function bta_dm_discover_next_device
**
** Description Starts discovery on the next device in Inquiry data base
**
** Returns void
**
*******************************************************************************/
static void bta_dm_discover_next_device(void)
{ tBTA_DM_MSG * p_msg; /* searching next device on inquiry result */
if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info)) != NULL)
{
bta_dm_search_cb.name_discover_done = FALSE;
bta_dm_search_cb.peer_name[] = ;
bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);//继续搜索服务
}
else
{
/* no devices, search complete */
bta_dm_search_cb.services = ; if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
{
p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;//都搜索我弄成之后上报event,结束discovery的流程
p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
bta_sys_sendmsg(p_msg);
}
}
}
服务搜索部分就介绍到这里。
3.3 没有搜索到设备或者搜索完成,上报BTA_DM_SEARCH_CMPL_EVT
再附上这段代码:
{
/* no devices, search complete */
bta_dm_search_cb.services = ; if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
{
p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
bta_sys_sendmsg(p_msg);
}
这边还是组装了一个event:
p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
相应的log也就是:BTA got event 0x206
const tBTA_DM_ACTION bta_dm_search_action[] =
{ bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */
bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */
bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */
bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */
bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */
bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */
bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */
执行的就是bta_dm_search_cmpl:
/*******************************************************************************
**
** Function bta_dm_search_cmpl
**
** Description Sends event to application
**
** Returns void
**
*******************************************************************************/
void bta_dm_search_cmpl (tBTA_DM_MSG *p_data)
{
APPL_TRACE_EVENT("%s", __func__);
...
if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT)
bta_dm_di_disc_cmpl(p_data);
else
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL);
#endif
}
函数如注释阐明的那样:Sends event to application
我们前面已经分析过bta_dm_search_cb.p_search_cback=bte_search_devices_evt ,这次传入的事件是BTA_DM_DISC_CMPL_EVT
bte_search_devices_evt --->继续进入到btif_dm_search_devices_evt:
/******************************************************************************
**
** Function btif_dm_search_devices_evt
**
** Description Executes search devices callback events in btif context
**
** Returns void
**
******************************************************************************/
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_search_data;
BTIF_TRACE_EVENT("%s event=%s", __FUNCTION__, dump_dm_search_event(event)); switch (event)
{
...
case BTA_DM_DISC_CMPL_EVT:
{
HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED);
}
break;
...
这一段其实再第一部分已经分析过,当传入的事件是BTA_DM_DISC_CMPL_EVT,那么就会调用:HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED); 来通知上层 。
其实也就是说,即便一条设备信息也搜索不到,那么也会发送BTA_DM_SEARCH_CMPL_EVT---->BTA_DM_DISC_CMPL_EVT --->调用HAL_CBACK:BT_DISCOVERY_STOPPED 来通知上层。
到这里 inquiry complete的流程就已经分析完毕了。
总结:
Inquiry Complete
- update level busy,(btm_acl_update_busy_level)并不会上报到java层
- 执行bta_dm_inq_cmpl_cb
- bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data); 该函数不会通知上层,
- 有搜索到设备,进行discovery
- 没有搜索到设备,上报BTA_DM_SEARCH_CMPL_EVT ,并通知到上层。
蓝牙inquiry流程之Inquiry Complete处理的更多相关文章
- 蓝牙inquiry流程之Advertising Report
setting 界面开始搜索的时候,通常也会同时进行le scan,这一点在inquiry流程之命令下发中已经讲述.此篇文章主要是分析一下对于controller 搜索到的广播包的处理.这里以Andr ...
- 蓝牙inquiry流程之HCI_Inquiry_Result_With_RSSI和HCI Extended Inquiry Result处理
首先介绍一下和inquiry的相关的流程. inquiry是从协议栈下发的一个HCI命令.其格式如下: 这里简单介绍下第二个参数,是inquiry的持续时间, 从上图看出 inquiry持续的时间是 ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(八):完成个人任务
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(九):历史任务查询
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(七):任务列表展示
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(六):启动流程
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(五):流程定义列表
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(三):流程模型列表展示
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
随机推荐
- MySQL——索引基础
本篇文章,我们将从索引基础开始,介绍什么是索引以及索引的几种类型,然后学习如何创建索引以及索引设计的基本原则. 本篇文章中用于测试索引创建的user表的结构如下: 什么是索引 索引(在 MySQL 中 ...
- Httprunner学习
一.简介 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份YAML/JSON脚本,即可实现自动化测试.性能测试.线上监控.持续集成等多种测试需求. 核心特性: 继 ...
- 记一次Linux下数据统计
需求: 服务端有应用访问日志,需要统计某一个API,访问top N的通道. 统计思路: 1.筛选/过滤待统计API: 2.分割,获取待统计具体字段: 3.计数: 4.按照计数结果降序排序: 5.截取t ...
- 蓝魔i7s刷机
,电脑管家,豌豆荚之类的PC工具 5. 安装MFT6.0.43.exe, 注意:MFT6.0.43需要对应的ISOC和USB驱动,不可使用其它版本 6. 将CUSTOM_CONFIG..INI文件复制 ...
- SQLServer的TDE加密
TDE的主要作用是防止数据库备份或数据文件被偷了以后,偷数据库备份或文件的人在没有数据加密密钥的情况下是无法恢复或附加数据库的. 首先创建SQL Server中master系统数据库的MASTER K ...
- 跨平台开发 -- C# 使用 C/C++ 生成的动态链接库
操作环境:Visual Studio 2017 如何实现 使用 C# 进行嵌入式开发? .NET Core 虽然实现了跨平台,但是不可能处处使用 C# 开发,就好像没人使用SQL开发安卓APP,每种语 ...
- mac系统默认python3.6
1. 终端打开.bash_profile文件 终端输入:open ~/.bash_profile 2. 打开.bash_profile文件后在内容最后添加 alias python=" ...
- 在学习前端的路上,立下一个Flag
今天开始百度前端学习,以此为证
- Android Studio快捷键——编辑篇
Android Studio是官方推出的Android开发IDE,本系列讲解Android Studio中常用的快捷键,本文是该系列的第一篇,讲解的内容是与编辑代码相关的快捷键. 本文所讲快捷键基于A ...
- $Gauss$消元
$Gauss$消元 今天金牌爷来问我一个高消的题目,我才想起来忘了学高消... 高斯消元用于解线性方程组,也就是形如: $\left\{\begin{matrix}a_{11}x_1+a_{12}x_ ...