1 描述
一个设备可以对正在广播的设备发起连接。
2 Message Sequence Charts
3 Zephyr Bluetooth Stack流程
1.bt_conn_create_le: 设置连接状态为BT_CONN_CONNECT_SCAN,开启scan(LE_Set_Scan_Enable)
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, const struct bt_le_conn_param *param)
conn = bt_conn_lookup_addr_le(peer); /* 查找是否已经对同一地址发起过连接 */
if (conn) return conn;// 已有连接,直接返回,此处有省略
conn = bt_conn_add_le(peer); /* 发起连接的是个新地址 */
bt_conn_set_param_le(conn, param);
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);// old_state=BT_CONN_DISCONNECTED
bt_le_scan_update(true);
start_le_scan(BT_HCI_LE_SCAN_PASSIVE, interval, window);
bt_hci_cmd_send(BT_HCI_OP_LE_SET_SCAN_PARAM, buf);
net_buf_put(&bt_dev.cmd_tx_queue, buf); // 通过tx线程发送
set_le_scan_enable(BT_HCI_LE_SCAN_ENABLE);
bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_SCAN_ENABLE, buf, NULL);
net_buf_put(&bt_dev.cmd_tx_queue, buf); // 通过tx thread发送
2.LE_Set_Scan_Enable对应的event为LE Advertising Report event,等收到广播后检查pendding的连接,如果连接的状态为 BT_CONN_CONNECT_SCAN,则发起连接(LE_Create_Connection)
static void rx_thread(void *p1, void *p2, void *p3)
bt_recv(buf);
hci_event(buf);
hci_le_meta_event(buf);
le_adv_report(buf); // LE Advertising Report event
check_pending_conn(&id_addr, &info->addr, info->evt_type);
/* 查找是否已有处于BT_CONN_CONNECT_SCAN的且目的地址为id_addr的连接*/
conn = bt_conn_lookup_state_le(id_addr, BT_CONN_CONNECT_SCAN);
hci_le_create_conn(conn); // 正式创建连接,发送LE_Create_Connection
bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
// 设置状态为BT_CONN_CONNECTED, old_state=BT_CONN_CONNECT_SCAN
bt_conn_set_state(conn, BT_CONN_CONNECT);
3 .LE_Create_Connection对应的event为LE Connection Complete Event说明连接完成,设置连接状态为BT_CONN_CONNECTED, 并调用att/gatt/smp/l2cap singal/应用 的 connected函数。
static void rx_thread(void *p1, void *p2, void *p3)
bt_recv(buf);
hci_event(buf);
hci_le_meta_event(buf);
le_legacy_conn_complete(buf);
struct bt_hci_evt_le_enh_conn_complete enh;
const bt_addr_le_t *id_addr;
id_addr = find_id_addr(&enh.peer_addr); // 如果开始配对过,则能找到rpa
if (id_addr != &enh.peer_addr) { // 不相同说明找到了
bt_addr_copy(&enh.peer_rpa, &enh.peer_addr.a);
bt_addr_le_copy(&enh.peer_addr, id_addr);
enh.peer_addr.type += BT_ADDR_LE_PUBLIC_ID;
} else
bt_addr_copy(&enh.peer_rpa, BT_ADDR_ANY);
le_enh_conn_complete(&enh);
if (is_enable_smp && atomic_test_and_clear_bit(bt_dev.flags,
BT_DEV_ID_PENDING)) {
// BT_DEV_ID_PENDING在smp_ident_addr_info中设置
bt_keys_foreach(BT_KEYS_IRK, update_pending_id); // 更新id到RL
}
/* 查找是否已经对同一地址发起过连接,且状态相同 */
conn = bt_conn_lookup_state_le(&id_addr, BT_CONN_CONNECT);
// 设置状态为BT_CONN_CONNECTED, old_state=BT_CONN_CONNECT
bt_conn_set_state(conn, BT_CONN_CONNECTED);
switch (old_state) {
case BT_CONN_CONNECT:
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
conn->type == BT_CONN_TYPE_LE) {
k_delayed_work_cancel(&conn->le.update_work);
if (delay_time_extra_update)
k_delayed_work_cancel(&conn->le.extra_update_work);
}
break;
}
switch (conn->state) {
case BT_CONN_CONNECTED:
bt_l2cap_connected(conn);
// 遍历所有l2cap channal(att, smp, l2cap signaling),
// 在bt_att_init/bt_smp_init/bt_l2cap_init中通过
//bt_l2cap_le_fixed_chan_register注册进来
SYS_SLIST_FOR_EACH_CONTAINER(&le_channels, fchan, node)
struct bt_l2cap_le_chan *ch;
/* 调用att/smp/l2cap signal通道的accept函数 */
fchan->accept(conn, &chan) < 0):
att->chan.chan.ops = &ops; // att
smp->chan.ops = &ops; // smp
*chan = &l2cap_chan.chan; // l2cap singal
ch = BT_L2CAP_LE_CHAN(chan);
ch->rx.cid = fchan->cid;// 设置att/smp/l2cap signal通道rx的cid
ch->tx.cid = fchan->cid;// 设置att/smp/l2cap signal通道tx的cid
l2cap_chan_add(conn, chan, NULL):
/* 调用att/smp/l2cap signal通道的connected函数 */
chan->ops->connected(chan);
// att connected函数
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
ch->tx.mtu = BT_ATT_DEFAULT_LE_MTU;// 设置att tx mtu
ch->rx.mtu = BT_ATT_DEFAULT_LE_MTU;// 设置att rx mtu
k_delayed_work_init(&att->timeout_work, att_timeout);
// 调用gatt的connected的函数
bt_gatt_connected(ch->chan.conn);
bt_gatt_foreach_attr(0x0001,0xffff,connected_cb,conn);
for (i = 0; i < ccc->cfg_len; i++) {
if (ccc->cfg[i].value) {
gatt_ccc_changed(attr, ccc);// 设置ccc
if (ccc->cfg == sc_ccc_cfg)
sc_restore(&ccc->cfg[i]);
add_subscriptions(conn);
notify_connected(conn);
break;
}
k_delayed_work_submit(&conn->le.extra_update_work,
conn->role == BT_HCI_ROLE_MASTER ? K_NO_WAIT :
delay_time_extra_update); // features, set phy, set LDE, update conn param