Zephyr Bluetooth Stack之Initiating Connection

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章