首先介绍一下和inquiry的相关的流程。

inquiry是从协议栈下发的一个HCI命令。其格式如下:

这里简单介绍下第二个参数,是inquiry的持续时间,

从上图看出 inquiry持续的时间是 设定值乘以1.28s,如果设定值是10,那么实际持续的时间就是12.8s

那么下了这个HCI命令之后,控制器端上传的event是什么呢?这个要看另外一个命令:HCI_Write_Inquiry_mode

我们主要关注一下其中的inquiry mode

根据这个设定值,我们知道controller 可能会上传event的类型。假如mode = 0x02,那么controller上传的event的类型就可能是Inquiry Result with RSSI format or Extended Inquiry Result format ,如果mode = 1,那么上传的event只能是Inquiry Result format with RSSI。

那Inquiry Result with RSSI format 和 Extended Inquiry Result format有什么区别呢?唯一的区别就是后者比前者多了一个extended inquiry response的数据域。

下面进入到 对于Inquiry Result with RSSI format 和 Extended Inquiry Result format 的代码处理流程的分析:

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;
#if BLE_INCLUDED == TRUE
UINT8 ble_sub_code;
#endif
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;
case HCI_INQUIRY_RESULT_EVT:
btu_hcif_inquiry_result_evt (p);
break;
case HCI_INQUIRY_RSSI_RESULT_EVT:
btu_hcif_inquiry_rssi_result_evt (p);
break;
case HCI_EXTENDED_INQUIRY_RESULT_EVT:
btu_hcif_extended_inquiry_result_evt (p);
break;
...

上面介绍的三种mode,都是调用同一个处理函数,只是传入的参数不同, 我们发现HCI_EXTENDED_INQUIRY_RESULT_EVT流程涵盖了HCI_INQUIRY_RSSI_RESULT_EVT 的流程。

我们只分析:HCI_EXTENDED_INQUIRY_RESULT_EVT的流程

static void btu_hcif_inquiry_rssi_result_evt (UINT8 *p)
{
/* Store results in the cache */
btm_process_inq_results (p, BTM_INQ_RESULT_WITH_RSSI);
}

继续看btm_process_inq_results的流程:

