首先介绍一下和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 + 1) + 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 = 0; UINT8 page_scan_per_mode = 0; UINT8 page_scan_mode = 0; UINT8 rssi = 0; DEV_CLASS dc; UINT16 clock_offset; UINT8 *p_eir_data = NULL; ... STREAM_TO_UINT8 num_resp, p);//解析出num_resp for xx = 0; 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_UINT8page_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_UINT8rssi, 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_bdaddrbda))// true 说明已经处理过,check是否要update { i_rssi = INT8)rssi; /* If this new RSSI is higher than the last one */ ifp_inq->inqparms.report_dup && rssi != 0) && p_i && i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0 #if BLE_INCLUDED == TRUE /* BR/EDR inquiry information update */ || p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0 #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[0] = dc[0]; p_cur->dev_class[1] = dc[1]; p_cur->dev_class[2] = dc[2]; 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, 0, BTM_EIR_SERVICE_ARRAY_SIZE * BTM_EIR_ARRAY_BITS/8)); /* 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; bdcpyresult.inq_res.bd_addr, p_inq->remote_bd_addr); memcpyresult.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN); BTM_COD_SERVICE_CLASSservice_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; ifp_inq_info = BTM_InqDbReadp_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; } ifbta_dm_search_cb.p_search_cback) bta_dm_search_cb.p_search_cbackBTA_DM_INQ_RES_EVT, &result);//上层会去解析,并且会设置是否知晓名字的标志位 ifp_inq_info) { /* application indicates if it knows the remote name, inside the callback copy that to the inquiry data base*/ ifresult.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_evttBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) { UINT16 param_len = 0; if p_data) param_len += sizeoftBTA_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_namep_data, NULL, NULL);//解析EIRdata中的名字并设置标志位 } btif_transfer_context btif_dm_search_devices_evt , UINT16) event, void *)p_data, param_len, param_len > sizeoftBTA_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_eventevent)); 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 = 0; bdstr_t bdstr; p_search_data = tBTA_DM_SEARCH *)p_param; bdcpybdaddr.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[0] = 0; cod = devclass2uint p_search_data->inq_res.dev_class); ... if !check_eir_remote_namep_search_data, bdname.name, &remote_name_len))//解析名字 check_cached_remote_namep_search_data, bdname.name, &remote_name_len); /* Check EIR for remote name and services */ if p_search_data->inq_res.p_eir) { BTA_GetEirServicep_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[5]; bt_device_type_t dev_type; uint32_t num_properties = 0; bt_status_t status; int addr_type = 0; memsetproperties, 0, sizeofproperties)); /* BD_ADDR */ BTIF_STORAGE_FILL_PROPERTY&properties[num_properties], BT_PROPERTY_BDADDR, sizeofbdaddr), &bdaddr); num_properties++; /* BD_NAME */ /* Don't send BDNAME if it is empty */ if bdname.name[0]) { BTIF_STORAGE_FILL_PROPERTY&properties[num_properties], BT_PROPERTY_BDNAME, strlenchar *)bdname.name), &bdname); num_properties++; } /* DEV_CLASS */ BTIF_STORAGE_FILL_PROPERTY&properties[num_properties], BT_PROPERTY_CLASS_OF_DEVICE, sizeofcod), &cod); num_properties++; /* DEV_TYPE */ #if definedBLE_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 = 0; if btif_get_device_typebdaddr.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, sizeofdev_type), &dev_type); num_properties++; /* RSSI */ BTIF_STORAGE_FILL_PROPERTY&properties[num_properties], BT_PROPERTY_REMOTE_RSSI, sizeofint8_t), &p_search_data->inq_res.rssi)); num_properties++; #ifdef BLUETOOTH_RTK BTIF_STORAGE_FILL_PROPERTY&properties[num_properties], BT_PROPERTY_REMOTE_VERSION_INFO, sizeofbt_remote_version_t), &info); num_properties++; #endif status = btif_storage_add_remote_device&bdaddr, num_properties, properties);//保存各个属性值到文件系统中 ASSERTCstatus == BT_STATUS_SUCCESS, "failed to save remote device inquiry)", status); #if definedBLE_INCLUDED) && BLE_INCLUDED == TRUE)) status = btif_storage_set_remote_addr_type&bdaddr, addr_type); #endif /* Callback to notify upper layer of device */ HAL_CBACKbt_hal_cbacks, device_found_cb, num_properties, properties);//向上层汇报 } } break;
这里注意btif_storage_add_remote_device 是将各个属性保存在系统的配置文件中。
上面的代码和BLE的广播包的处理 如出一辙,都是组装成bt_property_t的形式进行上报,通过HAL_CBACKbt_hal_cbacks, device_found_cb,num_properties, properties); 来上面五个属性:设备地址、设备名字、设备类、设备类型、设备rssi
那关于BREDR 的inquiry 的数据包处理流程就分析到这里。