两种存储模式:
一般来说,我们看到的一些字符串形式的数字都是大端存储形式:
但是以上的写法只是方便人们看,存到机器里面还得是字节的形式,怎么存也得根据芯片和软件的规定来看。
有关数据发送,ESP32的变量是小端存储的,假如要发送一个16位变量,即uint16_t data = 0x0001(就是订阅通知时要写到特征描述符里的数据),实际上等同于发送了[0x01,0x00]两个字节。
有关数据接收,假如收到了一个4个字节的数据,存在buf数组里,要将它合成为一个为整形,可以逐个取出来进行运算合成;如果明确知道buf的低地址存的是低字节,而机器又是小端模式存储变量的,就也可以直接 int data = *(int *)buf,就是将字节指针转换成int类型的指针,然后取值。
BLE 设备地址长度为 6 字节,外加 1 个比特表示地址类型。
BLE 规范定义了若干种地址类型:
在另外一个角度来说,用于识别设备身份的只有公共地址和随机静态地址两种,设备必须设置这两种中的一种来对外表明自己的身份。
PDU: 协议数据单元 (Protocol Data Unit)。由上图可见,数据包中的PDU在2-257字节之间,具体又分为LL Header、Payload和MIC三个部分。其中Payload最大为251字节,包含L2CAP Header、ATT Header 和 ATT Payload 三部分,而ATT Payload 才是我们真正发送的数据(ATT Data),最大为244字节。
DLE:数据长度扩展 (Data Length Extensions)。该功能在蓝牙核心规范 4.2 版本中引入,允许Payload容纳更多数据(最多 251 字节,默认为 27 字节)。即,在不开启DLE的情况下,一个数据帧的payload部分最多为27字节,除去两个Header共7个字节,有效数据仅有20个字节。而在开启DLE的情况下,单个数据包可以发送244个字节的有效数据。
MTU: 最大传输单元(Maximum Transmission Unit)。这是一个跟所使用协议栈有关的参数,描述的是一次 GATT 操作(例如,写、读等操作)中可以发送的数据量。由于MTU已经包含了ATT Header的3个字节,因而调用一次相关函数api时可以传入的有效数据量最大为(MTU-3)。当MTU的设置大于单个数据包最大长度时,协议栈就会分包发送。以下是几种情况。
总的来说,MTU更多的是一个应用层编程时的概念,芯片厂商在根据自己芯片的性能和资源去订制协议栈时,一般会限定MTU的最大值,目前最大MTU一般在500到1000之间。至于单个数据包的最大长度则是由蓝牙规范严格规定的,开启DLE时最多为251字节,当需要发送的有效数据大于244(即MTU大于247)时,就会发生分包。因此,编程时需要合理选择MTU,以减少分包导致的资源浪费。
另外,由于主从机协议栈处理数据的能力不同,因而需要主从机对MTU进行协商。比如A协议栈的MTU设置为555,即调用一个write函数就可以最多发送552个字节的有效数据,然而接收端B协议栈的处理能力可能较弱,或者内存不足接收不了那么多数据,也就无法从接收到的多个数据包中提取出这552个字节。为此,刚连接时,主从机都必须使用23字节的默认MTU进行通信,之后双方进行协商,使用两者提出的MTU之中较小的MTU进行后续的通信。
以上部分图片来自Nordic。