/*******************************************************************************
**
** Function btm_process_inq_results
**
** Description This function is called when inquiry results are received from
** the device. It updates the inquiry database. If the inquiry
** database is full, the oldest entry is discarded.
**
** Parameters inq_res_mode - BTM_INQ_RESULT_STANDARD
** BTM_INQ_RESULT_WITH_RSSI
** BTM_INQ_RESULT_EXTENDED
**
** Returns void
**
*******************************************************************************/
void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode)
{
UINT8 num_resp, xx;
BD_ADDR bda;
tINQ_DB_ENT *p_i;
tBTM_INQ_RESULTS *p_cur=NULL;
BOOLEAN is_new = TRUE;
BOOLEAN update = FALSE;
INT8 i_rssi;
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
UINT8 page_scan_rep_mode = ;
UINT8 page_scan_per_mode = ;
UINT8 page_scan_mode = ;
UINT8 rssi = ;
DEV_CLASS dc;
UINT16 clock_offset;
UINT8 *p_eir_data = NULL;
...
STREAM_TO_UINT8 (num_resp, p);//解析出num_resp for (xx = ; xx < num_resp; xx++)//依次处理,一般只有一个
{
update = FALSE;//初始化位false
/* Extract inquiry results */
STREAM_TO_BDADDR (bda, p);//解析出地址等
STREAM_TO_UINT8 (page_scan_rep_mode, p);
STREAM_TO_UINT8 (page_scan_per_mode, p); if (inq_res_mode == BTM_INQ_RESULT_STANDARD)
{
STREAM_TO_UINT8(page_scan_mode, p);
} STREAM_TO_DEVCLASS (dc, p);//解析device class
STREAM_TO_UINT16 (clock_offset, p);
if (inq_res_mode != BTM_INQ_RESULT_STANDARD)
{
STREAM_TO_UINT8(rssi, p);//stand 没有rssi
} p_i = btm_inq_db_find (bda);//查找数据库,后续会判断是否已经处理过
...
/* Check if this address has already been processed for this inquiry */
if (btm_inq_find_bdaddr(bda))// true 说明已经处理过,check是否要update
{
i_rssi = (INT8)rssi;
/* If this new RSSI is higher than the last one */
if(p_inq->inqparms.report_dup && (rssi != ) &&
p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi ==
#if BLE_INCLUDED == TRUE
/* BR/EDR inquiry information update */
|| (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) !=
#endif
))
{
p_cur = &p_i->inq_info.results;
BTM_TRACE_DEBUG("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi);
p_cur->rssi = i_rssi;
update = TRUE;
}
/* If we received a second Extended Inq Event for an already */
/* discovered device, this is because for the first one EIR was not received */
else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i))
{
p_cur = &p_i->inq_info.results;
update = TRUE;
}
/* If no update needed continue with next response (if any) */
else
continue;
} /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
if (p_i == NULL)
{
p_i = btm_inq_db_new (bda);//新建数据库
is_new = TRUE;
} /* If an entry for the device already exists, overwrite it ONLY if it is from
a previous inquiry. (Ignore it if it is a duplicate response from the same
inquiry.
*/
else if (p_i->inq_count == p_inq->inq_counter //相等说明是本次inquiry
#if (BLE_INCLUDED == TRUE )
&& (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR)
#endif
)
is_new = FALSE;//不是新的 /* keep updating RSSI to have latest value */
if( inq_res_mode != BTM_INQ_RESULT_STANDARD )//如果不是标准模式,rssi每次都要更新
p_i->inq_info.results.rssi = (INT8)rssi;
else
p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI; if (is_new == TRUE)//如果是新设备,那么保存这些信息
{
/* Save the info */
p_cur = &p_i->inq_info.results;
p_cur->page_scan_rep_mode = page_scan_rep_mode;
p_cur->page_scan_per_mode = page_scan_per_mode;
p_cur->page_scan_mode = page_scan_mode;
p_cur->dev_class[] = dc[];
p_cur->dev_class[] = dc[];
p_cur->dev_class[] = dc[];
p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; p_i->time_of_resp = GKI_get_os_tick_count();//获取时间,用以计算最老的item if (p_i->inq_count != p_inq->inq_counter)
p_inq->inq_cmpl_info.num_resp++; /* A new response was found */ #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
p_cur->inq_result_type = BTM_INQ_RESULT_BR;
if (p_i->inq_count != p_inq->inq_counter)
{
p_cur->device_type = BT_DEVICE_TYPE_BREDR;
p_i->scan_rsp = FALSE;
}
else
p_cur->device_type |= BT_DEVICE_TYPE_BREDR;
#endif
p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
...
/* Initialize flag to FALSE. This flag is set/used by application */
p_i->inq_info.appl_knows_rem_name = FALSE;//初始化位false
}
if (is_new || update)
{
if( inq_res_mode == BTM_INQ_RESULT_EXTENDED )
{
memset( p_cur->eir_uuid, ,
BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS/));
/* set bit map of UUID list from received EIR */
btm_set_eir_uuid( p, p_cur );//将UUID list保存在tBTM_INQ_RESULTS->eir_uuid中
p_eir_data = p;
}
else
p_eir_data = NULL; /* If a callback is registered, call it with the results */
if (p_inq_results_cb)//调用回调
(p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
}
}
}

上面的流程比较简单,主要就是保存inquiry回来的信息,然后调用p_inq_results_cb 来处理 设备信息。这个在BTM_StartInquiry的时候传入参数bta_dm_inq_results_cb,调用的也就是这个回调函数。下面继续分析bta_dm_inq_results_cb

