300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 传统蓝牙HCI连接的流程介绍

传统蓝牙HCI连接的流程介绍

时间:2019-08-19 18:54:40

相关推荐

传统蓝牙HCI连接的流程介绍

一. 声明

本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:

第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。

第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,基于USB的H2等

第三篇:传统蓝牙controller介绍,主要介绍传统蓝牙芯片的介绍,包括射频层(RF),基带层(baseband),链路管理层(LMP)等

第四篇:传统蓝牙host介绍,主要介绍传统蓝牙的协议栈,比如HCI,L2CAP,SDP,RFCOMM,HFP,SPP,HID,AVDTP,AVCTP,A2DP,AVRCP,OBEX,PBAP,MAP等等一系列的协议吧。

第五篇:低功耗蓝牙controller介绍,主要介绍低功耗蓝牙芯片,包括物理层(PHY),链路层(LL)

第六篇:低功耗蓝牙host介绍,低功耗蓝牙协议栈的介绍,包括HCI,L2CAP,ATT,GATT,SM等

第七篇:蓝牙芯片介绍,主要介绍一些蓝牙芯片的初始化流程,基于HCI vendor command的扩展

第八篇:附录,主要介绍以上常用名词的介绍以及一些特殊流程的介绍等。

另外,开发板如下所示,对于想学习蓝牙协议栈的最好人手一套。以便更好的学习蓝牙协议栈,相信我,学完这一套视频你将拥有修改任何协议栈的能力(比如Linux下的bluez,Android下的bluedroid)。

------------------------------------------------------------------------------------------------------------------------------------------

CSDN学院链接(进入选择你想要学习的课程):/lecturer/5352?spm=1002.2001.3001.4144

蓝牙交流扣扣群:970324688

Github代码:/sj15712795029/bluetooth_stack

入手开发板:/item.htm?spm=a1z10.1-c-s.w4004-22329603896.18.5aeb41f973iStr&id=622836061708

蓝牙学习目录:/XiaoXiaoPengBo/article/details/107727900

------------------------------------------------------------------------------------------------------------------------------------------

二.hci connection command以及产生的event

此部分指的是hci的连接,不是上层profile的连接,流程如下:

总结步骤:

1)蓝牙协议栈向芯片发送连接的command

2)蓝牙芯片上报蓝牙协议栈command status with create connection opcode

3)蓝牙芯片上报蓝牙协议栈connect complete

下面我们就来一一分析3个步骤

步骤1):蓝牙协议栈像芯片发送连接的command,连接command封包格式如下:

参数:

BD_ADDR:要连接的remote设备的蓝牙地址

Packet_Type:支持的数据封包类型。

Page_Scan_Repetition_Mode:page scan重复模式

Reserved: 保留

Clock_Offset:时钟偏移。

Allow_Role_Switch:是否允许角色转换

我们直接来看下wireshark转的snoop

代码如下:

