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 设备的回连,暂且分析到这里.


  • 相关阅读:
    SocketChannel 例子(转)
    多态(Polymorphism)的实现机制(上)--C++篇
    多态(Polymorphism)的实现机制(下)--Java篇
    java volatitle 多线程问题
    线程BlockingQueue (转)
    java 多态,和方法覆盖分析(转)
    MFC 调试技巧
    strlen与sizeof区别(转载)
    杭电1048
    杭电2013
  • 原文地址:https://www.cnblogs.com/libs-liu/p/10138322.html
Copyright © 2011-2022 走看看