蓝牙HCI
蓝牙HCI
HCI概述
HCI 是 Host Controller Interface 的缩写,也就是说,他是 Host 和 Controller 之间的桥梁
HCI COMMAND 是蓝牙协议栈发送个芯片的命令
HCI EVENT 是蓝牙芯片上报给蓝牙协议栈的事件
HCI ACL 是蓝牙协议栈与蓝牙芯片双向交互的普通数据
HCI SCO 是蓝牙协议栈与蓝牙芯片双向交互的通话/语音识别数据
HCI ISO 是 BLE audio,是 core5.2 才添加的
HCI数据格式
HCI 数据格式如果没额外强调就是小端格式
HCI Command packet
HCI Command 的数据格式有两个字节的 Opcode,其中 OCF 占 10bit,OGF 占 6bit,一个字节的参数长度,剩下的是参数,因为参数长度用一个字节表示所以后面参数最大有 255 个,整个 Command 的长度最大就是 258
每一个命令去执行都有自己的 Opcode,这个 Opcode 是唯一的,OGF 是一个组,OCF 是组中的一个,在 HCI COMMANDS AND EVENTS 这个目录下面,每一个小标题都有一个 OGF,里面每个 command 都有自己的 OCF(另外还有个 0x3F 是给厂商预留能自己定义的)
比如截图这里 LINK CONTROL 的 OGF 是 0x01,还有个 OCF 是 0x0001 的 Inquiry,他俩组合起来的 opcode 表示 HCI_Inquiry,其他的 command 道理是一样的
接下来随便打开一个 hci log,看一下 hci_reset,wireshark 已经帮我们解析出来了,OGF 和 OCF 都是 3,并且他们是咋拼起来的也很清楚了,OGF 左移两位,然后和 OCF 拼起来
按照 OGF 和 OCF 去找也能在核心规范里面找到
再找一个带参数的,看一下格式
根据 OGF 和 OCF 在定位核心规范中定位
一共有两个参数,一个是 BD_ADDR(蓝牙地址),长度是 6 字节,一个是 Role(角色) 长度是 1 字节
HCI ACL Data packet
牵扯到上层的数据就是 ACL 格式的,数据格式比较简单,首先是 12bit 的 Handle,这个是连接后生成的 connection handle
HCI Event packet
相比 command event 比较简单,直接用 event code 来定位 event
比如 HCI_Command_Status 的 event code 是 0xf
HCI流控
流控,数据流控制,就是用来管理两个节点之间的数据的传输,防止出现一个节点数据缓冲区满了,另一个节点还在给他发数据导致数据丢失的情况
controller 的流控:host 先发送 hci command 去读取 controller 的信息,controller会把包括节点的数量、每个节点的大小等发回给 host。正常开始发送数据的时候(假如 controller 有 8 个节点),host 发送一个,controller 会自己变为 7,等处理完这一个之后会发送一个 packet Completed event 给 host 同时变为 8 个
host 流控:host 主动发送 command 给 controller 告诉自己的信息,然后发送 set controller to host flow control。正常开始发数据的时候 controller 发给 host 数据,host 处理完会发一个 host number of completed packets
蓝牙初始化流程
CSR8X11
略
SIG标准
HCI Reset 相当于芯片的软复位,OGF 是 0x03,OCF 也是 0x0003,他没有参数
芯片会回复一个 Command Complete,他的 event code 是 0x0e,还有三个参数,Num_HCI_Command_Packets,1byte,对应 Number of Allowed Command Packets 表示可以发送数据包的数量
Command Opcode 就是 command 的 opcode,Return_Parameters 对应 Status: Success (0x00) 表示状态
Read Local Version Information 读取芯片版本,对应的 OGF 是 0x04,OCF 是 0x01,他返回的参数就比较多了
主要是返回了蓝牙芯片的版本信息
这些版本对应的编号在:Assigned Numbers | Bluetooth® Technology Website 第七页中有定义,HCI Version 就是蓝牙协议的版本
Read Buffer Size,读取缓冲区大小 OGF 是 0x04,OCF 是 0x05,没有参数,缓冲区大小是流控用到的
Read BD ADDR 然后获取蓝牙地址,OGF 是 0x04,OCF 是 0x09,返回一个状态和一个蓝牙地址
Write Class of Device 设置 Class of Device,OGF 是 0x03,OCF 是 0x024 用来标识设备类型,手机配对蓝牙设备的时候前面的耳机、键盘这种类型就是靠 cod 来标识的,详细见:蓝牙设备类型cod(蓝牙class of device介绍)_Wireless_Link的博客-CSDN博客_蓝牙设备类型
Write Local Name 设置蓝牙设备的名字,OGF 是 0x03,OCF 是 0x013,有一个参数就是设备的名字
Write Page Timeout 作用是给 controller 设置一个超时时间,当 controller 超过了这个时间还连接不上对端设备就给 host 上报
Set Event Mask 是 host 告诉 controller 想要接受哪些事件,不想接受哪些事件,controller 就只会上报 host 想接收的的事件
Write Simple Pairing Mode 是设置 SSP 配对方式,如果 Simple Pairing Mode 是 disable 的话就是 PINCODE 方式,需要手动输入配对码;如果双方都是 Simple Pairing Mode enable 的话,会以弹出一个小窗口展示配对码,点击配对的形式
Write Inquiry Mode 设置搜索模式有三种搜索模式
第一种模式每个设备只上报一次标准信息,有蓝牙地址、cod 等,不管信号强度咋变,只上报一次
第二种模式会在标准的蓝牙信息前提再带上信号强度 RSSI,会重复上报
第三种模式会带 EIR 会带蓝牙名称、支持的 UUID 以及自定义的信息,会重复上报
这个数据包就是告诉告诉芯片要第三种模式,对端支持的信息都要拿到 Inquiry Result with RSSI format or Extended Inquiry Result format
Write Scan Enable 设置 scan 模式,有两种模式,一个是 Inquiry Scan 一种是 Page Scan,只有开启了 Inquiry Scan 才能被搜索到,只有开启了 Page Scan 才能被连接,这里全部开启了,即可以被搜索和连接
Write LE Host Supported 这一步相当于是使能 LE
Write LE Host Supported 设置 EIR 信息,这个东西之后具体学习
初始化到这里就算是结束了,再往下就是对端设备的连接请求了
如果只是想要被搜索到,下一个 HCI Reset、一个 Write Local Name、一个 Scan Enable 就足够了
BLE scan
传统蓝牙与BLE Scan的差异
传统蓝牙分为 79 个信道,0 到 78,BLE 是 40个信道,0 到 39
传统蓝牙搜索的话,对端设备要 write scan enable 我们才能扫描到,然后跳频也是在整个 79 个信道跳,我们扫描设备的时候要么遍历信道,要么也是随机扫,所以哪怕两个设备扫描到的时间也不固定
BLE 为了弥补这个问题,把广播信道固定在了 37、38、39,之所以选这三个是为了避开同样在 2.4Ghz 的 WIFI 的 ch1、ch6、ch11
同时也没有 Inquiry Scan 这类的模式了,改成了 advertising
同时传统蓝牙 inquiry 会通过设置 number 和 timeout 自动停止,但是 BLE 的 scan 不会停止,只能是通过上层修改 scan disable 才能停止
在初始化过程中设置 Event Mask 的时候需要设置上 LE Meta,否则获取不到扫描的数据
需要对 LE 的功能进行使能,Write LE Host Supported,OGF 是 0x03,OCF 是 0x006D,本来有两个参数,但是有一个弃用了,现在只需要关注 LE_Supported_Host 这个参数就行了
设置扫描的参数 LE Set Scan Parameters,其中 LE_Scan_Interval 表示一次扫描总共花费的时间,LE_Scan_Window 表示一次扫描中真实扫描的时间
还要使能 LE Set Scan Enable
BLE_Scan HCI 解析
返回的结果是在 LE Meta Event 中的 LE Advertising Report event,因此又多了个 Subevent Code 的概念,LE Meta Event Code 是 0x3E,LE Advertising Report Subevent Code 是 0x02
后面跟一个 Num_Reports,表示上报的数量,但一般都是一个一个报的
Event_Type 这个字段就表示扫描到的设备广播的类型(可搜索可连接的非定向广播 0x00、可连接的定向广播 0x01、可扫描的非定向广播 0x02、不可连接的非定向广播 0x03)
Address_Type 是地址类型,正常来说安卓都是 random 地址
Manufacturer Specific Data 里面的数据是厂商自定义的,会带一些厂商 id,主要是用来识别设备的,比如你的蓝牙耳机打开盒子之后手机上会弹出一个窗口,会问你是不是要连接这个耳机之类的
BLE 广播
核心的三条命令,Set Advertising Parameters 设置广播的参数(广播行为是什么)
Set Advertising Data 设置广播的数据(广播什么数据)
Set Advertising Enable 使能广播
因为在 BLE5.0 之前 Advertising Data 只能放 31 byte 的数据,如果东西一多就放不下来了。因此引入了一个 scan response 的概念,这里面的数据就是被扫描到之后才会给的
如果设备使用主动扫描会发送 ScanReq,且目标注册了 Set Scan Response Data 的话,就能同时把 advertising data 和 scan response data 扫描出来
如果使用被动扫描,就只会收到 advertising data 了