如果一个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, , 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 = ;
btif_config_get_int(name, "HidSSRMaxLatency", &value);
dscp_info.ssr_max_latency = (uint16_t) value; value = ;
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 > )
{
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:::dc::]
DevClass =
AddrType =
Name = RCU
DevType =
LE_KEY_PENC = 23e2e46363ca4ca562dadc625cc244a41f2225d81a0a8d1924e80110
LE_KEY_PID = 0000000000000000000000000000000000d00909dc0059
LE_KEY_PCSRK = 0000000043210c0c420203040505080708090c0101c674e3
LE_KEY_LENC = 09d6fa5537cb5859f7f9220613104ab0a2f11001
LE_KEY_LCSRK = 00000000a2f10122d4ecbea1a40287b6eb74c08767855ce2
LE_KEY_LID =
Service = ----00805f9b34fb
HidReport = 4d2a0201001a4d2a0101011a4d2a0102020e4d2afd01031a4d2a5a01041a4d2a5a02050e
HidAttrMask =
HidSubClass =
HidAppId =
HidVendorId =
HidProductId =
HidVersion =
HidCountryCode =
HidSSRMaxLatency =
HidSSRMinTimeout =
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, , 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 != && 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 + );
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 = ; memset(&cback_data, , sizeof(tBTA_HH));
...
{
...
state_table = bta_hh_st_tbl[p_cb->state - ]; 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 = ; i < BTIF_HH_MAX_ADDED_DEV; i++) {
if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address, p_data->dev_info.bda, ) == ) {
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=;
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 = ; 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] == )
{
p_dev->gatt_if[i] = gatt_if;
if (i == )
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 == )
{
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 = {};
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 */
, /* UINT16 min_len */
)) /* 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 = ;
BOOLEAN rt = TRUE; for (i = ; 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, , 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, , 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设备回连的问题就先分析到这里。

蓝牙BLE设备主机重启回连流程分析的更多相关文章

  1. 蓝牙BLE设备断线回连分析

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

  2. Android-低功耗蓝牙(BLE)-客户端(主机/中心设备)和服务端(从机/外围设备)

    一.Android 低功耗蓝牙(BLE)的API简介 从Android 4.3(API 18)才支持低功耗蓝牙(Bluetooth Low Energy, BLE)的核心功能, BLE蓝牙协议是GAT ...

  3. IOS 可以连接 蓝牙BLE设备,但是无法发现服务(原创)

    注:转载请标明文章来源,感谢支持作者劳动! 一.问题描述 用iphone手机上的nRF connect软件调试蓝牙通信. 1.nRF52蓝牙demo电路板,烧录一个SDK的程序,iphone手机可以成 ...

  4. Android 4.4.2上与BLE 蓝牙锁设备的通讯

    Android从4.3(Api level 18)开始支持BLE的开发,本文记录了Android 4.4.2设备与BLE设备通讯的流程. 权限需求: <uses-permission andro ...

  5. ESP32:蓝牙BLE控制M3508电机

    ESP32:蓝牙BLE控制M3508电机 先给各位朋友拜个年,祝大家新春快乐,事事顺利,身体健康啊! 还是熟悉的3508,内容概述: ESP32主控 蓝牙BLE通信 使用实时系统(FreeRTOS) ...

  6. Android BLE设备蓝牙通信框架BluetoothKit

    BluetoothKit是一款功能强大的Android蓝牙通信框架,支持低功耗蓝牙设备的连接通信.蓝牙广播扫描及Beacon解析. 关于该项目的详细文档请关注:https://github.com/d ...

  7. Android 6.0 Kotlin 蓝牙BLE扫描(改为指定时间没有发现新设备后停止扫描使用interface)

    package com.arci.myapplication import android.os.Bundleimport android.support.design.widget.Snackbar ...

  8. 蓝牙BLE实用教程

    蓝牙BLE实用教程 Bluetooth BLE 欢迎使用 小书匠(xiaoshujiang)编辑器,您可以通过 设置 里的修改模板来改变新建文章的内容. 1.蓝牙BLE常见问答 Q: Smart Re ...

  9. 蓝牙BLE实用教程(转载)

    欢迎使用 小书匠(xiaoshujiang)编辑器,您可以通过 设置 里的修改模板来改变新建文章的内容. 1.蓝牙BLE常见问答 Q: Smart Ready 和 Smart 以及传统蓝牙之间是什么关 ...

随机推荐

  1. Android 底部导航栏实现一 Fragment-replace

    [效果](这里下载的软件收费的试用有水印) [推荐]这里推荐一个图标网http://iconfont.cn/.以上图标来自此图标网 [项目结构] [步骤] ①创建布局文件,写底部导航栏 <?xm ...

  2. Play 2D games on Pixel running Android Nougat (N7.1.2) with Daydream View VR headset

  3. Apache Windows下Apache安装步骤

    1.apache官网下载Apache HTTP Server服务器 我相信有些朋友刚用apache服务器时,都希望从官网上下载,而面对着官网上众多的项目和镜像以及目录,也许有点茫然.下面是具体步骤: ...

  4. turnserver 配置说明记录

    coTurn工程提供了较完整的STUN和TURN服务,记录其主要的命令行参数配置说明 针对TURN/STUN服务进程turnserver.exe的使用参数做简单说明 -L 监听的IP地址 -p 监听端 ...

  5. SQL Server中通用数据库角色权限处理

    SQL Server中通用数据库角色权限处理   最近和同事在做数据库权限清理的事情,主要是删除一些账号:取消一些账号的较大的权限等,例如,有一些有db_owner权限,我们取消账号的数据库角色db_ ...

  6. SQL Server OPTION (OPTIMIZE FOR UNKNOWN) 测试总结

      关于SQL Server的查询提示OPTION (OPTIMIZE FOR UNKNOWN) ,它是解决参数嗅探的方法之一. 而且对应的SQL语句会缓存,不用每次都重编译.关键在于它的执行计划的准 ...

  7. 洗礼灵魂,修炼python(75)--全栈项目实战篇(3)—— 账户注册登录管理系统

    要求: 1.系统可以创建用户和登录用户,根据用户的输入不同,做出不同的反应(创建还是登录) 2.创建用户不能创建已存在的用户名 3.登录用户的操作最多只能有三次,超过三次冻结账户,每使用一次提示用户还 ...

  8. 自动化测试基础篇--Selenium中JS处理浏览器弹窗

    摘自https://www.cnblogs.com/sanzangTst/p/7692454.html 浏览器弹窗: 现在大多数网站都会使用自定义弹窗,使用Selenium自带的方法暂时处理不了,这时 ...

  9. Scrapy at a glance预览

    1.安装scrapy 2.创建爬虫项目 scrapy startproject test_scrapy 3.创建quotes_spider.py文件4.复制下面代码到quotes_spider.py文 ...

  10. jQuery入门(1)

    1.了解jQuery与JavaScript的区别 css --你的长相啦 Html --躯干 js --运动神经 jQuery就是对JavaScript的一个拓展,封装,就是让JavaScript更好 ...