藍牙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 的數據包處理流程就分析到這里。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM