zoukankan      html  css  js  c++  java
  • GATT服务搜索流程(二)

    关于bta_dm_cb.p_sec_cback,这里我们之前已经分析过,他就是bte_dm_evt ,最终调用的函数btif_dm_upstreams_evt :

    static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
    {
        tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param;
        tBTA_SERVICE_MASK service_mask;
        uint32_t i;
        bt_bdaddr_t bd_addr;
    ...
            case BTA_DM_BLE_AUTH_CMPL_EVT:
                BTIF_TRACE_DEBUG("BTA_DM_BLE_AUTH_CMPL_EVT. ");
                btif_dm_ble_auth_cmpl_evt(&p_data->auth_cmpl);
                break;
    ...
    }

    继续看:

    /*******************************************************************************
    **
    ** Function         btif_dm_ble_auth_cmpl_evt
    **
    ** Description      Executes authentication complete event in btif context
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
    {
        /* Save link key, if not temporary */
        bt_bdaddr_t bd_addr;
        bt_status_t status = BT_STATUS_FAIL;
        bt_bond_state_t state = BT_BOND_STATE_NONE;
    
        bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
        if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) )
        {
            /* store keys */
        }
        if (p_auth_cmpl->success)
        {
            status = BT_STATUS_SUCCESS;
            state = BT_BOND_STATE_BONDED;
            int addr_type;
            bt_bdaddr_t bdaddr;
            bdcpy(bdaddr.address, p_auth_cmpl->bd_addr);
            if (btif_storage_get_remote_addr_type(&bdaddr, &addr_type) != BT_STATUS_SUCCESS)
                btif_storage_set_remote_addr_type(&bdaddr, p_auth_cmpl->addr_type);
    
            /* Test for temporary bonding */
            if (btm_get_bond_type_dev(p_auth_cmpl->bd_addr) == BOND_TYPE_TEMPORARY) {
    ...
            } else {
                btif_dm_save_ble_bonding_keys();//保存key 到config
            BTA_GATTC_Refresh(bd_addr.address);//refresh
            btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);//继续获取服务
        }
        else
        {
    ...
        }
        bond_state_changed(status, &bd_addr, state);//上报状态
    }

    btif_dm_save_ble_bonding_keys 很简单,就是保存SMP相关的key 到config文件,bond_state_changed也很简单,就是 上报状态,下面着重看看BTA_GATTC_Refresh和btif_dm_get_remote_services_by_transport

    首先看看BTA_GATTC_Refresh:简单的地方会一带而过:

    /*******************************************************************************
    **
    ** Function         BTA_GATTC_Refresh
    **
    ** Description      Refresh the server cache of the remote device
    **
    ** Parameters       remote_bda: remote device BD address.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void BTA_GATTC_Refresh(BD_ADDR remote_bda)
    {
        tBTA_GATTC_API_OPEN  *p_buf;
    
        if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL)
        {
            p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT;//发送事件
    
            memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
    
            bta_sys_sendmsg(p_buf);
        }
        return;
    }

    处理这个事件的函数是:  bta_gattc_process_api_refresh:

    /*******************************************************************************
    **
    ** Function         bta_gattc_process_api_refresh
    **
    ** Description      process refresh API to delete cache and start a new discovery
    **                  if currently connected.
    **
    ** Returns          None.
    **
    *******************************************************************************/
    void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg)
    {
        tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_conn.remote_bda);//查找cache
        tBTA_GATTC_CLCB      *p_clcb = &bta_gattc_cb.clcb[0];
        BOOLEAN         found = FALSE;
        UINT8           i;
        UNUSED(p_cb);
    
        if (p_srvc_cb != NULL)//找到cache
        {
            /* try to find a CLCB */
            if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0)
            {
                for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++)
                {
                    if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb)
                    {
                        found = TRUE;//找到对应的clcb
                        break;
                    }
                }
                if (found)
                {
                    bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);//继续搜索
                    return;
                }
            }
            /* in all other cases, mark it and delete the cache */
            if (p_srvc_cb->p_srvc_cache != NULL)//没有找到对应clcb,那么这个cache也没有存在的价值了,直接删除
            {
                while (!GKI_queue_is_empty(&p_srvc_cb->cache_buffer))
                    GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer));
    
                p_srvc_cb->p_srvc_cache = NULL;
            }
        }
        /* used to reset cache in application */
        bta_gattc_co_cache_reset(p_msg->api_conn.remote_bda);//删除/data/misc/bluedroid/gatt_cache_* 文件
    
    }

     这个函数的作用:

    1. 如果找到cache,并且找到clcb,那么继续进行服务搜索,
    2. 否则删除cache,包括data/misc/bluedroid/下面的文件,重新开始。

    我们这里只分析第一次配对之后的服务搜索。

    下面继续看btif_dm_get_remote_services_by_transport :

    /*******************************************************************************
    **
    ** Function         btif_dm_get_remote_services_transport
    **
    ** Description      Start SDP to get remote services by transport
    **
    ** Returns          bt_status_t
    **
    *******************************************************************************/
    bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t *remote_addr, const int transport)
    {
        /* Set the mask extension */
        tBTA_SERVICE_MASK_EXT mask_ext;
        mask_ext.num_uuid = 0;//搜索全部服务
        mask_ext.p_uuid = NULL;
        mask_ext.srvc_mask = BTA_ALL_SERVICE_MASK;
    
        BTA_DmDiscoverByTransport(remote_addr->address, &mask_ext,
                       bte_dm_search_services_evt, TRUE, transport);
    //bte_dm_search_services_evt回调函数
        return BT_STATUS_SUCCESS;
    }

    看看BTA_DmDiscoverByTransport:

    /*******************************************************************************
    **
    ** Function         BTA_DmDiscoverByTransport
    **
    ** Description      This function does service discovery on particular transport
    **                  for services of a
    **                  peer device. When services.num_uuid is 0, it indicates all
    **                  GATT based services are to be searched; otherwise a list of
    **                  UUID of interested services should be provided through
    **                  p_services->p_uuid.
    **
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void BTA_DmDiscoverByTransport(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services,
                        tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search,
                        tBTA_TRANSPORT transport)
    {
    #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
        bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, transport);
    #endif
    }

    继续往下看:

    /*******************************************************************************
    **
    ** Function         bta_dm_discover_send_msg
    **
    ** Description      This function send discover message to BTA task.
    **
    ** Returns          void
    **
    *******************************************************************************/
    #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
    static void bta_dm_discover_send_msg(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services,
                        tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search,
                        tBTA_TRANSPORT transport)
    {
        tBTA_DM_API_DISCOVER    *p_msg;
        UINT16  len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) +
                                    sizeof(tBT_UUID) * p_services->num_uuid) :
                                    sizeof(tBTA_DM_API_DISCOVER);
    
        if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(len)) != NULL)
        {
            memset(p_msg, 0, len);
    
            p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;//发送该事件
            bdcpy(p_msg->bd_addr, bd_addr);
            p_msg->p_cback = p_cback;
            p_msg->sdp_search = sdp_search;
            p_msg->transport    = transport;

    这里发现他发送了事件到BTA task进行搜索的流程:函数功能正如注释“This function send discover message to BTA task.”

    最终BTA执行的函数是:

    /*******************************************************************************
    **
    ** Function         bta_dm_discover
    **
    ** Description      Discovers services on a remote device
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_dm_discover (tBTA_DM_MSG *p_data)
    {
    #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
        UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->discover.num_uuid);
    #endif
            /* save the search condition */
        bta_dm_search_cb.services = p_data->discover.services;
    
    #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
        bta_dm_gattc_register();
        utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid);
        if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 &&
            p_data->discover.p_uuid != NULL)
        {
            if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL)
            {
                p_data->discover.p_cback(BTA_DM_DISC_CMPL_EVT, NULL);
                return;
            }
            memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len);
        }
        bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
    #endif
    
        bta_dm_search_cb.p_search_cback = p_data->discover.p_cback;
        bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
        bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;//mask
        bta_dm_search_cb.service_index = 0;
        bta_dm_search_cb.services_found = 0;
        bta_dm_search_cb.peer_name[0] = 0;
        bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
        bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead (p_data->discover.bd_addr);
        bta_dm_search_cb.transport = p_data->discover.transport;
    
        bta_dm_search_cb.name_discover_done = FALSE;
        memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID));
        bta_dm_discover_device(p_data->discover.bd_addr);//action
    }

    这里注意bta_dm_search_cb.p_search_cback = p_data->discover.p_cback =  bte_dm_search_services_evt,后期搜索到结果的相关的处理,肯定会调用到这个回调函数。这里要非常注意的是当进行服务搜索的时候bta_dm_search_cb.p_search_cback =  bte_dm_search_services_evt,当进行设备搜索的时候bta_dm_search_cb.p_search_cback = bte_search_devices_evt,注意不要搞混。

    bta_dm_discover 主要做了三件事:

    1. bta_dm_gattc_register ,这里其实在蓝牙enable的时候就已经注册好了,关于该函数分析:bta_dm_gattc_register
    2. 组建bta_dm_search_cb 结构
    3. bta_dm_discover_device 

    下面分别来分析:

     下面来看一下bta_dm_discover_device :

    这是一个 服务发现的总的函数接口,涉及 到BREDR 以及BLE 的部分,我们这里只关注BLE的情况:

                if (transport == BT_TRANSPORT_LE)
                {
                    if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK)
                    {
                        //set the raw data buffer here
                        memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
                        bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf;
    
                        bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF;
                        bta_dm_search_cb.ble_raw_used = 0;
    
                        /* start GATT for service discovery */
                        btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);//进行GATT 搜索
                        return;
                    }
                }

     继续看btm_dm_start_gatt_discovery:

    /*******************************************************************************
    **
    ** Function         btm_dm_start_gatt_discovery
    **
    ** Description      This is GATT initiate the service search by open a GATT connection
    **                  first.
    **
    ** Parameters:
    **
    *******************************************************************************/
    void btm_dm_start_gatt_discovery (BD_ADDR bd_addr)
    {
        bta_dm_search_cb.gatt_disc_active = TRUE;
    
        /* connection is already open */
        if (bdcmp(bta_dm_search_cb.pending_close_bda, bd_addr) == 0 &&
            bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID)
        {
            memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN);
            bta_sys_stop_timer(&bta_dm_search_cb.gatt_close_timer);
            btm_dm_start_disc_gatt_services(bta_dm_search_cb.conn_id);//如果已经打开,那么直接进行搜索
        }
        else
            BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, TRUE, BTA_GATT_TRANSPORT_LE);//打开GATT 通道
    }

    这是一个服务搜索的函数,但是当 GATT 通道没有打开的时候,我们只要调用 BTA_GATTC_Open就可以了,那说明这个函数在打开GATT通道之后会自动进行搜索。

    那这里关于BTA_GATTC_Open的流程分析,请参考:这里


  • 相关阅读:
    Info.plist的秘密(raywenderlich笔记)
    我所理解的性能测试中负载测试与压力测试的区别
    seo优化
    localStorage,sessionStorage那些事儿
    浏览器cookie那些事儿
    JavaScript--Ajax请求
    javascript-理解原型、原型链
    React Native:从入门到原理
    知道这 20 个正则表达式,能让你少写 1,000 行代码
    程序猿进化必读:让App的运行速度与响应速度趋于一流(iOS)
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9343495.html
Copyright © 2011-2022 走看看