/*******************************************************************************
**
** Function bta_dm_inq_results_cb
**
** Description Inquiry results callback from BTM
**
** Returns void
**
*******************************************************************************/
static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir)
{ tBTA_DM_SEARCH result;
tBTM_INQ_INFO *p_inq_info;
UINT16 service_class; bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN);
BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class);
result.inq_res.is_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER)?TRUE:FALSE;
result.inq_res.rssi = p_inq->rssi; #if (BLE_INCLUDED == TRUE)
result.inq_res.ble_addr_type = p_inq->ble_addr_type;
result.inq_res.inq_result_type = p_inq->inq_result_type;
result.inq_res.device_type = p_inq->device_type;
result.inq_res.flag = p_inq->flag;
#endif /* application will parse EIR to find out remote device name */
result.inq_res.p_eir = p_eir; if((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL)
{
/* initialize remt_name_not_required to FALSE so that we get the name by default */
result.inq_res.remt_name_not_required = FALSE; } if(bta_dm_search_cb.p_search_cback)
bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result);//上层会去解析,并且会设置是否知晓名字的标志位 if(p_inq_info)
{
/* application indicates if it knows the remote name, inside the callback
copy that to the inquiry data base*/
if(result.inq_res.remt_name_not_required)
p_inq_info->appl_knows_rem_name = TRUE;//将标志位位传递到数据库 } }

上面的逻辑很简单,就是组建了一个 tBTA_DM_SEARCH 然后继续向上层汇报 事件。

我们继续看bta_dm_search_cb.p_search_cback 的流程,我们已经多次分析:bta_dm_search_cb.p_search_cback = 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 = ; if (p_data)
param_len += sizeof(tBTA_DM_SEARCH);
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
switch (event)
{
case BTA_DM_INQ_RES_EVT:
{
if (p_data->inq_res.p_eir)
param_len += HCI_EXT_INQ_RESPONSE_LEN;
}
break;
...
/* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
if (event == BTA_DM_INQ_RES_EVT){
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);//解析EIRdata中的名字并设置标志位
}
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
}

我们继续看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_RES_EVT:
{
/* inquiry result */
UINT32 cod;
bt_bdname_t bdname;
bt_bdaddr_t bdaddr;
UINT8 remote_name_len;
tBTA_SERVICE_MASK services = ;
bdstr_t bdstr; p_search_data = (tBTA_DM_SEARCH *)p_param;
bdcpy(bdaddr.address, p_search_data->inq_res.bd_addr); #if (BLE_INCLUDED == TRUE)
p_search_data->inq_res.device_type);
#else
BT_DEVICE_TYPE_BREDR);
#endif
bdname.name[] = ; cod = devclass2uint (p_search_data->inq_res.dev_class);
...
if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len))//解析名字
check_cached_remote_name(p_search_data, bdname.name, &remote_name_len); /* Check EIR for remote name and services */
if (p_search_data->inq_res.p_eir)
{
BTA_GetEirService(p_search_data->inq_res.p_eir, &services);
BTIF_TRACE_DEBUG("%s()EIR BTA services = %08X", __FUNCTION__, (UINT32)services);
/* TODO: Get the service list and check to see which uuids we got and send it back to the client. */
} {
bt_property_t properties[];
bt_device_type_t dev_type;
uint32_t num_properties = ;
bt_status_t status;
int addr_type = ; memset(properties, , sizeof(properties));
/* BD_ADDR */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr);
num_properties++;
/* BD_NAME */
/* Don't send BDNAME if it is empty */
if (bdname.name[])
{
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_BDNAME,
strlen((char *)bdname.name), &bdname);
num_properties++;
} /* DEV_CLASS */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
num_properties++;
/* DEV_TYPE */
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
/* FixMe: Assumption is that bluetooth.h and BTE enums match */ /* Verify if the device is dual mode in NVRAM */
int stored_device_type = ;
if (btif_get_device_type(bdaddr.address, &stored_device_type) &&
((stored_device_type == BT_DEVICE_TYPE_BLE &&
p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BREDR) ||
(stored_device_type == BT_DEVICE_TYPE_BREDR &&
p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE))) {
dev_type = BT_DEVICE_TYPE_DUMO;
} else {
dev_type = p_search_data->inq_res.device_type;
} if (p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE)
addr_type = p_search_data->inq_res.ble_addr_type;
#else
dev_type = BT_DEVICE_TYPE_BREDR;
#endif
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type);
num_properties++;
/* RSSI */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_REMOTE_RSSI, sizeof(int8_t),
&(p_search_data->inq_res.rssi));
num_properties++; #ifdef BLUETOOTH_RTK
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_REMOTE_VERSION_INFO, sizeof(bt_remote_version_t),
&info);
num_properties++;
#endif status = btif_storage_add_remote_device(&bdaddr, num_properties, properties);//保存各个属性值到文件系统中
ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device (inquiry)", status);
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
status = btif_storage_set_remote_addr_type(&bdaddr, addr_type);
#endif
/* Callback to notify upper layer of device */
HAL_CBACK(bt_hal_cbacks, device_found_cb,
num_properties, properties);//向上层汇报
}
}
break;

