HCI 功能规范【5. HCI data formats】(2/5)

📅 2026/7/6 13:59:16
HCI 功能规范【5. HCI data formats】(2/5)
这部分内容属于HCI data formats主要讲的是HCI Command 和 HCI Event 中的数据、参数、字段值应该按照什么规则表示、排列和解析。它不是在讲某一个具体 HCI 命令而是在讲整个 HCI 层通用的数据格式规则。后面你看任何 HCI Command、HCI Event、HCI ACL Data都要先理解这些基础规则。一、这部分整体想表达什么HCI 是 Host 和 Controller 之间的标准接口。Host 发送 Command 给 ControllerController 返回 Event 给 Host这些数据包里面都有大量字段例如Opcode Event Code Status Connection_Handle BD_ADDR Advertising_Data_Length Advertising_Data RSSI这些字段不能随便解释必须按照统一规则解析。这部分主要规定了1. Controller 返回的数据必须正确。 2. HCI 参数默认按 little-endian 小端格式表示。 3. HCI Command / Event 中参数顺序默认按照规范表格顺序排列。 4. 数组参数有固定排列规则。 5. 大多数参数是固定长度少数参数是可变长度。 6. bit string 的最低位 bit 在右边。 7. 未知值、保留值不能导致 Host 或 Controller 停止工作。 8. Controller 默认应支持所有有效参数值。二、5.1 Correctness参数值必须正确表达实际情况这一小节讲的是正确性原则。原文意思是Controller 应当正确设置返回参数和事件参数使这些参数能够准确表示正在报告的数据或情况。例如在HCI_Connection_Complete event里面Link_Type参数必须正确表示当前报告的连接类型。关键信息 1Controller 返回的数据不能乱填HCI Event 或 Command Complete Event 中的参数是 Host 后续判断协议状态的依据。例如连接完成事件中可能包含Status Connection_Handle BD_ADDR Link_Type Encryption_EnabledHost 会根据这些字段判断连接是否成功 连接句柄是多少 对端设备地址是多少 连接类型是什么 当前是否启用了加密如果 Controller 上报的字段不准确Host 的状态机就可能出错。关键信息 2字段格式正确还不够字段语义也必须正确也就是说HCI 不只是要求字段长度正确 字段顺序正确 字段编码正确还要求字段值必须符合真实情况例如实际建立的是 ACL 连接那么HCI_Connection_Complete event中的Link_Type就必须表示 ACL connection不能填成 SCO 或 eSCO。否则 Host 可能会按照错误的连接类型处理后续流程。三、5.2 Data and parameter formats数据和参数格式规则这一小节是重点讲 HCI 参数的通用解析规则。关键信息 1默认使用 little-endian 小端格式原文说All values are in binary and hexadecimal little-endian formats unless otherwise noted.意思是除非规范特别说明否则 HCI 里面的数值都按照little-endian 小端格式表示。小端格式的意思是低有效字节先传输 高有效字节后传输例如 16-bit 数值0x1234在 HCI 原始字节中会表示为34 12再比如 32-bit 数值0x12345678在 HCI 原始字节中会表示为78 56 34 12这个规则非常重要。因为 HCI 中很多字段都是多字节字段例如Opcode Connection_Handle Conn_Interval Supervision_Timeout Company_Identifier看 btsnoop 日志时不能直接按字节显示顺序理解数值而要按小端方式还原。例如日志中看到18 00它表示的是0x0018不是0x1800关键信息 2参数顺序默认按照规范表格顺序排列原文说Unless noted otherwise, the order of parameters in an HCI Command packet or HCI Event packet is the order the parameters are listed in the command or event.意思是除非特别说明HCI Command packet 或 HCI Event packet 中的参数排列顺序就是规范中参数表列出的顺序。例如规范中某个命令的参数表是Parameter_A Parameter_B Parameter_C那么这个 HCI Command 的参数部分就是Parameter_A Parameter_B Parameter_C不能自己调整顺序。这个规则对于解析 HCI 日志非常关键。因为在 btsnoop 中看到的通常是一串十六进制字节。要解析它必须先找到对应命令或事件的参数表然后按照表格顺序一个字段一个字段拆出来。关键信息 3数组参数的排列方式规范中数组参数通常写成ParameterA[i]如果有多组数组参数例如ParameterA[i] ParameterB[i]那么默认排列方式是ParameterA[0], ParameterB[0], ParameterA[1], ParameterB[1], ParameterA[2], ParameterB[2], ... ParameterA[n], ParameterB[n]而不是ParameterA[0], ParameterA[1], ParameterA[2], ParameterB[0], ParameterB[1], ParameterB[2]这个点很重要。因为很多 HCI Event 会一次返回多个对象例如多个连接、多个广播报告、多个句柄等。规范的默认逻辑是第 0 个对象的一组字段 第 1 个对象的一组字段 第 2 个对象的一组字段而不是把同一种字段全部集中放在一起。关键信息 4数组参数的描述通常只描述单个元素原文说The description of an arrayed parameter will actually describe a single element of the array.意思是当规范描述数组参数时描述的是数组里的一个元素而不是整个数组。例如Connection_Handle[i]规范中对它的说明可能是Connection handle for the connection.这个描述实际表示每一个 Connection_Handle 元素都是某条连接的句柄也就是Connection_Handle[0] Connection_Handle[1] Connection_Handle[2] ...每个元素都按同一个规则理解。关键信息 5多字节参数最低有效字节先传输原文中又进一步说明for multi-octet parameters the rightmost, Least Significant Octet is transmitted first意思是对于多 octet 参数最右边的最低有效字节先传输。这里的octet 8 bit 1 byte例如0x1234最右边的0x34是最低有效字节所以先传34 12这和 little-endian 是同一个核心规则只是说得更具体。关键信息 6大多数参数是固定长度原文说大多数非数组参数以及数组参数中的每个元素都是固定长度的。例如Status1 octet Connection_Handle2 octets BD_ADDR6 octets RSSI1 octet这些字段的长度是确定的解析时可以按照固定长度直接切分。例如Status 1 byte Connection_Handle 2 bytes BD_ADDR 6 bytes关键信息 7部分参数是可变长度有些参数不是固定长度而是可变长度。这种情况下规范会在具体命令或事件中说明并且通常会用另一个字段表示它的长度。典型结构是Data_Length Data例如 BLE 广播数据相关字段Advertising_Data_Length Advertising_Data如果Advertising_Data_Length 0x0A表示后面的Advertising_Data实际长度是 10 字节。所以解析可变长度字段时不能固定切 31 字节、255 字节而是要先看 Length 字段。关键信息 8可变长度参数会受到整个 packet 最大长度限制原文还补充说如果一个 command 或 event 有数组参数或者有可变长度参数那么决定长度的参数可能导致整个 HCI Command / Event packet 太大超过最大允许长度。这时实际有效最大值可能会小于规范中单独写的最大值。简单理解某个字段理论最大可以很大 但是整个 HCI packet 本身有最大长度限制 所以它实际能用的长度可能更小例如一个事件里有多个 report每个 report 又有可变长度数据那么Number_of_Reports Data_Length Report 内容这些字段组合起来不能超过 HCI Event packet 的最大长度。关键信息 9bit string 的最低位 bit 在右边原文说Where bit strings are specified, the low order bit is the right hand bit意思是当规范使用 bit string 表示字段时最低位 bit 在右边。例如0b10右边的0是 bit 0左边的1是 bit 1。所以0b10表示bit 1 1 bit 0 0再比如0b00000101表示bit 0 1 bit 2 1 其他 bit 0这个规则在看 bit mask、feature bit、flag 字段时非常重要。不要从左边开始数 bit 0而是要从右边开始数。关键信息 100xXX / N 0xXX 表示一类值原文说如果一个参数值描述为0xXX或者N 0xXX那么这个描述适用于所有可能的值除非某些值有单独说明。这个主要是在解释规范的写作方式。例如某个字段可能写0xXX: 某种通用含义那么只要没有被单独列出的其他值都适用这个描述。如果规范说明某个范围之外的值是 reserved那么这些值就是保留值不能作为有效值使用。关键信息 11未知值或未知 opcode 应被忽略不能导致系统停止工作原文说Parameter values or opcodes that an implementation does not know how to interpret shall be ignored... The Host or Controller shall not stop functioning because of receiving a reserved value.意思是如果 Host 或 Controller 收到了自己不认识的参数值或 opcode应当忽略它并且用正确的信令完成当前正在尝试的操作。最关键的是不能因为收到 reserved value就导致 Host 或 Controller 停止工作。这体现的是蓝牙协议的兼容性设计。因为蓝牙协议会不断升级新版本可能增加新的 opcode、新的参数值、新的 feature bit。旧设备不认识这些新值是正常的。正确处理方式是不认识 ↓ 忽略或按规范返回合适错误 ↓ 继续正常工作错误处理方式是不认识 ↓ 协议栈异常 ↓ 蓝牙功能崩溃这对你写 App 或 SDK 解析蓝牙日志也有启发解析到未知值时不要让程序崩溃 应该保留兼容处理 未知字段可以记录日志但不能直接中断整个流程。关键信息 12Controller 默认应支持所有有效参数值原文最后说除非特别说明例如Mandatory Range或者某个值对应的是可选功能但当前设备不支持否则 Controller 应支持所有参数的有效值。这里要区分valid values有效值 reserved values保留值例如某个参数定义为0x00Disable 0x01Enable 0x02-0xFFReserved for future use那么 Controller 应该支持0x00 0x01但不需要支持0x02-0xFF因为后者是 reserved values不是 valid values。四、这部分对你看 HCI 日志有什么帮助以后你看 btsnoop 或 HCI 原始数据时可以按这个思路解析1. 先确定 packet 类型Command、Event、ACL Data 等。 2. 再确定具体 Opcode 或 Event Code。 3. 找到规范中对应命令或事件的参数表。 4. 按参数表顺序依次解析字段。 5. 遇到多字节字段按 little-endian 还原。 6. 遇到 Length 字段按 Length 决定后面可变数据长度。 7. 遇到数组字段按一组一组对象解析。 8. 遇到 bit string从右边开始数 bit 0。 9. 遇到 unknown / reserved value不要直接认为设备必须崩溃要看规范要求如何忽略或返回错误。五、结合一个简单例子理解假设某个 HCI Event 的参数定义为Status 1 octet Connection_Handle 2 octets Data_Length 1 octet Data variable RSSI 1 octet原始数据是00 0B 00 03 AA BB CC C5按规则解析Status 00 Connection_Handle 0B 00小端还原为 0x000B Data_Length 03 Data AA BB CC RSSI C5这里最关键的是Connection_Handle 不能解析成 0x0B00 而应该解析成 0x000B因为 HCI 默认使用 little-endian。六、这部分可以总结为这部分内容讲的是HCI 数据格式和参数格式的通用规则。核心结论是1. Controller 返回的参数必须真实、准确地反映实际情况。 2. HCI 中多字节参数默认使用 little-endian 小端格式。 3. HCI Command / Event 中参数顺序默认按照规范表格顺序排列。 4. 数组参数默认按对象顺序交错排列。 5. 大多数参数是固定长度少数参数是可变长度。 6. 可变长度字段通常由另一个 Length 字段决定。 7. bit string 的 bit 0 在最右边。 8. 未知参数值或 opcode 应被忽略不能导致 Host 或 Controller 停止工作。 9. Controller 默认应支持所有规范定义的有效参数值reserved values 不属于有效值。这一节是阅读 HCI 章节的基础。理解它之后再看具体的 HCI Command 和 HCI Event就不会只是看到一堆十六进制字节而是可以按照字段顺序、长度、小端格式、数组规则和 bit 规则把它们还原成真正的协议含义。