zoukankan      html  css  js  c++  java
  • 蓝牙BLE设备断线回连分析

    在 文章中分析了Hogp的连接的流程 ,这里分析一下回连的流程.

    在使用ble设备的过程中,我们发现当设备和主机配对之后,如果没有解除配对,那么即便设备和主机断开,那么也是可以重新连接而不需要重新走配对的流程,这里的分析的源代码是Android7.0 .

    回连的大概的流程是:hogp 连接完成之后,会把当前的device 加入到whitelist里面.,标记为可以回连的设备.当设备和主机断开的时候,主机会根据whitelist里面的设备来进行回连.

    这里我们从hogp连接流程中将device加入到 whitelist的流程来开始分析.

    /*******************************************************************************
    **
    ** Function         bta_hh_le_open_cmpl
    **
    ** Description      HID over GATT connection sucessfully opened
    **
    *******************************************************************************/
    void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB *p_cb)
    {
        if ( p_cb->disc_active == BTA_HH_LE_DISC_NONE)
        {
            bta_hh_le_register_input_notif(p_cb, p_cb->mode, TRUE);
            bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
    
    #if (BTA_HH_LE_RECONN == TRUE)
            if (p_cb->status == BTA_HH_OK)
            {
                bta_hh_le_add_dev_bg_conn(p_cb, TRUE);//加入到bg connection 中
            }
    #endif
        }
    }

    继续看bta_hh_le_add_dev_bg_conn 的实现:

    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) 
        { /* start reconnection if remote is a bonded device */ /* verify bond */ 
            BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE);
            if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) == 0) 
                to_add = FALSE;//如果没有完成安全认证,那么不会加入到whitelist里面  }
            if (!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); 
                p_cb->in_bg_conn = TRUE;//标记为in_bg_conn 为true 
                BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL); 
         } 
            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_api.c

    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 =
           (tBTA_GATTC_API_OPEN *) osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
    
        p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;
        p_buf->client_if = client_if;
        p_buf->is_direct = is_direct;
        p_buf->transport = transport;
        memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
    
        bta_sys_sendmsg(p_buf);
    }

    这里不多说,  bta_gattc_hdl_event  -->BTA_GATTC_API_OPEN_EVT ->bta_gattc_process_api_open 我们直接看实际处理的函数 

    bta_gattc_act.c

    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);
        UNUSED(p_cb);
    
        if (p_clreg != NULL)
        {
            if (p_msg->api_conn.is_direct)//is_direct是false
            {
                if ((p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if,
                                                        p_msg->api_conn.remote_bda,
                                                        p_msg->api_conn.transport)) != NULL)
                {
                    bta_gattc_sm_execute(p_clcb, event, p_msg);
                }
                else
                {
                    APPL_TRACE_ERROR("No resources to open a new connection.");
    
                    bta_gattc_send_open_cback(p_clreg,
                                              BTA_GATT_NO_RESOURCES,
                                              p_msg->api_conn.remote_bda,
                                              BTA_GATT_INVALID_CONN_ID,
                                              p_msg->api_conn.transport, 0);
                }
            }
            else
            {
                bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);//init bg conn
            }
        }
    
    }

    继续看bta_gattc_init_bk_conn 

    /*******************************************************************************
    **
    ** 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))//标记p_bg_tck->cif_mask ,暂时没看出来用处
        {
            /* always call open to hold a connection */
            if (!GATT_Connect(p_data->client_if, p_data->remote_bda, false, p_data->transport, false))//执行gatt_connect,注意这里的参数是no_direct
            {
            /*出错处理*/
            }
            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))
                {
                    if ((p_clcb = bta_gattc_find_alloc_clcb(p_data->client_if, p_data->remote_bda,
                        BTA_GATT_TRANSPORT_LE)) != NULL)
                    {
                        gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
    
                        /* open connection */
                        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);//当前就是connection状态,BTA_GATTC_IGNORE
                        status = BTA_GATT_OK;
                    }
                }
            }
        }
    ...
    }

    上面的重点是 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, BOOLEAN opportunistic)
    {
        tGATT_REG    *p_reg;
        BOOLEAN status = FALSE;
    
        /* 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)//定向是直接建立连接,否则加入whitelist
            status = gatt_act_connect (p_reg, bd_addr, transport, opportunistic);
        else
        {
            if (transport == BT_TRANSPORT_LE)
            status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);
            else
            {
                GATT_TRACE_ERROR("Unsupported transport for background connection");
            }
        }
    
        return status;
    
    }

     我们这里执行的是gatt_update_auto_connect_dev 

    /*******************************************************************************
    **
    ** 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);
    
        if (add)
        {
            ret = gatt_add_bg_dev_list(p_reg, bd_addr, is_initator);//添加到whitelist
            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_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE); 

    /*******************************************************************************
    **
    ** Function         gatt_update_app_use_link_flag
    **
    ** Description      Update the application use link flag and optional to check the acl link
    **                  if the link is up then set the idle time out accordingly
    **
    ** Returns          void.
    **
    *******************************************************************************/
    void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add,
                                       BOOLEAN check_acl_link)
    {
        // If we make no modification, i.e. kill app that was never connected to a device,
        // skip updating the device state.
        if (!gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add))//gatt_cb->p_tcb->app_hold_link[i] ==  gatt_if
            return;
    
        if (!check_acl_link ||
                p_tcb->att_lcid != L2CAP_ATT_CID || /* only update link idle timer for fixed channel */
                (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) == GATT_INVALID_ACL_HANDLE)) {
            return;
        }
    
        if (is_add) {
            /* acl link is connected disable the idle timeout */
            GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);//设置timeout为无限长
        } else {
            if (!gatt_num_apps_hold_link(p_tcb)) {
                /* acl link is connected but no application needs to use the link
                   so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
                GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
                                    p_tcb->transport);//如果是remove,那么设置timeout为1s
            }
        }
    }

     下面继续看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);//未找到则分配,此结构为gatt_cb.bgconn_dev
        }
    
        if (p_dev)
        {
            for (i = 0; i < GATT_MAX_APPS; i ++)
            {
                if (is_initator)//主机端一般都是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;
                            ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr);//update background connection
                        break;
                    }
                }
    
            }
        }
    
        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);
    }
    /*******************************************************************************
    **
    ** 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)//判断whitelist容量
        {
            BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
            return FALSE;
        }
    
        if (to_add)
            background_connection_add((bt_bdaddr_t*)bd_addr);//添加到background_connections
        else
            background_connection_remove((bt_bdaddr_t*)bd_addr);
    
        btm_suspend_wl_activity(p_cb->wl_state);
        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);
        return TRUE;
    }

    这里简单看下bg connection的管理:用hash map 来实现的,

    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);
      }
    }

    到这里 已经将设备添加到bg connection里面了,

    下面继续看 

    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 =
            (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *)osi_calloc(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
    }

    发出BTA_DM_API_BLE_SET_BG_CONN_TYPE 信息.

    相应的处理函数:

    /*******************************************************************************
    **
    ** Function         BTM_BleSetBgConnType
    **
    ** Description      This function is called to set BLE connectable mode for a
    **                  peripheral device.
    **
    ** Parameters       bg_conn_type: it can be auto connection, or selective connection.
    **                  p_select_cback: callback function when selective connection procedure
    **                              is being used.
    **
    ** Returns          void
    **
    *******************************************************************************/
    BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE   bg_conn_type,
                                 tBTM_BLE_SEL_CBACK   *p_select_cback)
    {
        BOOLEAN started = TRUE;
    
        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;
    ...

    if (started)
    btm_cb.ble_ctr_cb.bg_conn_type = bg_conn_type;  //更新 bg_conn_type = BTM_BLE_CONN_AUTO = 1

     

     我们继续看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)//true
        {
    
            if ( p_cb->conn_state == BLE_CONN_IDLE )//未 正在连接状态,当前状态是 BLE_CONN_IDLE
            {
                exec = btm_execute_wl_dev_operation();//add to whitelist
            }
    
    /*background_connections_pending 此条件判断不符,因为当前ble 设备和主机已经连接,故不会去下0x200d*/
            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  */
    #ifdef BLUETOOTH_RTK
                                                    BTM_BLE_CONN_INT_MIN_DEF,
    #else
                                                    BTM_BLE_CONN_INT_MAX_DEF,   /* UINT16 conn_int_max  */
    #endif
                                                    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);
                }
            }
            else
            {
                exec = FALSE;
            }
        }
        else  //false 状态
        {
            if (p_cb->conn_state == BLE_BG_CONN)
            {
                btsnd_hcic_ble_create_conn_cancel();
                btm_ble_set_conn_st (BLE_CONN_CANCEL);
                p_cb->wl_state &= ~BTM_BLE_WL_INIT;
            }
            else
            {
                exec = FALSE;
            }
        }
        return exec;
    }

     在上面的 btm_execute_wl_dev_operation  流程中,会将设备加入到whitelist里面去,对应的HCI 命令是Command: HCI_LE_Add_Device_To_White_List 

    到目前为止,已经将设备加入到bg connection里面以及contrller的 whitelist里面了.

    当设备与主机端断开连接,那么主机端应该主动发起,回连,.

    下面我们简单看一下,当设备与主机端断开的时候,主机端的行为.

    /*******************************************************************************
    **
    ** Function         btu_hcif_disconnection_comp_evt
    **
    ** Description      Process event HCI_DISCONNECTION_COMP_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_disconnection_comp_evt (UINT8 *p)
    {
        UINT16  handle;
        UINT8   reason;
    
        ++p;
        STREAM_TO_UINT16 (handle, p);
        STREAM_TO_UINT8  (reason, p);
    
        handle = HCID_GET_HANDLE (handle);
    
        l2c_link_hci_disc_comp (handle, reason);//L2cap 相关的链接处理
    
        /* Notify security manager */
        btm_sec_disconnected (handle, reason);//security manager的处理
    }

     我们主要看一下btm_sec_disconnected的处理:

    这里挑重点;

    void btm_sec_disconnected (UINT16 handle, UINT8 reason)
    {
        tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev_by_handle (handle);
        UINT8             old_pairing_flags = btm_cb.pairing_flags;
        int               result = HCI_ERR_AUTH_FAILURE;
        tBTM_SEC_CALLBACK   *p_callback = NULL;
        tBT_TRANSPORT      transport = BT_TRANSPORT_BR_EDR;
    
        btm_acl_resubmit_page();//如果有挂起的连接请求,那么继续
    
        transport  = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR: BT_TRANSPORT_LE;
    
        p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
    
        /* clear unused flags */
        p_dev_rec->sm4 &= BTM_SM4_TRUE;
    
        uint8_t *bd_addr = (uint8_t *)p_dev_rec->bd_addr;
    
        /* If we are in the process of bonding we need to tell client that auth failed */
        if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
             && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0))
        {
            ...
        }
    
    #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
        btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, HCI_SUCCESS);//当link状态改变时更新le设备应该做的行为
        /* see sec_flags processing in btm_acl_removed */
    
        if (transport == BT_TRANSPORT_LE)/*清掉各种flag*/
        {
            p_dev_rec->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
            p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED|BTM_SEC_LE_ENCRYPTED);
            p_dev_rec->enc_key_size = 0;
        }
        else
    #endif
        {
    ...
        }
    
    ...
        p_dev_rec->sec_state  = BTM_SEC_STATE_IDLE;
        p_dev_rec->security_required = BTM_SEC_NONE;
    
        p_callback = p_dev_rec->p_callback;
    
        /* if security is pending, send callback to clean up the security state */
        if(p_callback)
        {
            p_dev_rec->p_callback = NULL; /* when the peer device time out the authentication before
                                             we do, this call back must be reset here */
            (*p_callback) (p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, BTM_ERR_PROCESSING);
        }
    
        BTM_TRACE_EVENT("%s after update sec_flags=0x%x", __func__, p_dev_rec->sec_flags);
    }

    这里我们只要专注于 btm_ble_update_mode_operation 就好.

    /*******************************************************************************
    **
    ** Function         btm_ble_update_mode_operation
    **
    ** Description      This function update the GAP role operation when a link status
    **                  is updated.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bd_addr, UINT8 status)
    {
        if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT)
        {
    ...
        }
    
        if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE)
        {
    ...
        }
    
        /* when no connection is attempted, and controller is not rejecting last request
           due to resource limitation, start next direct connection or background connection
           now in order */
        if (btm_ble_get_conn_st() == BLE_CONN_IDLE && status != HCI_ERR_HOST_REJECT_RESOURCES &&
            !btm_send_pending_direct_conn())//当没有direct请求的时候
        {
             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)//BTM_BLE_CONN_AUTO前面已经设置过了
                ret = btm_ble_start_auto_conn(TRUE);
    
            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,上面分析了当设备仍然和主机有连接的情况,当前设备已经断开,是真正需要回连的时候,

    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();//这里不会重复添加whitelist, memset.
            }
         /*这里会发现 bg connection 里面还有 设备需要回连*/
            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;
              /*发送0x200d到controller*/
                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_MIN_DEF,
                                                    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);//设置连的状态
                }
            }
            else
            {
                exec = FALSE;
            }
        }
        else
        {
            if (p_cb->conn_state == BLE_BG_CONN)
            {
                btsnd_hcic_ble_create_conn_cancel();
                btm_ble_set_conn_st (BLE_CONN_CANCEL);
                p_cb->wl_state &= ~BTM_BLE_WL_INIT;
            }
            else
            {
                BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", p_cb->conn_state);
                exec = FALSE;
            }
        }
        return exec;
    }    

    host端向controller端发起了连接的请求,也即回连请求,.

    对于Le 设备的回连,暂且分析到这里.


  • 相关阅读:
    A1023 Have Fun with Numbers (20分)(大整数四则运算)
    A1096 Consecutive Factors (20分)(质数分解)
    A1078 Hashing (25分)(哈希表、平方探测法)
    A1015 Reversible Primes (20分)(素数判断,进制转换)
    A1081 Rational Sum (20分)
    A1088 Rational Arithmetic (20分)
    A1049 Counting Ones (30分)
    A1008 Elevator (20分)
    A1059 Prime Factors (25分)
    A1155 Heap Paths (30分)
  • 原文地址:https://www.cnblogs.com/libs-liu/p/10138322.html
Copyright © 2011-2022 走看看