蓝牙inquiry流程之命令下发

Posted libs-liu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝牙inquiry流程之命令下发相关的知识,希望对你有一定的参考价值。

android 上面的蓝牙inquiry 是在设置界面,打开蓝牙就会自动搜索周边的蓝牙设备,其最终调用到协议栈的start_discovery接口,此篇文章分析该接口的调用流程以及与controller交互过程。

static int start_discovery(void)
{
    /* sanity check */
    if (interface_ready() == FALSE)
        return BT_STATUS_NOT_READY;
    return btif_dm_start_discovery();
}

 

bt_status_t btif_dm_start_discovery(void)
{
    tBTA_DM_INQ inq_params;
    tBTA_SERVICE_MASK services = 0;
    tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;

#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    memset(&adv_filt_param, 0, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
    /* Cleanup anything remaining on index 0 */
    BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_DELETE, 0, &adv_filt_param, NULL,
                             bte_scan_filt_param_cfg_evt, 0);

    /* Add an allow-all filter on index 0*/
    adv_filt_param.dely_mode = IMMEDIATE_DELY_MODE;
    adv_filt_param.feat_seln = ALLOW_ALL_FILTER;
    adv_filt_param.filt_logic_type = BTA_DM_BLE_PF_FILT_LOGIC_OR;
    adv_filt_param.list_logic_type = BTA_DM_BLE_PF_LIST_LOGIC_OR;
    adv_filt_param.rssi_low_thres = LOWEST_RSSI_VALUE;
    adv_filt_param.rssi_high_thres = LOWEST_RSSI_VALUE;
    BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_ADD, 0, &adv_filt_param, NULL,
                             bte_scan_filt_param_cfg_evt, 0);

    /* TODO: Do we need to handle multiple inquiries at the same time? */

    /* Set inquiry params and call API */
    inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;//设置inquiry模式,ble和bredr
#else
    inq_params.mode = BTA_DM_GENERAL_INQUIRY;
#endif
    inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;//设置超时时间

    inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;//设置接收的最大的response数量
    inq_params.report_dup = TRUE;

    inq_params.filter_type = BTA_DM_INQ_CLR;//0
    /* TODO: Filter device by BDA needs to be implemented here */

    /* Will be enabled to TRUE once inquiry busy level has been received */
    btif_dm_inquiry_in_progress = FALSE;
    /* find nearby devices */
    BTA_DmSearch(&inq_params, services, bte_search_devices_evt);//执行搜索
    return BT_STATUS_SUCCESS;
}

 

上面代码的主要做的事情是,设置相关的搜索的参数,然后调用BTA_DmSearch(&inq_params, services, bte_search_devices_evt); 进行搜索。

我们这里再次整理一下 传入BTA_DmSearch的参数:

    inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
    inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
    inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
    inq_params.report_dup = TRUE;
    inq_params.filter_type = BTA_DM_INQ_CLR;//0

    tBTA_SERVICE_MASK services = 0;

    bte_search_devices_evt 是一个回调函数,实现也是在btif_dm.c,最终会被赋值给
    bta_dm_search_cb.p_search_cback = bte_search_devices_evt

 

我们看看BTA_DmSearch具体的实现,

/*******************************************************************************
**
** Function         BTA_DmSearch
**
** Description      This function searches for peer Bluetooth devices. It performs
**                  an inquiry and gets the remote name for devices. Service
**                  discovery is done if services is non zero
**
**
** Returns          void
**
*******************************************************************************/
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{
    tBTA_DM_API_SEARCH    *p_msg;
    if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
    {
        memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
        p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
        memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
        p_msg->services = services;
        p_msg->p_cback = p_cback;
        p_msg->rs_res  = BTA_DM_RS_NONE;
        bta_sys_sendmsg(p_msg);
    }

}

 

这里发现就是组装了一个msg,然后发送给btu 线程处理,这里整理一下发送给btu 线程的参数:

p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ)); 上面赋值的参数
p_msg->services = services;//service = 0
p_msg->p_cback = p_cback;//bte_search_devices_evt

p_msg->rs_res = BTA_DM_RS_NONE;

我们查找一下, BTA_DM_API_SEARCH_EVT 执行的函数:bta_dm_search_start 

/*******************************************************************************
**
** Function         bta_dm_search_start
**
** Description      Starts an inquiry
**
**
** Returns          void
**
*******************************************************************************/
void bta_dm_search_start (tBTA_DM_MSG *p_data)
{
    tBTM_INQUIRY_CMPL result;

#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
    UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->search.num_uuid);
    bta_dm_gattc_register();
