Texas Instruments CC2540/41
Bluetooth® Low Energy
Software Developer’s Guide
v1.3.2
Document Number:SWRU271F
《低功耗蓝牙开发权威指南》
Robin Heydon著,陈灿峰、刘嘉 译
机械工业出版社
2014.6
标签:读书笔记 BLE
HCI是主机和控制器之间的接口,主要完成两个任务:
一般来说,主机接口是两个设备之间的物理接口和逻辑接口。逻辑接口定义了命令、事件和数据的封包格式。物理接口定义了主机和控制器之间如何传输这些数据包。
蓝牙规范中定义了四种物理接口:
所谓的逻辑接口是指在单芯片设备上,并不需要在组件之间真正实现这样的信息传输接口;如果系统中的控制器和主机分别位于两个芯片上,HCI逻辑接口就体现为在两者之间传输数据的物理接口。
HCI逻辑接口的三个概念:
一旦控制器与其他设备建立了连接,控制器底层HCI接口就创建一个HCI信道,HCI信道被连接句柄(connection handle)标识。连接句柄既可以标志主机交给控制器并准备发给对端的数据,也可以标志控制器从对端收到的准备交给主机的数据。
无论何时,只要主机尝试创建一个连接,控制器就为主机提供一个连接句柄。直到连接结束连接句柄才会失效。连接结束的原因可能是本地的链路层终止规程,也可能是链路监控超时导致。
主机通过向控制器发送命令数据包来执行命令。这些命令通常用于配置控制器的状态,或者请求控制器完成操作。
HCI命令包格式由三部分组成:用来确认发送命令的操作码(2字节)、参数长度(1字节)以及命令参数。每个命令都有自己一套独特的参数。
BLE中有三种基本命令类型,分别实现如下功能:
控制器发往主机的事件数据包主要用于发送信息和反馈之前输入的命令。
HCI事件数据包由事件类型编码(1字节)、参数长度(1字节)以及命令参数。每个时间都有自己一套独特的参数。
BLE有三种基本事件类型:
数据包是指主机和控制器之间传输的应用数据。控制器接收来自主机的数据包,将其传给对端设备。对端设备收到数据之后,将其从控制器发往主机。
HCI数据包格式包含句柄/标记(2字节)、数据长度(1字节)以及数据。HCI数据包有两种标记:数据包边界标记和广播标记。数据包边界标记用来确认上层协议L2CAP的信息是一个开始数据包还是一个延续包。类似于链路层数据信道PDU中的LLID。
从主机发送到控制器的数据包,标记00标识开始包,01标识延续包;
从控制器发送到主机的数据包,标记10标识开始包,01标记延续包。
HCI接口有两种流控形式:命令流控和数据流控。控制器使用命令流控同时处理多个HCI命令。因为控制器内部拥有足够的缓存,能够存储一定数量的命令;主机可以通过控制器来获知缓冲区的长度,从而得知可以同时发送的命令的最大数量。
HCI接口不支持事件流控,因为事件的数量受限于可处理命令的数量,另外主机比控制器拥有更多的资源,能够顺序地缓冲和处理这些事件。
一共有两种数据流:主机到控制器以及控制器到主机。主机到控制器的数据流控是必须的,而控制器到主机的数据流控可以忽略。对于主机到控制器的数据流控,控制器拥有一定数量的缓冲区,每个缓冲区存放一个数据包。每次控制器都从一个缓冲区提取数据包来发送给对端设备,一旦数据包发送成功,控制器释放该缓冲区,一边装填主机发送给控制器的新数据包。
利用控制器与对端设备通信之前,主机可以先对控制器进行下列相关操作:
A[重置控制器状态] --> B[读取设备地址]
B --> C[设置事件掩码]
C --> D[读取流控缓存]
D --> E[读取控制器支持的功能列表]
E --> F[生成随机数]
F --> G[加密数据]
G --> H[设置随机地址]
H --> I[配置白名单]
主机->链路层:重置
Note left of 链路层:重置控制器为默认状态
链路层->主机:命令完成
由于控制器可能正在执行其他操作,或者主机传输才刚刚建立。在这种情况下,可以吧控制器重置为就绪态,这样会把所有可配置参数恢复为默认值。
主机通过重置Reset命令来重置控制器。控制器一旦重置,将向主机返回命令完成Command Complete事件。充值命令不会重置物理链路,如果要重置物理链路,需要执行另外的链路重置操作。虽然主机可以发送多条命令给控制器,如果控制器正在执行重置,也不能接受其他命令。重置命令可以抢占其他命令的执行。
主机->链路层:读取BD_ADDR
链路层->主机:命令完成
主机通过向控制器发送Read BD_ADDR命令来读取设备地址,后者返回一个含有固定设备地址的Command Complete事件。如果控制器没有固定地址,则返回全零地址00:00:00:00:00:00。此时,主机需要为控制器生成一个随机地址,否则无法进行数据传输。
通过设置事件掩码,主机告诉控制器哪些事件能被接收,哪些不能接收。这样控制器只会发那些能被接收的事件。
主机->链路层:设置事件掩码
链路层->主机:命令完成
主机->链路层:设置低功耗事件掩码
链路层->主机:命令完成
Set Event Mask命令曾用于经典蓝牙设置各类事件,由于其中的“meta-event”事件仍然适用于低功耗蓝牙,主机可以使用该命令来启动或屏蔽meta-event。另外LE Set Event Mask命令用来启动或屏蔽相关的低功耗蓝牙事件。
主机->链路层:读取低功耗缓冲区大小
链路层->主机:命令完成
主机->链路层:读取缓冲区大小
链路层->主机:命令完成
LE Read Buffer Size
Read Buffer Size
确保主机和控制器兼容的另一个办法是,主机向控制器发送命令之前首先确认控制器支持的功能。
主机->链路层:读取支持功能列表
链路层->主机:命令完成
主机通过发送LE Read Supported Features 命令来获得控制器所支持的功能列表。在控制器返回的Command Complete 实践中包含了此功能列表。一般来说,主机在发送和功能有关的命令之前,应该首先发送LE Read Supported Features命令。
控制器的设计可以非常简单,也可以非常复杂。主机必须知道控制器支持哪些状态及其组合,以免因设置了无效的状态而导致错误。
主机->链路层:读取支持的状态列表
链路层->主机:命令完成
主机发送LE Read Supported States命令后,控制器返回带有支持的状态列表的Command Complete事件。
控制器可以支持如下的状态:
控制器可以方便产生随机数,这些随机数通常源于设备自身的物理特性。
主机->链路层:生成随机数
链路层->主机:命令完成
主机发送LE Rand命令来让控制器为其生成随机数。随机数包含在返回的Command Complete事件中。
主机可以使用BLE的AES-128加密引擎来加密数据。主机发送LE Encrypt命令来进行数据加密。此命令中包含了需要加密的数据和加密密钥。控制器使用AES-128加密算法进行加密,并在返回的Command Complete事件中包含已加密数据。
在BLE中没有解密命令,主机只能检查相同的明文在变成密文后是否一致,但不能使用密钥将密文恢复为明文。
主机->链路层:加密数据
链路层->主机:命令完成
如果控制器没有固定地址,或者主机希望使用私有地址来替代固定地址,那么主机必须为控制器设置一个随机地址,以便用于广播、主动扫描和发起连接等操作。
主机->链路层:生成随机数
链路层->主机:命令完成
主机->链路层:加密数据
链路层->主机:命令完成
主机->链路层:设置随机地址
链路层->主机:命令完成
主机首先使用LE Rand命令来生成一个随机数。接下来,此随机数和IRK(Identity Resolving Key,身份解析密钥)分别作为明文和加密密钥执行LE Encrypt命令。主机获得了返回值后将其作为随机地址,使用LE Set Random Address命令对控制器进行设置。在收到了地址设置的Command Complete事件之后,该随机地址才能用于其他命令。
控制器里面存储着一个设备地址列表,称为白名单。白名单在充满广播报文的密集环境中可用来搜索已知设备。不过由于白名单的容量有限,在使用之前首先要确定其容量的大小。主机可以通过命令对白名单进行添加、删除以及重置等操作,而控制器可以根据白名单来过滤广播数据包。
主机->链路层:读取白名单大小
链路层->主机:命令完成
主机->链路层:清空白名单列表
链路层->主机:命令完成
主机->链路层:添加设备至白名单
链路层->主机:命令完成
主机使用LE Read White List Size命令来读取白名单的容量大小,控制器在返回的Command Complete 事件中包含了最多能容纳的条目数量。在管理白名单方面,可以用LE Clear White List命令来清空列表,要从列表中添加和删除条目则应该使用LE Add Device To White List命令和LE Remove Device From White List命令。
当控制器正在使用白名单的时候不能改变其列表内容。
两个BLE设备之间最基本的通信模型就是广播(broadcasting)和观察(observing)模型。两者通过广播和扫描来传输数据。
控制器有两类数据可以通过广播发送:广播数据和扫描响应数据。另外,控制器还有一系列的参数,用来设置如何发送以及何时发送广播报文。
HCI广播过程如下:
主机->链路层:设置广播参数
链路层->主机:命令完成
主机->链路层:读取广播信道发射功率
链路层->主机:命令完成
主机->链路层:设置广播数据包
链路层->主机:命令完成
主机->链路层:设置扫描响应数据
链路层->主机:命令完成
主机->链路层:启动广播
链路层->主机:命令完成
Note right of 链路层:发送广播数据包
Note right of 链路层:发送广播数据包
主机->链路层:关闭广播
链路层->主机:命令完成
主机使用LE Set Advertising Parameters 命令来设置广播参数。配置参数包括广播的最小间隔时间和最大间隔时间,范围从20ms~10.24s。另外,广播类型一共有四种,分别是:
LE Set Advertising Parameters命令还可以用来设置地址类型,或者为固定设备地址,或者为随机地址。如果当前的广播类型为定向广播,那么在广播数据包中应含有对端设备的地址。另外,还有两个参数可以配置,分别是广播信道映射和广播过滤策略。广播信道映射用来决定使用哪三个广播信道,而过滤策略则用来过滤不符合规则的广播数据包,过滤策略可以设置为如下规则之一:
如果想获得广播时的发射功率,那么可以使用LE Read Advertising Channel TX Power 命令。另外,还将发射功率的值放在广播数据包中或者扫描响应数据包中,从而实现靠近配对,或者供用户界面根据路径损耗对设备进行排序。
要设置广播数据包和扫描响应数据包的内容,主机分别使用LE Set Advertising Data 命令和LE Set Scan Response Data命令实现。
当一切配置就绪,可以使用LE Set Advertising Enabled 来启动或关闭广播。广播一旦启动,控制器将使用配置好的参数进行广播。
要接收对端设备的广播数据包,可以使用被动扫描。HCI被动扫描过程如下:
主机->链路层:设置扫描参数(被动模式)
链路层->主机:命令完成
主机->链路层:启动扫描
链路层->主机:命令完成
Note right of 链路层:接收广播数据包
链路层->主机:广播报告(广播数据)
Note right of 链路层:接收广播数据包
链路层->主机:广播报告(广播数据)
主机->链路层:停止扫描
链路层->主机:命令完成
使用LE Set Scan Parameters命令来进行设置控制器的扫描参数,可配置的参数如下:
如果定向广播数据包中的目的地址并非自己,及时广播数据包的发送者在自己的白名单中也要将给数据包抛弃。
一旦扫描参数设置完毕,主机就可以启用LE Set Scan Enabled 命令启动扫描。扫描过程中,如果控制器接收到的符合过滤策略和其他规则的广播数据包,则发送一个LE Advertising Report 事件给主机。除了广播者的设备地址外,广播报告事件还包含了广播数据包中的数据,以及接收广播数据包时的信号接收强度。可以利用该信号强度以及位于广播数据包中的发射功率,共同确定信号的路径损失,从而给出大致的范围。
主机如果想停止扫描,还是使用LE Set Scan Enable 命令,只是参数应设置为“停止扫描”。
主动扫描不仅可以捕获到对端设备的广播数据包,还可以捕获可能的扫描响应包。
在参数配置和启动扫描方面,主动扫描和被动扫描使用的命令完全一样。不过,因为控制器要发送SCAN_REQ数据包给对端设备,以便获取扫描响应数据包,而这些数据包需要包含发送地址,因此在使用LE Set Scan Parameters命令时需要配置一个额外参数,决定链路层的数据包适用固定地址亦或是随机地址。HCI主动扫描过程如下所示:
主机->链路层:设置扫描参数(主动模式)
链路层->主机:命令完成
主机->链路层:启动扫描
链路层->主机:命令完成
Note right of 链路层:接收广播数据包
Note right of 链路层:发送扫描请求
Note right of 链路层:接收扫描响应
链路层->主机:广播报告(扫描响应数据)
Note right of 链路层:接收广播数据包
Note right of 链路层:发送扫描请求
Note right of 链路层:接收扫描响应
链路层->主机:广播报告(扫描响应数据)
主机->链路层:停止扫描
链路层->主机:命令完成
控制器收到SCAN_RSP数据包后向主机发送一个LE Advertising Report事件。该事件同样包括了链路层数据包的广播类型。因此主机能够判断对端设备是否可以连接或扫描,从而区分出广播数据包和扫描响应数据包。
广播和扫描仅仅是蓝牙功能的一部分,要实现更多的应用功能必须依靠两个设备之间的连接。要建立连接,其中一个蓝牙设备应该处于可连接的广播状态,由另一个设备发起连接。当然,连接的对象既可以是一个白名单,也可以是指定的单一设备。建立连接需要耗费一定的时间,如果用户或者应用程序不再需要连接时,可以在连接未建立之前取消。
最常用的连接方式是主机先将对端设备添加到白名单中,然后再与白名单中的设备进行连接。通过这种方式,控制器可以同一时间与多个设备发起连接。实际上,这能让主机请求控制器同时与A、B、C、D、E、F等设备发起连接。HCI与白名单中的设备发起连接的过程如下:
主机->链路层:添加设备至白名单
链路层->主机:命令完成
主机->链路层:建立连接(白名单)
链路层->主机:命令状态
Note right of 链路层:接收广播数据包
Note right of 链路层:发送连接请求
链路层->主机:连接完成
Note over 链路层:主设备
Note right of 链路层:发送数据信道数据包
Note right of 链路层:接收数据信道数据包
要与一个或多个设备发起连接,白名单必须包含这些设备。主机使用LE Add Device To White List以及其他白名单管理命令实现该功能。一旦主机打算与白名单中的设备连接,则向控制器发送LE Create Connection命令。
LE Create Connection命令可配置如下参数:
发起连接参数对白名单的所有设备是完全相同的。如果控制器收到白名单中某一设备的可连接广播数据包,则向对端设备发送CONNECT_REQ数据包,其中含有所有连接所需的信息。另外,控制器还向主机发送LE Connection Complete事件。如果对端设备接收到 CONNECT_REQ数据包,它也会向主机发送LE Connection Complete事件。
该LE Connection Complete事件包含连接句柄,用于标记主机和控制器之间传输的数据包。该事件还包含当前控制器的角色信息(主从设备),以及从设备的地址、间隔时间、等待时间、监控超时和主设备的时钟精度等。从设备需要利用时钟精度来决定其窗口扩展,而该参数提供给主机当做信息参考之用。
当连接已经建立并且发送了LE Connection Complete事件,所有的广播或者其他的发起连接请求都将自动停止,如果主机想继续广播或与其他设备进行连接,则必须再次执行响应的命令。
主机->链路层:建立连接(设备A)
链路层->主机:命令状态
Note right of 链路层:接收广播数据包(设备B)
Note right of 链路层:接收广播数据包(设备C)
Note right of 链路层:接收广播数据包(设备A)
Note right of 链路层:发送连接请求
链路层->主机:连接完成
Note right of 链路层:发送数据信道数据包
Note right of 链路层:接收数据信道数据包
与单一设备进行连接,主机同样使用LE Create Connection命令。区别在于,发起者的过滤策略将设置为“忽略白名单”,另外还需要设置对端设备的地址等相关参数。
连接请求的接收方长时间没有响应,此时主机可以取消此连接请求,转而执行其他任务。取消连接请求过程如下所示:
主机->链路层:建立连接(设备A)
链路层->主机:命令状态
Note right of 链路层:接收广播数据包(设备B)
Note right of 链路层:接收广播数据包(设备C)
主机->链路层:取消建立连接
链路层->主机:命令完成
链路层->主机:建立完成(失败)
这里可能会出现竞态条件,当发送LE Create Connection Cancel命令同时,可能连接尚未完成。但在返回命令完成的过程中,连接完成。这是返回的可能是连接完成的回复,也可能是连接建立取消的回复。
主机->链路层:更新连接(设备A)
链路层->主机:命令状态
Note right of 链路层:发送链路层连接更新请求
链路层->主机:连接更新完成
主设备使用LE Connection Update命令修改连接参数。连接参数包括新的连接间隔时间、等待时间、监控超时以及连接事件长度。控制器收到命令之后先返回Command Status事件,随后才发送链路更新请求数据包给对端设备(LL中的10.1)。瞬时时刻到来时,从设备更新连接参数,随后控制器返回LE Connection Update Complete事件表示连接参数已经更新。
主机->链路层:设置主机信道分类
链路层->主机:命令完成
Note right of 链路层:发送链路层信道映射图请求
主机->链路层:读取信道映射图
链路层->主机:命令完成
BLE不能直接向对端设备发送请求以设置链路层信道图。但主机可以使用LE Set Host Channel Classification命令来达到相同的目的。主机无法知道某个信道好不好,但控制器可以通过检测信道中数据包的错误率来判断哪些未知信道不好。
LE Set Host Channel Classification命令将返回Command Complete事件。控制器可以在任何时候启动链路层控制规程修改信道映射图。另外,主机也可以使用LE Read Channel Map命令获得当前信道映射图,该命令的返回时间包含了每个链路层数据信道的使用情况。
主机->链路层:读取对端设备的支持功能列表
链路层->主机:命令状态
Note right of 链路层:发送链路层功能请求
Note right of 链路层:接收链路层功能响应
链路层->主机:完成读取对端设备的支持功能列表
主设备的主机使用LE Read Remote Used Features命令请求获取对端设备的支持功能列表。该命令除了返回Command Status事件外,还会让控制器发送LL_FEATURE_REQ以及获得对端设备的LL_FEATURE_RSP。随后,控制器在返回的LE Read Remote Used Features Complete事件中包含了对端设备的功能信息。
主机->链路层:读取对端设备的版本信息
链路层->主机:命令状态
Note right of 链路层:发送链路层版本指示
Note right of 链路层:接收链路层版本指示
链路层->主机:完成读取对端设备的版本信息
当再次执行LE Read Remote Version Information命令时,虽然仍然返回相同的事件,但控制器并不会执行相关的链路层规程。这是因为版本信息会被当做一种静态信息缓存在控制器中。
之后补充
之后补充
如果不再需要发送数据,或者维持连接比断开后重连需要更多的能量时,主机可以终止连接。
主机->链路层:终止连接
链路层->主机:命令状态
Note right of 链路层:发送链路层终止指示
Note right of 链路层:接收链路层确认
链路层->主机:终止连接完成
主机向链路层发送Disconnect命令终止连接,随后链路层返回Command Status事件并尝试终止连接。如果连接成功终止,控制器将返回Disconnect Complete事件。
当发生监控超时或者MIC失效导致连接中断,主机也会受到Disconnect Complete事件。