• 蓝牙inquiry流程之HCI_Inquiry_Result_With_RSSI和HCI Extended Inquiry Result处理


    首先介绍一下和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_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 != 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;
    
        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 = 0;
    
        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 = 0;
                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[0] = 0;
    
                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[5];
                    bt_device_type_t dev_type;
                    uint32_t num_properties = 0;
                    bt_status_t status;
                    int addr_type = 0;
    
                    memset(properties, 0, 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[0])
                    {
                        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 = 0;
                    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 的数据包处理流程就分析到这里。


  • 相关阅读:
    C语言学习11(循环结构:for语句)
    C语言学习9(循环结构:while语句)
    C语言学习8(选择结构的嵌套)
    C语言学习笔记2
    C语言学习笔记1
    C语言的学习5(数据的输出)
    C语言学习12(函数的定义)
    第二十一章流 14临时文件 简单
    第二十一章流 12输出数据到文件指定位置处seekp() 简单
    第二十一章流 11指定读取文件中的数据seekg() 简单
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9243500.html
Copyright © 2020-2023  润新知