• 蓝牙BLE设备主机重启回连流程分析


    如果一个BLE设备已经与蓝牙中心设备连接上,那么当中心设备的断电重启,其依然会和配对过的BLE设备连接上,而不需要重新走配对的流程,这个过程叫做回连。

    这篇文章就分析一下当中心设备断电重启之后,其与BLE设备的回连的流程。

    当设备重启之后,蓝牙协议栈以及所有的上层的profile 都要重新进行初始化,之前的配对信息是保存在文件bt_config.conf中,蓝牙起来之后,会去加载这个文件,去解析曾经配对过的设备,对于已经配对过的设备,并且配对信息保持完整,那么就会对该设备发起回连。那么是什么时候进行对bt_config.conf文件的解析的工作的呢?

    蓝牙初始化结束之后,会接着对于各个profile的初始化,当Hid host profile 打开完成之后会对bt_config.conf 文件进行解析并 加载相应的设备信息。我们这里从hid host 打开完成之后开始分析:

    hid host 打开完成之后,会经过btif_hh_upstreams_evt 来上报消息:

    static void btif_hh_upstreams_evt(UINT16 event, char* p_param)
    {
        tBTA_HH *p_data = (tBTA_HH *)p_param;
        btif_hh_device_t *p_dev = NULL;
        int i;
        int len, tmplen;
    
        BTIF_TRACE_DEBUG("%s: event=%s", __FUNCTION__, dump_hh_event(event));
    
        switch (event)
        {
            case BTA_HH_ENABLE_EVT:
                BTIF_TRACE_DEBUG("%s: BTA_HH_ENABLE_EVT: status =%d",__FUNCTION__, p_data->status);
                if (p_data->status == BTA_HH_OK) {
                    btif_hh_cb.status = BTIF_HH_ENABLED;
                    BTIF_TRACE_DEBUG("%s--Loading added devices",__FUNCTION__);
                    /* Add hid descriptors for already bonded hid devices*/
                    btif_storage_load_bonded_hid_info();/*load hid information*/
                }
    ...

    我们继续看btif_storage_load_bonded_hid_info 的实现:

    /*******************************************************************************
    **
    ** Function         btif_storage_load_bonded_hid_info
    **
    ** Description      BTIF storage API - Loads hid info for all the bonded devices from NVRAM
    **                  and adds those devices  to the BTA_HH.
    **
    ** Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
    **
    *******************************************************************************/
    bt_status_t btif_storage_load_bonded_hid_info(void)
    {
        bt_bdaddr_t bd_addr;
        tBTA_HH_DEV_DSCP_INFO dscp_info;
        uint16_t attr_mask;
        uint8_t  sub_class;
        uint8_t  app_id;
    
        memset(&dscp_info, 0, sizeof(dscp_info));
        for (const btif_config_section_iter_t *iter = btif_config_section_begin(); iter != btif_config_section_end(); iter = btif_config_section_next(iter)) {
            const char *name = btif_config_section_name(iter);
            if (!string_is_bdaddr(name))
                continue;
    
            BTIF_TRACE_DEBUG("Remote device:%s", name);
            int value;
            if(btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS)//获取bonded devices信息
            {
                if(btif_config_get_int(name, "HidAttrMask", &value))//保存各种属性
                {
                    attr_mask = (uint16_t)value;
    
                    btif_config_get_int(name, "HidSubClass", &value);
                    sub_class = (uint8_t)value;
    
                    btif_config_get_int(name, "HidAppId", &value);
                    app_id = (uint8_t)value;
    
                    btif_config_get_int(name, "HidVendorId", &value);
                    dscp_info.vendor_id = (uint16_t) value;
    
                    btif_config_get_int(name, "HidProductId", &value);
                    dscp_info.product_id = (uint16_t) value;
    
                    btif_config_get_int(name, "HidVersion", &value);
                    dscp_info.version = (uint8_t) value;
    
                    btif_config_get_int(name, "HidCountryCode", &value);
                    dscp_info.ctry_code = (uint8_t) value;
    
                    value = 0;
                    btif_config_get_int(name, "HidSSRMaxLatency", &value);
                    dscp_info.ssr_max_latency = (uint16_t) value;
    
                    value = 0;
                    btif_config_get_int(name, "HidSSRMinTimeout", &value);
                    dscp_info.ssr_min_tout = (uint16_t) value;
    
                    size_t len = btif_config_get_bin_length(name, "HidDescriptor");
                    if(len > 0)
                    {
                        dscp_info.descriptor.dl_len = (uint16_t)len;
                        dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
                        btif_config_get_bin(name, "HidDescriptor", (uint8_t *)dscp_info.descriptor.dsc_list, &len);
                    }
                    string_to_bdaddr(name, &bd_addr);
                    // add extracted information to BTA HH
                    if (btif_hh_add_added_dev(bd_addr,attr_mask))//addd new devices to btif_hh_cb.added_devices
                    {
                        BTA_HhAddDev(bd_addr.address, attr_mask, sub_class,
                                app_id, dscp_info);//add device to BTA_HH
                    }
                }
            }
            else
            {
    ...
            }
        }
    
        return BT_STATUS_SUCCESS;
    }

     上面的流程很简单,获取已经绑定的设备各种信息,主要有哪些信息呢?这里附上已经绑定设备的保存的信息(BLE):

    [d0:09:09:dc:00:59]
    DevClass = 1344
    AddrType = 0
    Name = RCU
    DevType = 2
    LE_KEY_PENC = 23e2e46363ca4ca562dadc625cc244a41f2225d81a0a8d1924e80110
    LE_KEY_PID = 0000000000000000000000000000000000d00909dc0059
    LE_KEY_PCSRK = 0000000043210c0c420203040505080708090c0101c674e3
    LE_KEY_LENC = 09d6fa5537cb5859f7f9220613104ab0a2f11001
    LE_KEY_LCSRK = 00000000a2f10122d4ecbea1a40287b6eb74c08767855ce2
    LE_KEY_LID = 
    Service = 00001812-0000-1000-8000-00805f9b34fb
    HidReport = 4d2a0201001a4d2a0101011a4d2a0102020e4d2afd01031a4d2a5a01041a4d2a5a02050e
    HidAttrMask = 0
    HidSubClass = 0
    HidAppId = 255
    HidVendorId = 93
    HidProductId = 2
    HidVersion = 0
    HidCountryCode = 0
    HidSSRMaxLatency = 0
    HidSSRMinTimeout = 0
    HidDescriptor = 05010906a1018501050719e029e71500250175019508810295017508810195057501050819012905910295017503910195067508150025a40507190029a48100c005010902a10185020901a1000509190129031500250195037501810295017505810105010930093109381581257f750895038106c0c00612ff0a12ffa10185fd0901750895ff16000026ff00190029ff8100c00612ff0a12ffa101855a0901750895ff16000026ff00190029ff8100950875010508190129089102c0

    上面的主要流程就是解析文件,确认某个设备的确是已经绑定好的设备,那么接下来就要走回连的流程,将该设备加入到白名单中,以及发起相应的连接流程,该流程的入口函数就是BTA_HhAddDev,下面我们继续分析该函数:

    /*******************************************************************************
    **
    ** Function         BTA_HhAddDev
    **
    ** Description      Add a virtually cabled device into HID-Host device list
    **                  to manage and assign a device handle for future API call,
    **                  host applciation call this API at start-up to initialize its
    **                  virtually cabled devices.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class,
                      UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info)
    {
        tBTA_HH_MAINT_DEV    *p_buf;
        UINT16  len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;
    
        p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len);
    
        if (p_buf != NULL)
        {
            memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV));
    
            p_buf->hdr.event            = BTA_HH_API_MAINT_DEV_EVT;//发送此event
            p_buf->sub_event            = BTA_HH_ADD_DEV_EVT;
            p_buf->hdr.layer_specific   = BTA_HH_INVALID_HANDLE;
    
            p_buf->attr_mask            = (UINT16) attr_mask;
            p_buf->sub_class            = sub_class;
            p_buf->app_id               = app_id;
            bdcpy(p_buf->bda, bda);
    
            memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
            if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list)
            {
                p_buf->dscp_info.descriptor.dl_len =  dscp_info.descriptor.dl_len;
                p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1);
                memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len);
            }
            else
            {
    ...
            }
    
            bta_sys_sendmsg(p_buf);//发送消息
        }
    }

     向BTU task 发送了BTA_HH_API_MAINT_DEV_EVT,其中包含的数据部分 都是 上面从文件解析出来的。我们继续看BTA_HH_API_MAINT_DEV_EVT 的处理,关于bta_sys_sendmsg 消息传送机制,这里就不讲了。

    简单看下消息流向:

    /*******************************************************************************
    **
    ** Function         bta_hh_hdl_event
    **
    ** Description      HID host main event handling function.
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
    {
        UINT8           index = BTA_HH_IDX_INVALID;
        tBTA_HH_DEV_CB *p_cb = NULL;
    
        switch (p_msg->event)
        {
    ...
            default:
                /* all events processed in state machine need to find corresponding
                    CB before proceed */
                if (p_msg->event == BTA_HH_API_OPEN_EVT)
                {
                    index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
                }
                else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)//add
                {
                    /* if add device */
                    if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
                    {
                        index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);//find devive control block
                    }
    ...
    p_cb = &bta_hh_cb.kdev[index];
    ...
    bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);//进入状态机

    我们看看状态机的轮转情况:

    /*******************************************************************************
    **
    ** Function         bta_hh_sm_execute
    **
    ** Description      State machine event handling function for HID Host
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
    {
        tBTA_HH_ST_TBL  state_table;
        UINT8           action;
        tBTA_HH         cback_data;
        tBTA_HH_EVT     cback_event = 0;
    
        memset(&cback_data, 0, sizeof(tBTA_HH));
    ...
    {
    ...
            state_table = bta_hh_st_tbl[p_cb->state - 1];
    
            event &= 0xff;
    
            p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;
    
            if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
            {
                (*bta_hh_action[action])(p_cb, p_data);
            }
    ...
        }
    
    return;
    }

    这里的状态机轮转也是 熟悉的套路,开始是 idle状态,bta_hh_st_idle

    /* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST    },

    事件处理之后还是idle 状态,执行的行为是BTA_HH_MAINT_DEV_ACT:

    /*******************************************************************************
    **
    ** Function         bta_hh_maint_dev_act
    **
    ** Description      HID Host maintain device list.
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
    {
        tBTA_HH_MAINT_DEV       *p_dev_info = &p_data->api_maintdev;
        tBTA_HH_DEV_INFO        dev_info ;
        UINT8                   dev_handle;
    
        dev_info.status = BTA_HH_ERR;
        dev_info.handle = BTA_HH_INVALID_HANDLE;
    
        switch (p_dev_info->sub_event)
        {
        case BTA_HH_ADD_DEV_EVT:    /* add a device */
            bdcpy(dev_info.bda, p_dev_info->bda);
            /* initialize callback data */
            if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
            {
    #if (BTA_HH_LE_INCLUDED == TRUE)
                if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr))
                {
                    dev_info.handle   = bta_hh_le_add_device(p_cb, p_dev_info);
                    dev_info.status   = BTA_HH_OK;
                }
                else
    #endif
    
                if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)
                                == HID_SUCCESS)
                ... /*非LE部分处理*/
            }
    ...
    (* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info);//bte_hh_evt--->btif_hh_upstreams_evt

     这里涉及到的回调函数就是bte_hh_evt,其实他最终还是调用btif_hh_upstreams_evt 来完成功能。我们看看其实现:

            case BTA_HH_ADD_DEV_EVT:
                BTIF_TRACE_WARNING("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",p_data->dev_info.status, p_data->dev_info.handle);
                int i;
                for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
                    if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address, p_data->dev_info.bda, 6) == 0) {
                        if (p_data->dev_info.status == BTA_HH_OK) {
                            btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;/*其实就是保存dev_handle*/
                        }
                        else {
        /*错误处理*/
                        }
                        break;
                    }
                }
                break;    

    这个handle 就是我们上面看到的

     dev_info.handle   = bta_hh_le_add_device(p_cb, p_dev_info);

     我们继续看看其干了什么?

    我们先看看他的注释怎么说:

    /*******************************************************************************
    **
    ** Function         bta_hh_le_add_device
    **
    ** Description      Add a LE HID device as a known device, and also add the address
    **                  into back ground connection WL for incoming connection.
    **
    ** Returns          void
    **
    *******************************************************************************/

     添加 该设备地址到whitelist 里面,当设备科连接的时候,就会直接连接上。

    UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info)
    {
        p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
        bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
    
        /* update DI information */
        bta_hh_update_di_info(p_cb,
                              p_dev_info->dscp_info.vendor_id,
                              p_dev_info->dscp_info.product_id,
                              p_dev_info->dscp_info.version,
                              p_dev_info->dscp_info.flag);/*更新设备消息,这些消息都是从bt_config.conf里面load的*/
    
        /* add to BTA device list */
        bta_hh_add_device_to_list(p_cb, p_cb->hid_handle,
                                  p_dev_info->attr_mask,
                                  &p_dev_info->dscp_info.descriptor,
                                  p_dev_info->sub_class,
                                  p_dev_info->dscp_info.ssr_max_latency,
                                  p_dev_info->dscp_info.ssr_min_tout,
                                  p_dev_info->app_id);//添加dscp_info 等消息到p_cb
    
        bta_hh_le_add_dev_bg_conn(p_cb, FALSE);/*add device to WL*/
    
        return p_cb->hid_handle;
    }

     上面代码的核心就是 添加 设备到BG connection,我们具体看实现:

    static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond)
    {
        UINT8           sec_flag=0;
        BOOLEAN         to_add = TRUE;
    
        if (check_bond)
        {
    ...
        }
    
        if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/
            !p_cb->in_bg_conn && to_add)
        {
            /* add device into BG connection to accept remote initiated connection */
            BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE);//gatt_if for hogp 
            p_cb->in_bg_conn = TRUE;
    
            BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL);//send msg the auto type
        }
        return;
    }

    这里分为两个部分来分析:

    1.  BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE);添加设备,并且标志为自动连接
    2. BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL); 开始回连的操作

    我们先看BTA_GATTC_OPen的实现,之前其实有一篇文章讲这个,但是那篇文章主要分析是direct connect,而这里主要分析auto connect:

    void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
                        BOOLEAN is_direct, tBTA_GATT_TRANSPORT transport)
    {
        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_OPEN_EVT;
    
            p_buf->client_if = client_if;
            p_buf->is_direct = is_direct;//false
            p_buf->transport = transport;//LE
            memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
    
    
            bta_sys_sendmsg(p_buf);
        }
        return;
    }

     看看event的处理:

    /*******************************************************************************
    **
    ** Function         bta_gattc_hdl_event
    **
    ** Description      GATT client main event handling function.
    **
    **
    ** Returns          BOOLEAN
    **
    *******************************************************************************/
    BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
    {
    ...
            case BTA_GATTC_API_OPEN_EVT:
                bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    ...

     看看 关于 auto connection的处理:

    /*******************************************************************************
    **
    ** Function         bta_gattc_process_api_open
    **
    ** Description      process connect API request.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg)
    {
        UINT16 event = ((BT_HDR *)p_msg)->event;
        tBTA_GATTC_CLCB *p_clcb = NULL;
        tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);//r is register 
        UNUSED(p_cb);
    
        if (p_clreg != NULL)
        {
            if (p_msg->api_conn.is_direct)
            {
        /*直连的处理*/
            }
            else
            {
                bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
            }
        }
    
    }    

     我们只要是看看  background connection的情况:

    /*******************************************************************************
    **
    ** Function         bta_gattc_init_bk_conn
    **
    ** Description      Process API Open for a background connection
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg)
    {
        tBTA_GATT_STATUS         status = BTA_GATT_NO_RESOURCES;
        UINT16                   conn_id;
        tBTA_GATTC_CLCB         *p_clcb;
        tBTA_GATTC_DATA         gattc_data;
    
        if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE, FALSE))//标记
        {
            /* always call open to hold a connection */
            if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE, p_data->transport))//gatt 连接,auto connection
            {
                uint8_t *bda = (uint8_t *)p_data->remote_bda;
                status = BTA_GATT_ERROR;
            }
            else
            {
                status = BTA_GATT_OK;
    
                /* if is a connected remote device */
                if (GATT_GetConnIdIfConnected(p_data->client_if,
                                              p_data->remote_bda,
                                              &conn_id,
                                              p_data->transport))//走到这里一般只是下发hci的连接命令,并没有连接上
                {
                        /*l连接上的处理*/
                }
            }
        }
    ...
    }
        

    我们看看GATT_Connect 的处理:

    /*******************************************************************************
    **
    ** Function         GATT_Connect
    **
    ** Description      This function initiate a connecttion to a remote device on GATT
    **                  channel.
    **
    ** Parameters       gatt_if: applicaiton interface
    **                  bd_addr: peer device address.
    **                  is_direct: is a direct conenection or a background auto connection
    **
    ** Returns          TRUE if connection started; FALSE if connection start failure.
    **
    *******************************************************************************/
    BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport)
    {
        tGATT_REG    *p_reg;
        BOOLEAN status = FALSE;
    
        GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
    
        /* Make sure app is registered */
        if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
        {
            GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
            return(FALSE);
        }
    
        if (is_direct)
            status = gatt_act_connect (p_reg, bd_addr, transport);
        else
        {
            if (transport == BT_TRANSPORT_LE)
            status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);//update auto connection 相关
            else
            {
                GATT_TRACE_ERROR("Unsupported transport for background connection");
            }
        }
    
        return status;
    
    }

    我们继续看:

    /*******************************************************************************
    **
    ** Function         gatt_update_auto_connect_dev
    **
    ** Description      This function add or remove a device for background connection
    **                  procedure.
    **
    ** Parameters       gatt_if: Application ID.
    **                  add: add peer device
    **                  bd_addr: peer device address.
    **
    ** Returns          TRUE if connection started; FALSE if connection start failure.
    **
    *******************************************************************************/
    BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initator)
    {
        BOOLEAN         ret = FALSE;
        tGATT_REG        *p_reg;
        tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
    
        GATT_TRACE_API ("gatt_update_auto_connect_dev ");
        /* Make sure app is registered */
        if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
        {
            GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered", gatt_if);
            return(FALSE);
        }
    
        if (add)
        {
            ret = gatt_add_bg_dev_list(p_reg, bd_addr, is_initator);/*加入到bg connection*/
    
            if (ret && p_tcb != NULL)/*如果是一个已经连接的设备*/
            {
                /* if a connected device, update the link holding number */
                gatt_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE);
            }
        }
        else
        {
            ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr, is_initator);
        }
        return ret;
    }

     我们继续看gatt_add_bg_dev_list的实现:

    /*******************************************************************************
    **
    ** Function         gatt_add_bg_dev_list
    **
    ** Description      add/remove device from the back ground connection device list
    **
    ** Returns          TRUE if device added to the list; FALSE failed
    **
    *******************************************************************************/
    BOOLEAN gatt_add_bg_dev_list(tGATT_REG *p_reg,  BD_ADDR bd_addr, BOOLEAN is_initator)
    {
        tGATT_IF gatt_if =  p_reg->gatt_if;
        tGATT_BG_CONN_DEV   *p_dev = NULL;
        UINT8       i;
        BOOLEAN      ret = FALSE;
    
        if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
        {
            p_dev = gatt_alloc_bg_dev(bd_addr);
        }
    
        if (p_dev)
        {
            for (i = 0; i < GATT_MAX_APPS; i ++)
            {
                if (is_initator)
                {
                    if (p_dev->gatt_if[i] == gatt_if)
                    {
                        GATT_TRACE_ERROR("device already in iniator white list");
                        return TRUE;
                    }
                    else if (p_dev->gatt_if[i] == 0)
                    {
                        p_dev->gatt_if[i] = gatt_if;
                        if (i == 0)
                            ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr);//update bg connection
                        else
                            ret = TRUE;
                        break;
                    }
                }
                else
                {
                 /*accept role 的处理*/
                }
            }
        }
    
        return ret;
    }

    我们接着看:

    /*******************************************************************************
    **
    ** Function         BTM_BleUpdateBgConnDev
    **
    ** Description      This function is called to add or remove a device into/from
    **                  background connection procedure. The background connection
    *                   procedure is decided by the background connection type, it can be
    *                   auto connection, or selective connection.
    **
    ** Parameters       add_remove: TRUE to add; FALSE to remove.
    **                  remote_bda: device address to add/remove.
    **
    ** Returns          void
    **
    *******************************************************************************/
    BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR   remote_bda)
    {
        BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
        return btm_update_dev_to_white_list(add_remove, remote_bda);//add
    }

    我们继续分析btm_update_dev_to_white_list:

    /*******************************************************************************
    **
    ** Function         btm_update_dev_to_white_list
    **
    ** Description      This function adds or removes a device into/from
    **                  the white list.
    **
    *******************************************************************************/
    BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr)
    {
        tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
    
        if (to_add && p_cb->white_list_avail_size == 0)
        {
            BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
            return FALSE;
        }
    
        if (to_add)
            background_connection_add((bt_bdaddr_t*)bd_addr);//add
        else
            background_connection_remove((bt_bdaddr_t*)bd_addr);//remove
    
        btm_suspend_wl_activity(p_cb->wl_state);//因为当前的WL没有行为,所以do nothing
        btm_enq_wl_dev_operation(to_add, bd_addr);//更新btm_cb.ble_ctr_cb.wl_op_q
        btm_resume_wl_activity(p_cb->wl_state);//恢复WL的行为
        return TRUE;
    }

    上面的逻辑很简单,就是把设备的地址add 到bg connection里面。然后更新whitelist的列表,然后重新调度WL的行为。我们先看看background_connection_add的实现:

    static void background_connection_add(bt_bdaddr_t *address) {
      assert(address);
      background_connections_lazy_init();
      background_connection_t *connection = hash_map_get(background_connections, address);
      if (!connection) {
        connection = osi_calloc(sizeof(background_connection_t));
        connection->address = *address;
        hash_map_set(background_connections, &(connection->address), connection);
      }
    }

    组建了 key value 键值对放置 到 background connection里面。

    我们在看看btm_resume_wl_activity 的实现:

    /*******************************************************************************
    **
    ** Function         btm_resume_wl_activity
    **
    ** Description      This function is to resume white list related activity
    **
    ** Returns          none.
    **
    *******************************************************************************/
    static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state)
    {
        btm_ble_resume_bg_conn();
    
        if (wl_state & BTM_BLE_WL_ADV)
        {
           btm_ble_start_adv();
        }
    
    }

     我们看btm_ble_resume_bg_conn的实现:

    /*******************************************************************************
    **
    ** Function         btm_ble_resume_bg_conn
    **
    ** Description      This function is to resume a background auto connection
    **                  procedure.
    **
    ** Parameters       none.
    **
    ** Returns          none.
    **
    *******************************************************************************/
    BOOLEAN btm_ble_resume_bg_conn(void)
    {
        tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
        BOOLEAN ret = FALSE;
        if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE)
        {
            if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
                ret = btm_ble_start_auto_conn(TRUE);//开始auto connection
                
            if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
                ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);
        }
    
        return ret;
    }

    我们继续往下看btm_ble_start_auto_conn实现:

    /*******************************************************************************
    **
    ** Function         btm_ble_start_auto_conn
    **
    ** Description      This function is to start/stop auto connection procedure.
    **
    ** Parameters       start: TRUE to start; FALSE to stop.
    **
    ** Returns          void
    **
    *******************************************************************************/
    BOOLEAN btm_ble_start_auto_conn(BOOLEAN start)
    {
        tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
        BD_ADDR dummy_bda = {0};
        BOOLEAN exec = TRUE;
        UINT16 scan_int;
        UINT16 scan_win;
        UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
        UINT8 peer_addr_type = BLE_ADDR_PUBLIC;
         
        if (start)
        {
            if ( p_cb->conn_state == BLE_CONN_IDLE )
            {
                exec = btm_execute_wl_dev_operation();//btm_add_dev_to_controller-->btsnd_hcic_ble_add_white_list
            }
    
            if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending()
                && btm_ble_topology_check(BTM_BLE_STATE_INIT))
            {
                p_cb->wl_state  |= BTM_BLE_WL_INIT;
    ...
                scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ?
                                              BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int;
                scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ?
                                              BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win;
    ...
    
                if (!btsnd_hcic_ble_create_ll_conn (scan_int,  /* UINT16 scan_int      */
                                                    scan_win,    /* UINT16 scan_win      */
                                                    0x01,                   /* UINT8 white_list     */
                                                    peer_addr_type,        /* UINT8 addr_type_peer */
                                                    dummy_bda,              /* BD_ADDR bda_peer     */
                                                    own_addr_type,          /* UINT8 addr_type_own */
                                                    BTM_BLE_CONN_INT_MIN_DEF,   /* UINT16 conn_int_min  */
                                                    BTM_BLE_CONN_INT_MAX_DEF,   /* UINT16 conn_int_max  */
                                                    BTM_BLE_CONN_SLAVE_LATENCY_DEF,  /* UINT16 conn_latency  */
                                                    BTM_BLE_CONN_TIMEOUT_DEF,        /* UINT16 conn_timeout  */
                                                    0,                       /* UINT16 min_len       */
                                                    0))                      /* UINT16 max_len       */
                {
                    /* start auto connection failed */
                    exec =  FALSE;
                    p_cb->wl_state &= ~BTM_BLE_WL_INIT;
                }
                else
                {
                    btm_ble_set_conn_st (BLE_BG_CONN);//set BLE connection state
                }
            }
            else
            {
                exec = FALSE;
            }
        }
     ...
        return exec;
    }

    上面执行的任务主要就是把设备加入到controller 的whitelist里面,然后下发LE connect 命令到controller,

    我们简单看下btm_execute_wl_dev_operation:

    /*******************************************************************************
    **
    ** Function         btm_execute_wl_dev_operation
    **
    ** Description      execute the pending whitelist device operation(loading or removing)
    *******************************************************************************/
    BOOLEAN btm_execute_wl_dev_operation(void)
    {
        tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;//btm_enq_wl_dev_operation 更新btm_cb.ble_ctr_cb.wl_op_q 
        UINT8   i = 0;
        BOOLEAN rt = TRUE;
    
        for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++)
        {
            if (p_dev_op->in_use)
            {
                rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr);//下发HCI command
                memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));
            }
            else
                break;
        }
        return rt;
    }

    好了,关于BTA_GATTC_Open  就分析到这里,下面我们看看第二点:

    2.BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL)的流程:

    void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback)
    {
    #if BLE_INCLUDED == TRUE
        tBTA_DM_API_BLE_SET_BG_CONN_TYPE    *p_msg;
    
        if ((p_msg = (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE))) != NULL)
        {
            memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE));
    
            p_msg->hdr.event        = BTA_DM_API_BLE_SET_BG_CONN_TYPE;
            p_msg->bg_conn_type     = bg_conn_type;
            p_msg->p_select_cback   = p_select_cback;
    
            bta_sys_sendmsg(p_msg);
        }
    #endif
    }

    执行的函数是

    void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data)
    {
        BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type,
                             p_data->ble_set_bd_conn_type.p_select_cback);
    }
    BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE   bg_conn_type,
                                 tBTM_BLE_SEL_CBACK   *p_select_cback)
    {
        BOOLEAN started = TRUE;
    
        BTM_TRACE_EVENT ("BTM_BleSetBgConnType ");
        if (!controller_get_interface()->supports_ble())
            return FALSE;
    
        if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type)
        {
            switch (bg_conn_type)
            {
                case BTM_BLE_CONN_AUTO:
                    btm_ble_start_auto_conn(TRUE);
                    break;

    发现这里最终也会执行到btm_ble_start_auto_conn,流程和上面的流程一样,就不赘述。

    关于BLE设备回连的问题就先分析到这里。

  • 相关阅读:
    windows10 应用商店(Microsoft store)进不去
    Java中System函数
    人生的智慧叔本华
    第2关:文本串里单词、数字和符号的识别
    C/C++语言编写PL/0编译程序的词法分析程序
    编译原理实践
    vanced 无法登录问题
    @bizresubmit
    《道德经》全文(翻译 )
    道德经第十章
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9593620.html
Copyright © 2020-2023  润新知