err_t hci_connect_req(struct bd_addr_t *bdaddr, uint8_t allow_role_switch){uint8_t page_scan_repetition_mode, page_scan_mode;uint16_t clock_offset;struct bt_pbuf_t *p;struct hci_link_t *link = hci_new();struct hci_inq_res_t *inqres;if(link == NULL){BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] fail\n",__FILE__,__FUNCTION__,__LINE__);return BT_ERR_MEM; /* Could not allocate memory for link */}link->state = SEND_CREATE_CONNECTION;bd_addr_set(&(link->bdaddr), bdaddr);HCI_REG(&(hci_active_links), link);/* Check if module has been discovered in a recent inquiry */for(inqres = pcb->ires; inqres != NULL; inqres = inqres->next){if(bd_addr_cmp(&inqres->bdaddr, bdaddr)){page_scan_repetition_mode = inqres->psrm;page_scan_mode = inqres->psm;clock_offset = inqres->co;break;}}if(inqres == NULL){/* No information on parameters from an inquiry. Using default values */page_scan_repetition_mode = 0x01; /* Assuming worst case: time betweensuccessive page scans starting<= 2.56s */page_scan_mode = 0x00; /* Assumes the device uses mandatory scanning, mostdevices use this. If no conn is established, tryagain w this parm set to optional page scanning */clock_offset = 0x00; /* If the device was not found in a recent inquirythis information is irrelevant */}if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_CREATE_CONN_PLEN, BT_PBUF_RAM)) == NULL){BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_pbuf_alloc fail\n",__FILE__,__FUNCTION__,__LINE__);return BT_ERR_MEM; /* Could not allocate memory for bt_pbuf_t */}/* Assembling command packet */p = hci_cmd_ass(p, HCI_CREATE_CONNECTION, HCI_LINK_CONTROL, HCI_CREATE_CONN_PLEN);/* Assembling cmd prameters */memcpy(((uint8_t *)p->payload)+3, bdaddr->addr, 6);bt_le_store_16((uint8_t *)p->payload,9,HCI_PACKET_TYPE);((uint8_t *)p->payload)[11] = page_scan_repetition_mode;((uint8_t *)p->payload)[12] = page_scan_mode;bt_le_store_16((uint8_t *)p->payload,13,clock_offset);((uint8_t *)p->payload)[15] = allow_role_switch;phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);bt_pbuf_free(p);return BT_ERR_OK;}

步骤2)芯片上报给蓝牙协议栈的command status with create connetion opcode

由于前面我们已经讲解了command status的event格式,所以我们在这就不再贴了,直接上wireshark抓的btsnoop

Event command status的代码处理也贴过了,我们直接来看步骤3

步骤3)蓝牙芯片向蓝牙协议栈上报connection complete事件,封包格式如下

参数:

Status:连接的状态

Connection_Handle:连接的句柄

BD_ADDR:连接的蓝牙地址

Link_Type:连接的类型

Encryption_Enabled: 是否允许加密

下面我们来直接看下Wireshark抓的btsnoop加深下印象

最后,我们来看看代码中是怎么处理的

case HCI_CONNECTION_COMPLETE:bdaddr = (void *)(((uint8_t *)p->payload)+3); /* Get the Bluetooth address */link = hci_get_link(bdaddr);switch(((uint8_t *)p->payload)[0]){case HCI_SUCCESS:BT_HCI_TRACE_DEBUG("hci_event_input: Conn successfully completed\n");if(link == NULL){if((link = hci_new()) == NULL){/* Could not allocate memory for link. Disconnect */BT_HCI_TRACE_DEBUG("hci_event_input: Could not allocate memory for link. Disconnect\n");hci_disconnect_acl(bdaddr, HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES);/* Notify L2CAP */lp_disconnect_ind(bdaddr);break;}bd_addr_set(&(link->bdaddr), bdaddr);link->conhdl = *((uint16_t *)(((uint8_t *)p->payload)+1));HCI_REG(&(hci_active_links), link);HCI_EVENT_CONN_COMPLETE(pcb,bdaddr,ret); /* Allow applicaton to do optional configuration of link */BT_HCI_TRACE_DEBUG("hci_event_input: Calling l2cap cb 1\n");hci_get_remote_feature(bdaddr);if(link->state == SEND_CREATE_CONNECTION){lp_connect_cfm(bdaddr, ((uint8_t *)p->payload)[10], BT_ERR_OK); /* Notify L2CAP */}elselp_connect_ind(&(link->bdaddr)); /* Notify L2CAP */link->state = OPEN;}else{link->conhdl = *((uint16_t *)(((uint8_t *)p->payload)+1));HCI_EVENT_CONN_COMPLETE(pcb,bdaddr,ret); /* Allow applicaton to do optional configuration of link */BT_HCI_TRACE_DEBUG("hci_event_input: Calling l2cap cb 2\n");hci_get_remote_feature(bdaddr);if(link->state == SEND_CREATE_CONNECTION)lp_connect_cfm(bdaddr, ((uint8_t *)p->payload)[10], BT_ERR_OK); /* Notify L2CAP */elselp_connect_ind(&(link->bdaddr)); /* Notify L2CAP */link->state = OPEN;}//TODO: MASTER SLAVE SWITCH??break;

三.hci接受连线请求command以及产生的event

老规矩,我们先来看下Wireshark整个封包的交互流程

步骤整理如下:

1)收到芯片上报给协议栈connect request的事件

