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