BLE Link Layer【Bit Ordering】:为什么 b0 b1 b2 = 110 表示 3,而不是 6?
下面这部分是 BLE Link Layer 规范里的Bit ordering比特顺序。它主要讲的是规范中字段的 bit 怎么编号、空口发送时 bit 的先后顺序、多个 octet 字段的发送顺序以及图示中的字段发送顺序。一、原文翻译1.2 Bit ordering1.2 比特顺序在 Link Layer 规范中当定义 packet 或 Protocol Data Unit简称 PDU里面的字段时比特顺序遵循little-endian格式。适用以下规则Least Significant Bit简称 LSB对应b0LSB 是第一个通过空口发送的 bit在图示中LSB 显示在左侧此外在 Link Layer 中定义的数据字段例如 PDU header 字段应当以LSB first的方式发送。例如一个 3-bit 参数X 3的发送方式如下b0 b1 b2 110在空口中1先发送接着发送1最后发送0。在规范中这会显示为110。规范中按照0b10101010这种格式指定的二进制字段值书写时是MSB 在左侧。例如 Section 2.1.2 中 advertising physical channel Access Address就是按照这种方式写的。多 octet 字段除了 Cyclic Redundancy Check简称 CRC以及 Message Integrity Check简称 MIC 之外应当以least significant octet first的方式发送。每个 octet 内部除了 CRC 之外应当以LSB first的顺序发送。例如advertising physical channel PDU 中的 48-bit 地址应当先发送最低有效 octet然后按照递增顺序发送剩余 5 个 octet。规范中指定的多 octet 字段值书写时是most significant octet 在左侧。例如0x112233445566其中 octet0x11是 most significant octet。当一个 packet 或 PDU 在图中显示为包含多个字段时这些字段应当按照图中显示的顺序发送最左侧字段先发送。二、必要 TipTip 1这部分最核心的问题是“规范怎么看空口怎么发”这部分内容非常容易让人混乱因为它同时涉及三件事1. bit 编号怎么定义 2. 规范里的字段值怎么书写 3. 空口实际发送顺序是什么简单说规范书写经常按人类习惯MSB 写在左边 空口发送很多字段按 LSB first 发送 多 octet 字段通常 least significant octet first 图中字段字段本身按图中从左到右发送所以不能只看规范里的显示顺序就直接认为空口也是完全按这个视觉顺序逐 bit 发送。Tip 2LSB 是 b0并且通常先发规范明确说The Least Significant Bit (LSB) corresponds to b0. The LSB is the first bit sent over the air.也就是说b0 是最低有效 bit b0 通常也是第一个在空口发送的 bit例如一个 3-bit 字段X 3二进制值是3 0b011如果字段定义为b0 b1 b2那么b0 1 b1 1 b2 0所以规范显示成b0 b1 b2 110空口发送顺序也是先发 b0 1 再发 b1 1 最后发 b2 0也就是1 - 1 - 0这里最容易误解的是110不是说这个值等于二进制0b110而是在按b0 b1 b2的顺序展示每个 bit。Tip 3b0 b1 b2 110不等于普通二进制写法0b110这个点非常关键。在普通二进制写法里0b110 6因为普通二进制默认是MSB 在左LSB 在右但是规范这里写b0 b1 b2 110它表达的是b0 1 b1 1 b2 0所以字段值其实是X b0 × 2^0 b1 × 2^1 b2 × 2^2 X 1 × 1 1 × 2 0 × 4 X 3因此b0 b1 b2 110表示的值是3不是6。这是看 BLE Link Layer 字段定义时很容易踩坑的地方。Tip 40b10101010这种写法仍然是 MSB 在左规范后面又说Binary field values specified in the specification that follow the format 0b10101010 are written with the MSB to the left.意思是只要规范用 0bxxxx 这种格式写二进制值就是 MSB 在左。比如0b10101010这个时候就不要再按b0 b1 b2...的展示方式理解。它就是普通二进制写法最左边是 MSB 最右边是 LSB所以要区分两种表达b0 b1 b2 110这是按 bit 编号顺序展示。0b110这是普通二进制数值写法MSB 在左。二者不能混为一谈。Tip 5多 octet 字段通常是 least significant octet first规范说Multi-octet fields ... shall be transmitted with the least significant octet first.也就是说多 octet 字段通常是低字节先发 高字节后发例如规范中写一个 6 字节字段值0x112233445566其中0x11 是 most significant octet 0x66 是 least significant octet因为多 octet 字段通常 least significant octet first所以空口发送 octet 顺序是0x66 - 0x55 - 0x44 - 0x33 - 0x22 - 0x11但是注意这是“octet 顺序”。每个 octet 内部的 bit 发送顺序通常仍然是 LSB first。Tip 6BLE 地址字段发送时也是低字节先发规范里举了 48-bit address 的例子。例如一个地址值写作A1:B2:C3:D4:E5:F6从多 octet 字段值的书写角度看可以理解为0xA1B2C3D4E5F6其中A1 是 most significant octet F6 是 least significant octet那么作为 48-bit 地址字段发送时空口 octet 顺序通常是F6 - E5 - D4 - C3 - B2 - A1但是很多 App 或抓包工具显示地址时通常显示为A1:B2:C3:D4:E5:F6所以不要把“工具显示顺序”和“空口发送顺序”直接等同。这也是为什么看广播包 raw data、HCI Event、空口抓包时经常会遇到地址字节顺序看起来反过来的情况。Tip 7CRC 和 MIC 是例外不能机械套用所有规则规范中特别提到with the exception of the Cyclic Redundancy Check (CRC) and the Message Integrity Check (MIC)也就是说多 octet 字段的发送顺序规则CRC 和 MIC 有例外。尤其 CRC 在 BLE Link Layer 中有自己专门的生成、移位和发送规则。所以看到 CRC 时不要简单套用多字节字段 低字节先发 每字节 LSB firstCRC 要回到 CRC 对应章节单独看。Tip 8图里的多个字段是左边字段先发最后一句也很重要Where a packet or PDU is shown in a figure as containing more than one field, the fields shall be transmitted in the order shown in the figure, leftmost first.意思是如果图中一个 packet 或 PDU 包含多个字段那么字段按照图中的顺序发送最左边字段先发送。注意这里说的是“字段顺序”不是字段内部的 bit 顺序。也就是说字段之间图中从左到右发送 字段内部按字段自己的 bit / octet ordering 规则发送例如一个图中画成Field A | Field B | Field C那么字段发送顺序是Field A - Field B - Field C但是 Field A 内部每个 bit 或每个 octet 怎么发还要看它自己的字段定义。Tip 9不要把 bit ordering、byte ordering、字段顺序混成一件事看 BLE 规范时至少要分清三层顺序1. 字段顺序 Field order 2. 字节顺序 Octet order / Byte order 3. bit 顺序 Bit order它们不是同一个概念。字段顺序图中多个字段Preamble | Access Address | PDU | CRC发送顺序是Preamble 先发 Access Address 后发 PDU 再发 CRC 最后发字节顺序多 octet 字段通常least significant octet first也就是低字节先发。bit 顺序每个 octet 内部通常LSB first也就是低 bit 先发。所以 BLE Link Layer 里的“顺序”不能只用一句“大端”或“小端”概括必须看具体层级。Tip 10为什么这部分对 HCI 和广播包解析很重要你之前一直在看 BLE Legacy 广播、HCI Command、Advertising Data、Scan Response Data、Advertising Report这部分其实非常有用。因为当你解析这些内容时经常会遇到字段值在规范中是一个顺序 HCI Event 里显示是一个顺序 抓包工具里显示又是一个顺序 空口实际发送顺序可能还不同比如Device Address Access Address PDU Header Advertising Data Company Identifier UUID CRC这些字段都可能涉及 bit 顺序、byte 顺序或者显示顺序的问题。如果不了解这部分就容易出现为什么地址字节顺序反了 为什么规范写的 bit 和我理解的数值对不上 为什么 b0 b1 b2 110 代表 3不是 6 为什么多字节字段显示是 0x112233445566但发送时从 0x66 开始所以这部分虽然短但它是后面看 PDU 格式、地址字段、Access Address、Header bit 位定义时的基础。