这里注意btif_storage_add_remote_device 是将各个属性保存在系统的配置文件中。

上面的代码和BLE的广播包的处理 如出一辙,都是组装成bt_property_t的形式进行上报,通过HAL_CBACK(bt_hal_cbacks, device_found_cb,num_properties, properties); 来上面五个属性:设备地址、设备名字、设备类、设备类型、设备rssi

那关于BREDR 的inquiry 的数据包处理流程就分析到这里。


蓝牙inquiry流程之HCI_Inquiry_Result_With_RSSI和HCI Extended Inquiry Result处理的更多相关文章

  1. 蓝牙inquiry流程之Advertising Report

    setting 界面开始搜索的时候,通常也会同时进行le scan,这一点在inquiry流程之命令下发中已经讲述.此篇文章主要是分析一下对于controller 搜索到的广播包的处理.这里以Andr ...

  2. 蓝牙inquiry流程之Inquiry Complete处理

    inquiry流程一般持续有12s多,当inquiry完成的时候,设备端会上报一个Event: Inquiry Complete 上来,那协议栈是如何把这个事件上传到应用层的呢?本篇文章来分析一下其具 ...

  3. activiti自定义流程之Spring整合activiti-modeler5.16实例(九):历史任务查询

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  4. activiti自定义流程之Spring整合activiti-modeler5.16实例(八):完成个人任务

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  5. activiti自定义流程之Spring整合activiti-modeler5.16实例(七):任务列表展示

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  6. activiti自定义流程之Spring整合activiti-modeler5.16实例(六):启动流程

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  7. activiti自定义流程之Spring整合activiti-modeler5.16实例(五):流程定义列表

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  8. activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  9. activiti自定义流程之Spring整合activiti-modeler5.16实例(三):流程模型列表展示

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

随机推荐

  1. Oracle EBS AP 创建贷项通知单并核销到相应发票

    --1.0 生成与发票一样的贷项通知单 created by jenrry 20170423 DECLARE L_CUSTOMER_TRX_ID NUMBER; L_INVOICE_NUMBER VA ...

  2. windows7环境下使用pip安装MySQLdb for python3.7

    1.首先,需要确定你已经安装了pip.在Python2.7的安装包中,easy_install.py和pip都是默认安装的.可以在Python的安装目录先确认,如果\Python37\Scripts里 ...

  3. sha256sum和 md5sum 命令之间的区别

    Short answer: For verifying ISOs, there is no practical difference, use whichever you want, as long ...

  4. python的学习之路day3

    大纲 1.汉字编码 2.浅拷贝与深拷贝 3.函数 4.return 5.函数的基本参数 6.format 7.三元运算(三目运算) 8.python的内置函数 abs() all() any() bo ...

  5. Resource View Window of Visual Studio

    https://msdn.microsoft.com/en-us/library/d4cfawwc.aspx For the latest documentation on Visual Studio ...

  6. MyBatis 中的级联

    MyBatis 的级联分为 3 种. 1.鉴别器(discriminator):它是根据某些条件决定采用具体实现类级联的方案,比如体检表要根据性别去区分. 2.一对一(association):比如学 ...

  7. react-native-storage 使用笔记 持续更新

    React-native-storage是在AsyncStorage之上封装的一个缓存操作插件库,刚开始接触这个也遇到了一些问题,在这里简单记录总结一下,碰到了就记下来,持续更新吧 1.安卓下stor ...

  8. 用ASP.NET Web API技术开发HTTP接口

    开发工具 Visual Studio 2013 SQL Server 2008 R2 准备工作 启动Visual Studio 2013,新建一个ASP.NET Web应用程序,命名为SimpleAP ...

  9. 【转】ajax 跨域 headers JavaScript ajax 跨域请求 +设置headers 实践

    解决跨域调用服务并设置headers 主要的解决方法需要通过服务器端设置响应头.正确响应options请求,正确设置 JavaScript端需要设置的headers信息 方能实现. 此处手札 供后人参 ...

  10. Scala学习之路 (三)Scala的基本使用

    一.Scala概述 scala是一门多范式编程语言,集成了面向对象编程和函数式编程等多种特性.scala运行在虚拟机上,并兼容现有的Java程序.Scala源代码被编译成java字节码,所以运行在JV ...