2)协议栈发送给芯片接受连接请求的command

3)收到command status with accept connection req的opcode

4)收到connect complete的event

步骤1)的connection request的event的封包格式如下

参数:

BD_ADDR:蓝牙地址

Class_of_Device: 对方的cod

Link_Type:连线类型

老规矩直接来看下Wireshark抓的btsnoop

然后看下代码我们是怎么处理的

case HCI_CONNECTION_REQUEST:bdaddr = (void *)(((uint8_t *)p->payload)); /* Get the Bluetooth address */link_type = ((uint8_t *)p->payload)[9];BT_HCI_TRACE_DEBUG("hci_event_input: recv conn req type %d\n",link_type);link = hci_get_link(bdaddr);if(link == NULL){if((link = hci_new()) == NULL){link->state = RECEIVED_CONNECTION_REQUEST;/* Could not allocate memory for link. Disconnect */BT_HCI_TRACE_DEBUG("hci_event_input: Could not allocate memory for link. reject\n");hci_reject_connection_request(bdaddr,HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES);link->state = REJECTED_CONNECTION_REQUEST;}else{bd_addr_set(&(link->bdaddr), bdaddr);/* TODO 此部分是否需要反转 */memcpy(&link->cod,((uint8_t *)p->payload)+6,3);link->role = HCI_ROLE_SLAVE;BT_HCI_TRACE_DEBUG("hci_event_input: con req cod 0x%x\n",link->cod);HCI_REG(&(hci_active_links), link);hci_accept_connection_request(bdaddr,HCI_ROLE_SLAVE);link->state = ACCEPTED_CONNECTION_REQUEST;}}else{if(link_type == HCI_LINK_TYPE_ACL){/* Could not allocate memory for link. Disconnect */BT_HCI_TRACE_DEBUG("hci_event_input: con exit. reject\n");hci_reject_connection_request(bdaddr,HCI_ACL_CONNECTION_EXISTS);link->state = REJECTED_CONNECTION_REQUEST;hci_close(link);}else{HCI_EVENT_SCO_REQ(pcb, bdaddr, ret);}}break;

步骤2)蓝牙协议栈发送给蓝牙芯片接受连接请求的命令封包格式如下:

参数:

BD_ADDR:蓝牙地址

Role:当前连接的角色

我们来看下Wireshark的抓的snoop

代码如下:

err_t hci_accept_connection_request(struct bd_addr_t *bdaddr, uint8_t role){struct bt_pbuf_t *p;if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_ACCEPT_CON_REQ_PLEN, BT_PBUF_RAM)) == NULL){BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_pbuf_alloc fail\n",__FILE__,__FUNCTION__,__LINE__);return BT_ERR_MEM;}/* Assembling command packet */p = hci_cmd_ass(p, HCI_ACCEPT_CONNECTION_REQUEST, HCI_LINK_CONTROL, HCI_ACCEPT_CON_REQ_PLEN);/* Assembling cmd prameters */memcpy(((uint8_t *)p->payload) + 3, bdaddr->addr, 6);((uint8_t *)p->payload)[9] = role;phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);bt_pbuf_free(p);return BT_ERR_OK;}

步骤3)收到command status with accept connection req的opcode

由于command status的格式以及代码我们已经在前面介绍,所以此部分我们只贴BTSNOOP

步骤4)收到connect complete的event

跟主动连接一样,就不在这里重复说明

这个小节其实还有很多要讲的,以上我们上面讲的主要是OGF=1的小部分命令以及event

我们在这个小节就不讲其他OGF了,我们在下一个小节,蓝牙初始化的时候来说明其他OGF,初始化主要会牵扯都OGF=3/OGF=4的部分command

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。