#endif
    if (p_bta_dm_cfg->avoid_scatter &&
        (p_data->search.rs_res == BTA_DM_RS_NONE) && bta_dm_check_av(BTA_DM_API_SEARCH_EVT))
    {
        memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH));
        return;
    }

    BTM_ClearInqDb(NULL);
    /* save search params */
    bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
    bta_dm_search_cb.services = p_data->search.services;

#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
    utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid);

    if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 &&
         p_data->search.p_uuid != NULL)//如果在搜索的时候设置了uuid,那么也会将这个值copy给bta_dm_search_cb.p_srvc_uuid
    {
        bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)
        memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len);
    }
#endif
    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);//扫描完成会调用到此函数

    if (result.status != BTM_CMD_STARTED)
    {
        result.num_resp = 0;
        bta_dm_inq_cmpl_cb ((void *)&result);//如果开始失败,直接调用回调函数汇报
    }
}

 

上面的代码执行完,我们看看bta_dm_search_cb的各个结构的值:

 bta_dm_search_cb.p_search_cback = bte_search_devices_evt

bta_dm_search_cb.services = 0;

bta_dm_search_cb.num_uuid  =0;

bta_dm_search_cb.p_srvc_uuid = NULL;

下面继续看看BTM_StartInquiry 的实现,这里可以简单分析一下,传入的三个参数:

第一个参数是,上面组装的inquiry相关的设置。

第二个参数是 扫描到设备调用

第三个参数是 扫描完成 (inquiry complete)的时候调用

/*******************************************************************************
**
** Function         BTM_StartInquiry
**
** Description      This function is called to start an inquiry.
**
** Parameters:      p_inqparms - pointer to the inquiry information
**                      mode - GENERAL or LIMITED inquiry, BR/LE bit mask seperately
**                      duration - length in 1.28 sec intervals (If ‘0‘, the inquiry is CANCELLED)
**                      max_resps - maximum amount of devices to search for before ending the inquiry
**                      filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
**                                         BTM_FILTER_COND_BD_ADDR
**                      filter_cond - value for the filter (based on filter_cond_type)
**
**                  p_results_cb   - Pointer to the callback routine which gets called
**                                upon receipt of an inquiry result. If this field is
**                                NULL, the application is not notified.
**
**                  p_cmpl_cb   - Pointer to the callback routine which gets called
**                                upon completion.  If this field is NULL, the
**                                application is not notified when completed.
** Returns          tBTM_STATUS
**                  BTM_CMD_STARTED if successfully initiated
**                  BTM_BUSY if already in progress
**                  BTM_ILLEGAL_VALUE if parameter(s) are out of range
**                  BTM_NO_RESOURCES if could not allocate resources to start the command
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
                              tBTM_CMPL_CB *p_cmpl_cb)
{
    tBTM_STATUS  status = BTM_CMD_STARTED;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
        p_inq->scan_type = INQ_GENERAL;
...
    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
    p_inq->inqparms = *p_inqparms;//保存inquiry的参数
    /* Initialize the inquiry variables */
    p_inq->state = BTM_INQ_ACTIVE_STATE;//active
    p_inq->p_inq_cmpl_cb = p_cmpl_cb;
    p_inq->p_inq_results_cb = p_results_cb;
    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
    p_inq->inq_active = p_inqparms->mode;//0x11

/* start LE inquiry here if requested */
    if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK))
    {
         if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
                                            p_inqparms->duration)) != BTM_CMD_STARTED)
        {
            BTM_TRACE_ERROR("Err Starting LE Inquiry.");
            p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
        }
#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
        p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;//开始inquiry之后,mode参数置0
#endif
    }

    /* BR/EDR inquiry portion */
...
    /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
    if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type,
                                            &p_inqparms->filter_cond)) != BTM_CMD_STARTED)//这里没有看到BRRDR的扫描,而只有这个清楚过滤的函数,那我可以想象,肯定是这个函数做完之后会自动开始bredr设备的inquiry
        p_inq->state = BTM_INQ_INACTIVE_STATE;
    return (status);
}

 




以上是关于蓝牙inquiry流程之命令下发的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段——git命令操作一个完整流程

VSCode自定义代码片段15——git命令操作一个完整流程

VSCode自定义代码片段15——git命令操作一个完整流程

使用 python 寻找低功耗蓝牙

esp32与jdy蓝牙模块有通信障碍吗

车机蓝牙通话流程分析的流程分析