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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值