低功耗蓝牙BLE的详细解读(2024 6.3更新)

目录

前言

1、BLE无线技术的概念

 2、BLE通信信道分析

3、BLE无线网络拓扑结构

广播组结构与星型结构的一对多区别

4、BLE协议栈

PHY层(Physical layer物理层)

LL层(Link Layer链路层)

HCI(Host controller interface)

GATT(Generic attribute profile )

ATT(Attribute protocol)

GAP层(Generic access profile)

SMP(Secure manager protocol)

L2CAP层(Logic link control and adaptation protocol)

5、BLE广播与扫描

5.1 广播事件

5.2 广播帧格式

前导(8bit):

接入地址(32bit)

广播报文类型(4bit)

发送地址类型和接收地址类型(各占1bit)

长度(8bit)

数据(0~296bit)

广播数据

校验(24bit)

5.3 广播帧位段定义的原因与含义

6、BLE数据连接建立过程

6.1 广播与扫描

6.2 建立连接

6.3 BLE报文格式

LLID(2bits)

NESN/SN(各占1bit)

MD(1bit)

RFU (Reserved for Future Use 3bit)

Length(5bit)

RFU (Reserved for Future Use 3bit)

数据净荷(Payload 2B-31B)

L2CAP PDU Length(2B)

L2CAP Channel ID (2B)

Opcode PDU (1B)

MIC(Message Integrity Check 4bit)

6.4 BLE空中包位段定义的原因与含义解析


前言

其实学习单片机在我目前看来最重要的知识点可以划分为两个,第一个为微操作系统的移植,第二个为通讯技术的使用。前者可以降低系统的响应时间,通过任务优先级与任务调度的处理可以清晰化开发逻辑。第二个通信技术的使用才可以达到通过无线设备进行操纵,毕竟是万物互联的时代。至于微操作系统可学的有国外的freetos与国内的开源openharmony。通信技术则需要都熟练掌握,主流的协议有蓝牙协议和WiFi协议。现在这个专栏就是记录初步了解蓝牙技术的相关知识点。

通信协议是严格定义交换信息的设备的硬件和软件应如何执行每个通信功能的规则手册。

在通信协议(又名规则手册)中,您会找到以下内容的规则:

  • 设备应如何识别自己

  • 他们应该如何建立、维护和结束连接

  • 他们可以发送什么样的数据,以及他们应该如何格式化它

  • 他们如何确保数据被两端正确接收和理解

  • 设备应该使用什么调制和通道

  • 设备应该使用什么错误编码技术

  • 应如何保护交换的信息

  • 通信协议基于多种因素,包括要交换的信息的特性、通信媒介以及将使用它的设备的功能。

1、BLE无线技术的概念

        BLE无线技术,即蓝牙低功耗(Bluetooth Low Energy)技术,是一种低成本、短距离、可互操作的鲁棒性(鲁棒性是指系统或者器件在不同的环境或者条件下,能够保持其功能或者性能的特性)无线技术,工作在免许可的2.4GHz ISM射频频段。它是基于蓝牙4.0规范下的LE蓝牙发展而来的,与传统蓝牙相比,最大的特点是成本和功耗降低,特别适用于实时性要求比较高的场景。
         BLE技术利用许多智能手段最大限度地降低功耗,如通过采用优化后的协议栈和高效的信号调制技术,BLE设备在传输数据时功耗极低,从而使得设备能够拥有更长的使用寿命。此外,BLE技术还支持高速数据传输,最高传输速率可达2Mbps,可满足大部分无线通信需求。同时,它采用了多种安全机制,如加密、认证、防止重放攻击等,确保数据传输的安全性。
   

 2、BLE通信信道分析

        通信时需要使用到天线,天线的主要功能可以概括为:完成无线电波的发射与接收。 发射时,把高频电流转换为电磁波发射出去:接收时,将电磁波转换为高频电流。为了防止不必要的干扰,国家规定了在不同频带上使用的发射功率。

        BLE工作在ISM频带,定义了两个频段,2.4GHz频段和896/915频带。BLE(蓝牙低功耗)在2.4GHz频段定义的每个信道占用2MHz的带宽。这个频段被分为40个信道,编号从0至39,每个信道宽为2MHz。其中有3个广播信道和37个数据信道。这些信道用于BLE设备之间的无线通信,包括设备发现、连接建立和数据传输等功能。BLE有自适应调频技术。

        想要被发现的BLE设备会在RF37、RF38和RF39通道上发送信号。当一个设备想要找到其他设备时。它会在主要广告通道上侦听广告数据包。

3、BLE无线网络拓扑结构

        BLE网络可以点对点或者点对多,一个ble主机可以连接多个ble从机,组成星型网络。

        星型网络是指在一个网络结构中,存在一个中心节点(通常称为主机或集线器),其他所有节点(从机)都直接连接到这个中心节点上。在BLE(蓝牙低功耗)网络中,一个BLE主机可以连接多个BLE从机,形成这样的星型网络结构。在这种结构中,主机负责协调和管理所有从机,而从机则通过主机进行通信。

另外还有一广播设备和多个扫描设备组成的广播组结构。广播组结构与星型结构的一对多区别:

  • 逻辑与物理:广播组是一个逻辑上的概念,关注的是消息的发送和接收方式;而星型网络是一个物理上的概念,关注的是设备之间的连接方式。
  • 控制点:在广播组中,消息发送者控制消息的发送;在星型网络中,中央节点控制数据的转发。
  • 目的:广播组是为了实现一对多的消息发送;而星型网络是为了方便网络管理和维护,以及提供可靠的数据传输。

4、BLE协议栈

        一般在嵌入式的开发中都会有调库这个思想,而蓝牙协议栈就相当于协议的具体实现形式。通俗的理解为用代码实现的函数库,以便于开发人员调用。BLE协议栈将各层的协议都集合在一起,以函数库的形式实现,并给用户提供应用程API函数接口,供开发人员调用。BLE协议栈主要用来对需要发送的应用数据进行层层封包,以生成一个满足BLE协议的空中数据包。也就是说,把应用数据包裹在一系列的帧头(header)和帧尾(tail)中。BLE协议栈的结构和配置图如图2-1所示。

4-1 BLE协议栈框图

       

BLE协议分层的原因:减少代码内部整体的关联性,易于代码维护。如果某一层的协议改变,只用更改对应的层即可,也方便代码迭代。

这里是核心部分,接下来从物理层开始对各层之间的功能作具体的解析,这里先列举作用,具体的实现有机会在补充。

4.1 物理层(Physical Layer)

        PHY层用来指定BLE所用的无线频段,调制解调方式和方法等。PHY层做得好不好,直接决定整个BLE芯片的功耗,灵敏度以及selectivity等射频指标。

蓝牙PHY层(Physical Layer物理层)在蓝牙通信中的主要作用包括:

  1. 规定基础射频参数:PHY层规定了BLE(蓝牙低功耗)通信的基础射频参数,这些参数包括信号频率、调制方式等。例如,BLE使用1Mbps(蓝牙5.0还支持2Mbps)自适应跳频的GFSK(高斯频移键控)射频,工作在2.4GHz频段(2400MHz~2480MHz)。
  2. 信号调制与解调:PHY层定义了BLE的调制方式,即如何将数字信号转换为模拟信号进行传输,以及如何将接收到的模拟信号还原为数字信号。在BLE中,通常使用GFSK作为调制方式。
  3. 频段与通道管理:PHY层指定了BLE使用的无线频段,并定义了频段的范围。此外,它还管理了BLE的通信通道,包括数据通道和广播通道。这些通道的设置有助于减少不同设备之间的干扰,提高通信质量。
  4. 实现与硬件设备的接口:PHY层还负责实现与硬件设备的接口,确保数字数据能够正确转换为无线信号,并通过硬件设备发送出去。同时,它也能够接收硬件设备接收到的无线信号,并将其转换为数字数据。
  5. 影响射频指标:PHY层的设计和实现直接影响到整个BLE芯片的功耗、灵敏度以及选择性等射频指标。一个优秀的PHY层设计可以带来更好的通信性能和更低的功耗。

4.2 链路层(Link Layer)

        LL层是整个BLE协议栈的核心,也是BLE协议栈的难点和重点。像Nordic的BLE协议栈能同时支持20个link(连接),就是LL层的功劳。LL层要做的事情非常多,比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK如何接收,如何进行重传,以及如何对链路进行管理和控制等等。LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者ATT。

蓝牙LL层(Link Layer链路层)在蓝牙通信中扮演着核心角色,主要负责以下几个方面的工作:

  1. 广播、扫描、建立和维护连接:链路层负责在设备之间广播信息,使其他设备能够发现和识别自己。同时,它还负责扫描周围的设备,寻找可以与之建立连接的设备。一旦找到目标设备,链路层将负责建立和维护连接,确保数据能够在两个设备之间可靠地传输。
  2. 数据包的组织、校验和加密:链路层负责确保数据包按正确的方式组织,包括添加必要的头部和尾部信息。它还负责生成和验证数据包的校验值,以确保数据的完整性和准确性。此外,链路层还提供了数据加密功能,以保护传输的数据免受未经授权的访问和篡改。
  3. 控制射频模块状态:链路层能够控制设备的射频模块处于不同的状态,包括待机、广播、扫描、正在启动或已连接等。这些状态的切换对于蓝牙设备的正常工作和节能非常重要。
  4. 定义设备角色:链路层定义了蓝牙设备在通信过程中的四种角色:广播设备、扫描设备、主设备和从设备。这些角色决定了设备在通信中的行为和功能。
  5. 数据传输和管理:一旦连接建立,链路层将负责在设备之间传输数据。它负责将数据封装成数据包,并在适当的时候将数据包发送出去。同时,链路层还负责接收来自其他设备的数据包,并将其传递给上层协议进行处理。此外,链路层还提供了重传机制,以确保数据在传输过程中的可靠性。

4.3 主机控制器接口层(Host controller interface,HCI)

        HCI是可选的,蓝牙HCI层的主要作用是为主机和控制器之间的通信提供标准化的接口和协议

        蓝牙HCI(Host Controller Interface)层在蓝牙通信中的主要作用是为Host(主机)和Controller(控制器)之间的通信提供一个标准的接口。具体来说,它主要完成以下几个任务:

  1. 命令发送:Host通过HCI层发送命令给Controller,以控制蓝牙设备的操作,如查询、连接、断开等。
  2. 事件发送:Controller通过HCI层将事件发送给Host,以通知Host蓝牙设备的状态变化或操作结果
  3. 数据传输:HCI层还负责在Host和Controller之间传递ACL Data(面向连接的数据),这些数据是在连接通道上进行传输的。

4.4 通用属性规范层(Generic attribute profile,GATT )

        GATT在蓝牙通信中起着至关重要的作用,它规范了数据内容、提供了数据传输和存储的架构、实现了数据的分类管理、确保了蓝牙设备的互联互通,并定义了设备角色和层次结构组织。

        蓝牙GATT(Generic Attribute Profile)是蓝牙协议栈中的一种重要协议,它在蓝牙通信中起着关键的作用。以下是GATT的主要作用:

  1. 数据传输和存储架构:GATT层是传输真正数据所在的层,它提供了一个数据传输和存储的架构以及基本操作。这个架构使得两个蓝牙设备之间可以高效、可靠地传输数据。
  2. 数据内容规范:GATT用来规范attribute(属性)中的数据内容Attribute是指一条带有标签的、可以被寻址的数据,每个属性都对应一个唯一的handle(句柄)。通过规范数据内容,GATT确保了数据的准确性和一致性。
  3. 数据分类管理:GATT运用group(分组)的概念对attribute进行分类管理。这种分类管理使得设备可以更加高效地处理和组织数据,提高了数据处理的效率。
  4. 蓝牙设备互联互通:虽然没有GATT,BLE(低功耗蓝牙)协议栈也能运行,但互联互通可能会出现问题。GATT和各种各样的应用profile使得BLE摆脱了Zigbee等无线协议的兼容性困境,成为了出货量最大的2.4G无线通信产品
  5. 定义设备角色:GATT定义了两类角色:服务端(server)和客户端(client)。服务端是数据的提供者,客户端是数据的请求者。这种角色定义使得设备之间的通信更加清晰和有序。
    蓝牙链路层定义的角色更多地关注于设备在蓝牙网络中的连接和传输行为,而GATT定义的角色则更多地关注于在已建立的连接上,设备之间如何进行数据的交互和通信。这两个层次的角色定义共同构成了蓝牙通信的完整框架。
  6. 层次结构组织:一个GATT服务器通过一个称为属性表的表格组织数据。这个属性表包含了用于真正发送的数据,以及数据的属性和描述。这种层次结构使得数据的管理和传输更加有序和高效。

4.5 属性协议层(Attribute protocol,ATT)

        简单来说,ATT层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。BLE协议栈中,开发者接触最多的就是ATT。BLE引入了attribute概念,用来描述一条一条的数据。Attribute除了定义数据,同时定义该数据可以使用的ATT命令,因此这一层被称为ATT层。

        ATT(Attribute Protocol)在蓝牙技术中起着至关重要的作用,它主要用于描述和管理设备的各种服务和特征,包括设备名称、服务、特征、描述等。以下是ATT协议的主要作用:

  1. 属性信息的描述和交换:ATT协议是一种轻量级的协议,用于在蓝牙设备之间传输和交换属性信息。这些属性信息描述了设备的状态、配置和其他相关信息。通过ATT协议,设备可以了解彼此的属性,以便进行相应的通信和数据交换。
  2. 定义服务端和客户端角色:ATT协议定义了两种角色:服务端(Server)和客户端(Client)。服务端是数据的提供者,它拥有并管理着一些数据属性(Attributes),这些属性可能包含设备的信息、状态、设置或者可以被远程控制的功能等。客户端是数据的请求者,它会向服务端请求特定的服务或特征的数据。
  3. 数据读写和通知:ATT协议允许客户端设备读取服务端设备的属性信息,并可以写入数据以更改设备的状态或配置。此外,服务端设备还可以主动通知客户端设备关于其属性值的变化,以便客户端设备能够实时了解设备的状态。
  4. 实现通信的规范:ATT协议是建立在GATT(Generic Attribute Profile)之上的一种协议,它定义了设备之间如何交换属性信息和实现通信的规范。这使得不同设备之间可以进行安全、高效的数据交换和通讯。
  5. 适用于多种应用场景:ATT协议的灵活性使得它适用于多种应用场景,从简单的传感器应用到复杂的物联网设备。通过ATT协议,这些设备可以相互通信,实现数据的共享和交换。

4.6 通用访问规范层(Generic access profile,GAP)

        GAP是对LL层payload(有效数据包)如何进行解析的两种方式中的一种,而且是最简单的那一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接等。

        GAP层(Generic Access Profile)是蓝牙低功耗(BLE)设备内部功能对外的接口层,它定义了BLE设备在通信过程中的一些基本行为和规范。GAP层的作用主要包括以下几个方面:

  1. 角色定义:GAP层定义了BLE设备在通信过程中的四种角色,分别是外围设备(Peripheral)、中央设备(Central)、播报设备(Broadcaster)和观察设备(Observer)。这些角色决定了设备在通信中的行为和功能。
  2. 广播和扫描:GAP层支持设备的广播和扫描功能。外围设备和播报设备可以发送广播数据,而中央设备和观察设备可以扫描周围的广播数据。这些功能使得BLE设备能够相互发现和建立连接。
  3. 连接管理:GAP层还负责处理设备的连接管理,包括连接的建立、更新、维护和终止。它定义了连接过程中的一些基本参数和规程,以确保设备之间的通信稳定和可靠。
  4. 安全功能:GAP层还提供了安全功能,如设备配对和加密传输等。这些功能可以保护设备的通信安全,防止数据泄露和非法访问。

        GAP层(Generic Access Profile)定义的四种角色(外围设备、中央设备、播报设备和观察设备)更侧重于设备在通信过程中的基本行为和功能。这些角色定义了设备如何发现和建立与其他设备的安全或不安全连接,以及它们之间的交互模式。

        而链路层(Link Layer)的角色定义(主设备、从设备、广播设备和扫描设备)则更侧重于通信过程中的物理层和数据传输方面的行为。链路层定义了设备在连接建立、数据传输、错误检测和纠正等方面的具体实现和操作。

        虽然GAP层和链路层都定义了设备的角色,但它们的侧重点和目的不同。GAP层关注于设备在通信过程中的行为和功能,而链路层则关注于通信过程中的物理层和数据传输方面的细节。因此,这两个层次的角色定义并不完全重复,而是相互补充,共同构成了BLE通信的完整框架。

4.7 安全管理层(Secure Manager ,SM)

        SMP用来管理BLE连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作。

        SMP(安全管理协议)在蓝牙通信中扮演着至关重要的角色,主要作用在于确保蓝牙设备之间的通信安全。以下是其具体作用:

  1. 配对和密钥分发:SMP定义了配对和密钥分发的过程,确保两个蓝牙设备在建立连接之前,能够通过安全的方式交换信息并生成共享的密钥。这个过程是建立安全通信的基础。
  2. 加密通信:通过配对和密钥分发过程生成的密钥,SMP能够用于对蓝牙设备之间的通信进行加密。加密后的通信数据在传输过程中不易被窃取或篡改,从而保护用户数据的隐私和安全。
  3. 安全性管理:SMP不仅涉及密钥的生成和分发,还负责在设备连接过程中进行安全性管理。这包括验证设备的身份、检测潜在的安全威胁以及采取适当的措施来应对这些威胁。
  4. 提供灵活的安全策略:SMP支持多种安全策略,可以根据不同的应用场景和需求进行灵活配置。这使得蓝牙设备能够适应不同的安全环境,并提供更加可靠的安全保护。

4.8 逻辑链路控制和适配协议层(Logic link control and adaptation protocol,L2CAP)

L2CAP对LL进行了一次简单封装,LL只关心传输的数据本身,L2CAP就要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。

L2CAP层(Logic Link Control and Adaptation Protocol)在蓝牙通信中扮演着关键的角色,它是蓝牙协议栈中的一部分,主要提供数据链路层的服务。以下是L2CAP层的主要作用和功能:

  1. 协议复用(Multiplexing):L2CAP层允许多个协议栈或应用程序同时共享相同的底层连接,从而实现复用。这使得蓝牙设备能够同时处理多种服务或任务,提高了通信效率。
  2. 分段与重组(Segmentation and Reassembly):由于蓝牙通信的底层带宽限制,L2CAP层需要将较大的数据包进行分割以适应传输,同时在接收端进行重组以恢复原始数据。这种机制确保了大数据包的可靠传输。
  3. 流量控制(Flow Control):L2CAP层支持每个信道的流量控制,这意味着它可以根据接收方的处理能力调整发送方的数据发送速率,从而避免数据丢失或缓冲区溢出。
  4. 错误控制(Error Control):L2CAP层提供了错误检测机制,能够检测并报告传输过程中出现的错误。虽然它本身不提供重传机制,但可以与底层协议配合实现可靠的数据传输。
  5. 提供逻辑通道(Logical Channels):L2CAP层为上层协议和应用提供了逻辑通道,这些通道在一条或多条逻辑链路上复用。这使得上层协议可以独立于底层物理连接进行数据传输和处理

5、BLE广播与扫描

在这里需要注意的点:

广播包:长度域包含6个比特,有效值的范围是6~37。

数据包:长度域包含5个比特,有效值的范围是0~31。(原BLE4.0 4.1中 规定数据长度5个比特)

5.1 广播事件

        在BLE(蓝牙低功耗)连接中,并不是两个设备都广播。实际上,在连接建立之前,通常是一个设备(通常称为外围设备或广播者)进行广播,而另一个设备(通常称为中央设备或扫描者)则进行扫描以发现广播设备。在连接过程中,必定有相应的广播帧格式。在BLE通信过程中,假设设备A需要连其他设备假设为B,则A需要不断地发送广播信号(此过程一般有一个时间间隔,在没发送广播数据时间内,芯片处于低功耗状态),每发送一次广播包,称之为一次广播事件。

5.2 广播帧格式

5-1 广播帧格式

前导(8bit):

前导:是一个8比特的交替序列

  • 接入地址的第一个比特为0:01010101
  • 接入地址的第一个比特为1:10101010

Note:BLE前导是一个固定的交替序列,用于提供可识别的序列,使得接收端能够准确地识别并同步到发送端的信号,从而确保后续数据的正确接收;还可以通过接受并分析BLE前导信号来计算出信号的频率偏移,并进行相应的补偿,从而保持与发送端在频率的一致性
这里对这计算频率偏移并补偿的原理做一点小小的解释

        如果接收端与发送端之间存在频率偏移,接收到类似于11001001这样的序列。接收端会尝试不同的频率偏移值(例如,以一定的步长增加或减少本地振荡器的频率),并对于每个偏移值,都计算接收到的序列与预期的10101010序列之间的相关性(或相似度)。当找到一个频率偏移值,使得接收到的序列与预期序列之间的相关性最高时,接收端就认为这个偏移值是当前信号的粗频偏估计值。一旦得到了粗频偏估计值,接收端就可以使用它来调整本地振荡器的频率,从而补偿接收到的信号中的频偏。经过补偿后,接收端就能更准确地解码后续的数据了。

简单来说,就是对不符合设定的前导信号与接收端原本就计算出的频偏模板进行匹配,得到频偏值,再进行调制。

接入地址(32bit)

广播接入地址0x8E89BED6(低字节在前)
数据接入地址:随机值,不同的连接有不同的值。在建立连接之后的两个设备间使用
这里的数据接入地址指的是BLE建立连接后,接收数据的设备地址。

广播报文的报头

包含4bit广播报文类型、2bit保留位、各占1bit的发送地址类型和接收地址类型。

广播报文类型(4bit)

5-2 广播报文类型

BLE(Bluetooth Low Energy,蓝牙低功耗)广播报文的主要类型包括以下几种:

  1. 可连接非定向广播(ADV_IND)
    • 这种广播类型允许任何设备扫描并尝试连接。
    • 它可以回复扫描响应包。
    • 是最常用的广播方式。
  2. 可连接定向广播(ADV_DIRECT_IND)
    • 专门用于与特定设备建立连接。
    • 它不能被其他非指定设备连接。
    • 通常包含广播者的地址和发起者的地址,发起者收到定向广播后可以立即发送连接请求。
  3. 不可连接非定向广播(ADV_NONCONN_IND)
    • 既不能被连接也不能回复扫描响应包。
    • 通常用于发送广播数据,如信标、传感器数据等。
  4. 主动扫描请求(SCAN_REQ)
    • 当一个BLE设备(通常是Central设备)在主动扫描模式下,检测到另一个BLE设备(通常是Peripheral设备)的广播后,它会向该Peripheral设备发送一个SCAN_REQ包。
    • SCAN_REQ包通常包含扫描者地址(ScanA)和广播者地址(AdvA),用于标识请求的来源和目标。
  5. 主动扫描响应(SCAN_RSP)
    • 作为对SCAN_REQ的响应,Peripheral设备会向Central设备发送一个SCAN_RSP包。
    • SCAN_RSP包包含关于Peripheral设备的更多信息,如设备名称、服务UUID(Universally Unique Identifier,通用唯一识别码)等。。
  6. 可扫描非定向广播(ADV_SCAN_IND)
    • 不能被连接,但可以被扫描并回复扫描响应包。
    • 适用于一些网关子设备等场景。
  7. 不可连接定向广播
    • 这种类型在BLE的标准规范中可能没有明确的定义,但理论上可以存在。它可能是指一种针对特定设备的不可连接广播。
  8. 其他特定于应用的广播类型
    • 根据BLE的应用场景和需求,可能还存在其他特定的广播类型。这些广播类型通常由BLE协议栈或设备制造商定义,并用于特定的应用或场景。

Note:在BLE的通信过程中,广播报文(如ADV_IND、ADV_SCAN_IND等)和扫描请求/响应(SCAN_REQ/SCAN_RSP)是分开处理的。广播报文是由Peripheral设备主动发送的,用于通知其存在和可用性;而扫描请求/响应则发生在Central设备和Peripheral设备之间,用于进一步的设备发现和连接建立过程。

发送地址类型和接收地址类型(各占1bit)

0:公共地址

1:随机地址

公共地址(Public Address)是由制造商从IEEE申请,并由IEEE注册机构为该制造商分配的机构唯一标识符OUI(Organizationally Unique Identifier)。这个地址是独一无二的,不能修改,通常用于标识设备的制造商和特定的设备。

随机地址(Random Address)则是一种可选的地址类型,可以在设备需要隐藏其真实身份或增强安全性时使用。随机地址可以进一步细分为静态地址(Static Device Address)和私有地址(Private Device Address)。静态地址是由设备在首次启动时生成的固定地址,而私有地址则是设备在每次广播时都会生成的随机地址。

长度(8bit)

广播报文的长度存储需要使用8个比特,因为在发送广播数据时需要带上6个字节的广播地址。而广播数据为0~37个字节,所以广播报文的长度范围为6~37个字节。

广播者地址(6个字节)+广播数据(31个字节)

广播数据(31bit)

蓝牙广告数据基础知识 - v4.0 - 蓝牙 API 文档 芯科科技 (silabs.com)

分为有效数据和无效数据

广播数据
5-3 广播或扫描响应数据格式

有效数据部分包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成。其中的各参数解析如下:

Length AD Type和AD Data的长度之和,单位为字节,使用16进制表示。如020106,为2个字节。

AD Type 指示AD Data数据的含义
常用的数据类型如下:

  • 0x01 = 标志
  • 0x03 = 16 位服务类 UUID 的完整列表
  • 0x09 = 完整的本地名称
  • 0x08 = 缩短的本地名称

不常用的如下:

  • 0x02:不完整的服务类 UUID 列表(Incomplete List of 16-bit Service Class UUIDs)
               表示后面跟随的是部分(不完整)的16位服务类UUID列表。
  • 0x04完整的128位服务类 UUID 列表(Complete List of 128-bit Service Class UUIDs)
               表示后面跟随的是完整的128位服务类UUID列表。
  • 0x05缩短的服务类 UUID 列表(Shortened Local Name)
                这实际上与 0x08 重复了,但某些文档可能错误地标记为 0x05。实际上,0x05 通常不              用于表示缩短的本地名称。
  • 0x06设备类(Device Class)
               包含了关于设备类型和主要/次要服务类的信息。
  • 0x07简单配对哈希(C)(Simple Pairing Hash C)
               用于简单配对过程的一部分。
  • 0xA 或 0x0A:TX 功率级别(Tx Power Level)
               指示设备的发射功率级别。
  • 0xD 或 0x0D安全管理器(SM)TK 值(Security Manager TK Value)
               用于安全简单配对过程的一部分。
  • 0xE 或 0x0E安全管理器(SM)OOB 标志(Security Manager OOB Flags)
               用于指示设备是否支持带外(OOB)配对。
  • 0xF 或 0x0FSLAVE 连接间隔范围(Slave Connection Interval Range)
               指示从设备(SLAVE)可以接受的连接间隔范围。
  • 0x10 到 0x1F服务数据(Service Data - 16-bit UUID)
               这些值用于指定与特定16位UUID关联的服务数据。
  • 0x20 到 0x3F公共服务数据(Public Target Address)
               这些值保留用于未来的公共服务数据定义。
  • 0x2A 到 0x3F(在某些实现中):厂商特定数据(Manufacturer Specific Data)
               用于包含厂商特定的信息。注意,这里的范围可能与公共服务数据重叠,具体取决于               实现和文档。
  • 0xFF制造商特定数据(Manufacturer Specific Data)
                一个特殊的数据类型,用于包含厂商特定的信息。通常紧跟其后的是一个字节,表示              制造商ID,然后是厂商的数据。

AD Data具体响应的数据。在解读时字符串按字节顺序读,UUID反着读

  1. 字节顺序
    • 对于UUID、数字值和其他非字符串数据,通常使用大端字节序。
    • 字符串数据则根据其字符编码进行解析,与字节顺序无关。
  2. 字符串解析
    • 字符串数据通常是以某种字符编码(如UTF-8)表示的。在解析时,你需要按照该编码的规则来读取字节,并将其转换为对应的字符。
    • 例如,对于UTF-8编码的字符串,你可能需要读取一个或多个字节来构成一个字符,具体取决于字符的编码值。

范例:

5-4 广播或扫描响应格式示例

在该示例中,广告有效负载的最大长度为 31 字节。它被拆分为单独的 AD 元素,其方式与第一个示例相同。

第一个元素是 flags 字节,其值与第一个示例中的值相同。

第二个元素的 AD Type 设置为 0x07,这意味着 128 位服务类 UUID 的完整列表。在这种情况下,设备将播发已分配给自定义服务的 128 位 UUID。在BLE广播报文中,这个UUID会被表示为16个字节的序列,并且按照小端字节序排列。所以在这里,字节顺序是相反的。

第三个元素是设备名称。项目中定义的设备名称为“BGM111 SPP 服务器”。由于广告有效负载没有足够的空间来容纳完整名称,因此该名称将被截断。AD 类型 0x08 用于指示这是一个缩写名称。只有名称的前 8 个字符才能放入广告数据中,以满足 31 字节的大小限制。

Note:字符串在内存中的表示不会受到大小端(Endianness)字节顺序的影响,因为字符串是由一系列的字符组成的,而每个字符在ASCII或UTF-8等编码中通常都被映射到一个固定的字节值。这些字节值被连续地存储在内存中,以形成字符串的完整表示。不论是在大端字节序系统还是小端字节序系统中,字符串"lloo"的ASCII编码字节表示始终是0x6c 0x6c 0x6f 0x6f,并且这个字节序列总是被解释为相同的字符串"lloo"。这是因为ASCII编码是基于单字节字符的,不涉及多字节数值的字节顺序问题。

校验(24bit)

3个字节,为CRC校验

CRC校验的工作原理是,发送方在发送数据之前,会先使用预定的CRC算法对数据进行计算,得到一个CRC校验和,然后将这个校验和附加到数据的末尾一起发送。接收方在收到数据后,会使用相同的CRC算法对接收到的数据进行计算,得到一个新的CRC校验和。如果新的CRC校验和与接收到的CRC校验和相同,则说明数据在传输过程中没有发生错误;如果不同,则说明数据在传输过程中发生了错误,接收方会采取相应的措施(如丢弃该数据或请求重新发送)。

5.3 广播帧位段定义的原因与含义

深入浅出低功耗蓝牙(BLE)协议栈 - iini - 博客园 (cnblogs.com)

        假设有设备A和设备B,设备A要把自己目前的电量状态83%(十六进制表示为0x53)发给设备B,该怎么做呢?作为一个开发者,我们当然希望调用一个简单的API就能完成这件事,比如send(0x53),实际上BLE协议栈就是为此设计的,开发者只需调用send(0x53)就可以把数据发送出去了,其余的事情BLE协议栈帮你搞定。很多人会想,BLE协议栈是不是直接在物理层就把0x53发出去,就如下图所示:

图5-5 BLE中理想状态下的数据传输模式

                               位段定义的原因                                 

                                位段定义的原理                                 

        这种方式初看起来挺美的,但由于很多细节没有考虑到,实际是不可行的。首先,它没有考虑用哪一个射频信道来进行传输,在不更改API的情况下,我们只能对协议栈进行分层,为此引入LL层,开发者还是调用send(0x53),send(0x53)再调用send_LL(0x53,2402M)(注:2402M为信道频率)。这里还有一个问题,设备B不清楚数据的发送对象,为此BLE引入access address概念,用来指明接收者身份,其中,0x8E89BED6这个access address比较特殊,它表示要发给周边所有设备,即广播。如果你要一对一的进行通信(BLE协议将其称为连接),即设备A的数据包只能设备B接收,同样设备B的数据包只能设备A接收,那么就必须生成一个独特的随机access address以标识设备A和设备B两者之间的连接。

        我们先来看一下简单的广播情况,这种情况下,我们把设备A叫advertiser(广播者),设备B叫scanner或者observer(扫描者)。广播状态下设备A的LL层API将变成send_LL(0x53,2402M, 0x8E89BED6)。由于设备B可以同时接收到很多设备的广播,因此数据包还必须包含设备A的device address(0xE1022AAB753B)以确认该广播包来自设备A,为此send_LL参数需要变成(0x53,2402M, 0x8E89BED6, 0xE1022AAB753B)。LL层还要检查数据的完整性,即数据在传输过程中有没有发生窜改,为此引入CRC24对数据包进行检验 (假设为0xB2C78E) 。同时为了调制解调电路工作更高效,每一个数据包的最前面会加上1个字节的preamble(前导帧),preamble一般为0x55或者0xAA【二进制状态下为0和1组成的交替序列,主要用来同步和定时】。这样,整个空中包就变成(注:空中包用小端模式表示!):

图5-6 广播帧的初步形式

 上面这个数据包还有如下问题:

  1. 没有对数据包进行分类组织,设备B无法找到自己想要的数据0x53。为此我们需要在access address之后加入两个字段:LL header和长度字节。LL header用来表示数据包的LL类型,长度字节用来指明payload的长度。对整个数据帧的有效数据进行位置标注。
  2. 设备B什么时候开启射频窗口以接收空中数据包?如上图case1所示,当设备A的数据包在空中传输的时候,设备B把接收窗口关闭,此时通信将失败;同样对case2来说,当设备A没有在空中发送数据包时,设备B把接收窗口打开,此时通信也将失败。只有case3的情况,通信才能成功,即设备A的数据包在空中传输时,设备B正好打开射频接收窗口,此时通信才能成功,换句话说,LL层还必须定义通信时序
  3. 当设备B拿到数据0x53后,该如何解析这个数据呢?它到底表示湿度还是电量,还是别的意思?这个就是GAP层要做的工作,GAP层引入了LTV(Length-Type-Value)结构来定义数据,比如020105,02-长度,01-类型(强制字段,表示广播flag,广播包必须包含该字段),05-值。由于广播包最大只能为31个字节,它能定义的数据类型极其有限,像这里说的电量,GAP就没有定义,因此要通过广播方式把电量数据发出去,只能使用供应商自定义数据类型0xFF,即04FF590053,其中04表示长度,FF表示数据类型(自定义数据),0x0059是供应商ID(自定义数据中的强制字段),0x53就是我们的数据(设备双方约定0x53就是表示电量,而不是其他意思)。对有效数据进行解析。

整体的数据如下

图5-7 广播帧实例
  • AAD6BE898E600E3B75AB2A02E102010504FF5900538EC7B2
    • AA – 前导帧(preamble)
    • D6BE898E – 访问地址(access address)
    • 60 – LL帧头字段(LL header)【包括广播报文类型、发送和接收地址类型】
    • 0E – 有效数据包长度(payload length)
    • 3B75AB2A02E1 – 广播者设备地址(advertiser address)
    • 02010504FF590053 – 广播数据
    • 8EC7B2 – CRC24值。

6、BLE数据连接建立过程

6.1 广播与扫描

        广播:在设备A(通常是手机或中央设备)和设备B(例如蓝牙耳机或外围设备)建立连接之前,设备B需要先进行广播。广播是以一定的广播间隔周期性地广播数据,目的是让周围的设备能够发现并识别它。广播数据包中包含了设备B的一些基本信息,如设备名称、服务UUID等。

        扫描:设备A通过蓝牙模块发送指令开始扫描周围的蓝牙设备。在扫描过程中,设备A会接收到设备B广播的数据包,并解析其中的信息。

        设备B不断发送广播信号给手机(Observer),如果手机不开启扫描窗口,手机是收不到设备B的广播的。如下图所示,不仅手机要开启射频接收窗口,而且只有手机的射频接收窗口跟广播发送的发射窗口匹配成功,而且广播射频通道和手机扫描射频通道是同一个通道,手机才能收到设备B的广播信号。也就是说,如果设备B在37通道发送广播包,而手机在扫描38通道,那么即使他们俩的射频窗口匹配,两者也是无法进行通信的。由于这种匹配成功是一个概率事件,因此手机扫到设备B也是一个概率事件,也就是说,手机有时会很快扫到设备B,比如只需要一个广播事件,手机有时又会很慢才能扫到设备B,比如需要10个广播事件甚至更多。

图6-1 BLE广播与扫描匹配图

6.2 建立连接

        建立连接请求:设备A在发现设备B后,会向设备B发送连接请求。这个连接请求通常是通过发送一个连接请求包来实现的,其中包含了连接参数、连接请求地址等信息。

        响应连接请求:设备B收到连接请求后,可以选择接受或拒绝连接。如果设备B接受连接请求,它会发送一个连接响应包给设备A;如果拒绝连接,则不发送连接响应包。

6
图6-2 中心设备扫描时接收到外围设备广播包时发送连接请求

详细的连接建立过程如下图6-3所示。

图6-3 BLE两设备详细的连接建立流程

注:图中M代表手机,S代表设备B,M->S表示手机将数据包发给设备B,即手机开启Tx窗口,设备B开启Rx窗口;S->M正好相反,表示设备B将数据包发给手机,即设备B开启Tx窗口,手机开启Rx窗口。

        详细解析advertiser发送完一个广播包之后150us(T_IFS),advertiser必须开启一段时间的射频Rx窗口,以接收来自observer的数据包。当手机在某个广播事件的时候扫到了设备B,也就是收到广播包A1时,Observer就可以在这段时间里给advertiser发出连接请求CONN_REQ(CONN_REQ又称为CONNECT_IND)。手机在收到A1广播包ADV_IND后,以此为初始锚点(这个锚点不是连接的锚点),T_IFS时间后给Advertiser发送一个connection request命令,即A2数据包,告诉advertiser我将要过来连你,请做好准备。Advertiser根据connect_req命令信息做好接收准备,connect_req包含如下关键信息:

  1. 访问地址(Access Address):
    • 这是一个6字节的随机地址,用于在连接建立后,作为数据包的标识,确保通信的正确性和安全性。
  2. CRC初始值(CRCInit)
    • 用于初始化CRC(循环冗余校验)计算的初始值,用于验证数据包在传输过程中的完整性。
  3. 窗口大小(Window Size)
    • 定义了在Master(通常指发起连接的设备,即Observer)期望Slave(即Advertiser)回复连接响应的时间窗口大小。这有助于同步两个设备的时间。
  4. 窗口偏移(Window Offset)
    • 定义了从Master发送Connection Request后的一个相对时间,Slave应在这个时间窗口内回复Connection Response。
  5. 连接间隔(Connection Interval)
    • 连接建立后,两个设备交换数据包的时间间隔。这个时间间隔是由两个设备在连接请求/响应过程中协商的。
  6. 从设备延迟(Slave Latency)
    • 定义了在保持连接的情况下,Slave可以跳过的最大连接事件数。这允许Slave在需要时进入低功耗模式。
  7. 超时时间(Supervision Timeout)
    • 如果在指定的时间内没有收到来自Slave的数据包,Master将认为连接已丢失,并终止连接。
  8. 跳频算法(Hop Increment)
    • 定义了频率跳变的增量,用于在多个蓝牙通道上进行频率分集,以提高通信的鲁棒性。
  9. 通道映射(Channel Map)
    • 定义了用于数据传输的蓝牙通道。这有助于避免与其他无线设备产生干扰。
  10. 其他参数
    • 可能还包括其他参数,如发射功率级别、连接参数更新请求等,但这些通常不是Connection Request中的核心部分。

        当Advertiser(Slave)收到Connection Request后,它会根据其中的信息准备好接收数据,并在适当的时间窗口内回复一个Connection Response(CONNECT_RSP)数据包。如果连接成功建立,那么后续的数据交换就可以根据这些参数进行。

BLE协议规定了连接请求数据包发送完毕后,存在一个强制的时延,这个时延就是1.25ms。这是为了确保设备在发送完连接请求后有足够的时间来准备接收连接响应,同时也为从设备(Advertiser)提供了处理连接请求的时间。

        connect_req其实是在告诉advertiser,手机将在Transmit Window期间发送第一个同步包(P1)给你,请在这段时间里把你的射频接收窗口打开。设备B收到P1后,T_IFS时间后将给手机回复数据包P2(ACK包)。一旦手机收到数据包P2,连接即可认为建立成功。当然,实际情况会比较复杂,手机有可能收不到P2,这个时候手机将持续发送同步包直到超时时间(supervision timeout)到,在此期间只要设备B回过一次ACK包,连接即算成功。后续手机将以P1为锚点(原点),Connection Interval为周期,周期性地给设备B发送数据包(Packet)。

         到底什么叫连接(connection)?像有线UART,很容易理解,就是用线(Rx和Tx等)把设备A和设备B相连,即为连接。用“线”把两个设备相连,实际是让2个设备有共同的通信媒介,并让两者时钟同步起来。蓝牙连接有何尝不是这个道理,所谓设备A和设备B建立蓝牙连接,就是指设备A和设备B两者一对一“同步”成功,其具体包含以下几方面:

  • 设备A和设备B对接下来要使用的物理信道达成一致
  • 设备A和设备B双方建立一个共同的时间锚点,也就是说,把双方的时间原点变成同一个点
  • 设备A和设备B两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包
  • 连接成功后,设备A和设备B通信流程如下所示:
图6-4 连接成功后设备A与设备B的通信流程

        如上图所示,一旦设备A和设备B连接成功(此种情况下,我们把设备A称为Master或者Central,把设备B称为Slave或者Peripheral),设备A将周期性以CI(connection interval)为间隔向设备B发送数据包,而设备B也周期性地以CI为间隔打开射频接收窗口以接收设备A的数据包。同时按照蓝牙spec要求,设备B收到设备A数据包150us,设备B切换到发送状态,把自己的数据发给设备A;设备A则切换到接收状态,接收设备B发过来的数据。由此可见,连接状态下,设备A和设备B的射频发送和接收窗口都是周期性地有计划地开和关,而且开的时间非常短,从而大大降低系统功耗并大大提高系统效率。

6.3 BLE报文格式

参考:BLE空中数据包格式 - 张妖刀 - 博客园 (cnblogs.com)

BLE中LL层的错误重传机制 - 不回本不改名 - 博客园 (cnblogs.com)

连接成功后,双方将可以互相发送数据,那么将涉及到其数据帧格式:

图6-5 BLE空中包格式

LLID(2bits

link layer ID,对LL PDU进行分类

  • LL Data PDU(Link Layer Data Protocol Data Unit,链路层数据协议数据单元):主要用于传输应用层数据,如位置信息、温度数据、用户输入等。每个LL Data PDU都有一个唯一的序列号(SN),以确保数据传输的可靠性和顺序性。
  • LL Control PDU(Link Layer Control Protocol Data Unit,链路层控制协议数据单元)用于控制链路层的连接过程,包括启动加密、更新连接参数、处理错误和终止连接等操作。LL Control PDU可能包含各种控制消息,如连接更新请求、加密请求和响应等。在蓝牙低功耗(BLE)通信中,这些PDU是构成data channel packet(数据信道空中包)的组成部分。
图6-6 LLID位参数选择及含义
  • 这是一个2位的字段,用于标识PDU的类型。
  • 00: 通常不使用,保留给未来使用。
  • 01: 标识数据PDU的开始。当这个值被设置时,PDU包含有效载荷的开始部分(可能是分片数据的第一部分)。
  • 10: 标识数据PDU的继续。当这个值被设置时,PDU包含有效载荷的后续部分(分片数据的中间或最后部分)。
  • 11: 标识控制PDU。这些PDU不包含有效载荷,而是用于链路层控制消息,如连接请求、连接响应等。

LL Control PDU是在Link layer层直接进行交互的,也就是说他们不会经过后面的L2CAP层,Link layer支持如下control PDU:

图6-7 LL层所支持的control PDU
 

NESN/SN(各占1bit)

        NESN和SN各占1bit。SN全称为sequence number,表示当前发送的packet编号。NESN,next expected sequence number,用来告知对方下一个期待的packet的编号。Link layer使用SN来告知对方这个packet是新数据包还是重传包,用NESN来告诉对方你之前发我的包已经收到了(相当于ACK的作用),我现在期待下一个新的数据包了。此BLE没有专门的ACK包,它是通过NESN/SN来实现ACK和重传双重功能的。请参考如下表格,仔细揣摩NESN和SN是如何编码的,以同时完成ACK和重传功能。

图6-8 在数据包传输过程中NESN/SN的变化

这里实现的思想就是,在收包成功时判断接受端的NESN与收到数据包的SN是否一致。

  • 从机收包成功时,若一致,则将接收端的SN值设置成与数据包的SN值等同,将NESN值+1。若不一致,则接收端的SN值与NESN值均保持不变。
  • 主机收包成功时,若一致,则将接收端的SN值增加1,同时设置NESN为下一个将要发送数据包的NESN。若不一致,则接收端的SN值与NESN值均保持不变。

规律:同一方向相邻的两个数据包,他们的NESN和SN与另一个包的NESN和SN是相反的,比如#3 NESN = #1 #NESN ,#3 SN = #1 #SN ,同样#2和#4 各自的NESN和SN是相互相反的

MD(1bit)

        这个标志位是用来通知对方设备自己还有其他数据准备发送。0 表示没有更多数据发送, 1 表示有更多数据准备发送。这样,只要还有数据需要发送,连接事件会自动扩展。一旦不再有数据发送,连接事件立即关闭。

RFU (Reserved for Future Use 3bit)

这些位是为未来使用而保留的,当前的BLE 4.0规范中不使用它们。

Length(5bit)

        这是一个变长字段,用于指示PDU中有效载荷(Payload)的长度。在BLE 4.0中,如果没有启用数据长度扩展(Data Length Extension),则Length字段的长度是固定的(通常是7位或8位)。启用数据长度扩展后,Length字段的长度可以更长,从而支持更大的有效载荷。

RFU (Reserved for Future Use 3bit)

这些位是为未来使用而保留的,当前的BLE 4.0规范中不使用它们。

数据净荷(Payload 2B-31B)

这里需要注意数据包和广播包的数据净荷长度差距。

数据净荷是数据PDU中用于传输实际数据(如应用数据、ATT命令等)的部分。它的长度由报头中的Length字段指定。在BLE 4.0中,如果没有启用数据长度扩展,则数据净荷的最大长度通常为27个字节(减去报头和MIC的长度)。启用数据长度扩展后,可以支持更长的数据净荷。数据净荷的内容由上层协议(如ATT、SMP等)定义,并通过BLE链路层进行传输。

mic是消息完整性检查分场景的(如果payload 为空或者该linklayer 没有加密可以不添加mic部分,反之添加mic部分)

L2CAP PDU Length(2B)

表示后面information payload的长度,不包括MIC。information payload最大长度除了受这个L2CAP length字段约束,同时还受MTU的限制。MTU,Maximum Transmission Unit,是ATT层与L2CAP层可以交互的最大数据长度,或者说是Client与Server可以交互的最大长度。

总结一下,蓝牙spec里面定义了2个长度字段:
LL data length和L2CAP length,同时ATT层还定义了一个MTU,以限制ATT PDU最大长度。
LL data length可以通过LL_LENGTH_REQ和LL_LENGTH_RSP来动态改变,MTU size则可以通过后面要讲到的Exchange MTU Request和Exchange MTU Response来改变,而L2CAP length无法动态改变,也就是说不能超过65535。

L2CAP Channel ID (2B)

逻辑通道的ID,BLE使用固定的通道编号,也就是说虽然蓝牙spec里面也允许BLE使用connection oriented channel,但大部分BLE协议栈实现的时候都是使用固定的通道编号,通道编号定义如下所示:

Value描述
0x0004用于ATT协议
0x0005用于L2CAP信令
0x0006用于安全管理

Opcode PDU (1B)

代替某种命令,通过的PDU携带的Attribute Parameters格式不同,下面详细说明。bit 0-5位表示。

Command:表示PDU Type 是否是命令(Command )。bit 6表示。

Authentication Signature标识位:
如果Attribute Opcode中身份验证签名标记位为0,则 Information Payload不含有Authentication Signature;
如果Attribute Opcode中身份验证签名标记位为1,则 Information Payload含有Authentication Signature。
bit 7 表示。

蓝牙相关学习:5.BLE协议属性协议层(ATT)_ble att-CSDN博客

这里可以看到参数的相应解析

MIC(Message Integrity Check 4bit)

MIC是用于确保数据PDU在传输过程中未被篡改或损坏的字段。它通常位于数据净荷之后,并在整个PDU(包括报头、数据净荷和MIC本身)上计算得出。MIC的计算方法由BLE规范定义,并使用特定的加密算法(如AES-CCM)进行。接收端在接收到PDU后,会使用相同的算法和密钥对数据PDU重新计算MIC,并将其与PDU中携带的MIC进行比较。如果两个MIC匹配,则表示数据PDU在传输过程中未被篡改或损坏;如果不匹配,则表示数据PDU已被篡改或损坏,接收端将丢弃该PDU。

6.4 BLE空中包位段定义的原因与含义解析

  • 对开发者来说,很简单,他只需要调用send(0x53)
  • GATT层定义数据的类型和分组,方便起见,我们用0x0013表示电量这种数据类型,这样GATT层把数据打包成130053(小端模式!)
  • ATT层用来选择具体的通信命令,比如读/写/notify/indicate等,这里选择notify命令0x1B,这样数据包变成了:1B130053
  • L2CAP用来指定connection interval(连接间隔),比如每10ms同步一次(CI不体现在数据包中),同时指定逻辑通道编号0004(表示ATT命令),最后把ATT数据长度0x0004加在包头,这样数据就变为:040004001B130053
  • LL层要做的工作很多,首先LL层需要指定用哪个物理信道进行传输(物理信道不体现在数据包中),然后再给此连接分配一个Access address(0x50655DAB)以标识此连接只为设备A和设备B直连服务,然后加上LL header和payload length字段,LL header标识此packet为数据packet,而不是control packet等,payload length为整个L2CAP字段的长度,最后加上CRC24字段,以保证整个packet的数据完整性,所以数据包最后变成:

  • AAAB5D65501E08040004001B130053D550F6
    • AA – 前导帧(preamble)
    • 0x50655DAB – 访问地址(access address)
    • 1E – LL帧头字段(LL header)【包括2bit LLID、1 bit NESN和1bit SN、1bit MD、3RFU 】
    • 08 – 有效数据包长度(payload length)
    • 04004000 – ATT数据长度,以及L2CAP通道编号(这里正常的数据应该是0040、0040,大小端)
    • 1B – notify command
    • 0x0013 – 应用数据handle
    • 0x53 – 真正要发送的应用数据
    • 0xF650D5 – CRC24值

PS:BLE的传输过程中到字节存放位置

PS:大端字节序(Big Endian)和小端字节序(Little Endian) - 知乎 (zhihu.com)

0x1234,这里0x12是高位,0x34是低位。记忆方法很简单,以左为尊就可以,左边字节处于高位。

大端小端影响字节存储的顺序

        CPU读取内存中的数据时,是从低地址向高地址方向进行读取的。如果是大端字节顺序存储,那么读取时会先读取出高位字节,反之小端存储就会先读取出低位字节。如果需要处理的数据是在大端存储的设备上生成的,那么在读取这些数据时就需要按照大端存储的顺序来读取;同样地,如果数据是在小端存储的设备上生成的,那么在读取这些数据时就需要按照小端存储的顺序来读取。

在BLE的传输过程中,涉及到字节存放位置的问题,这与系统的大端还是小端有关。

        “对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字节,用两个字节表示一个汉字。这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码单元是word(双字节),word之间的顺序是编码方案指定的,word内部的字节排列才会受到endian的影响。”,

        所以utf-8也没有字节序的问题。节序问题之存在于需要使用两个字节以上来表示整数。而UTF-8只是一串字节流,不存在字节序问题,不过将这些字节流翻译成Unicode比其他的传输方式复杂。以字节为单位编码的,无论一个汉字是多少个字节,都无字节序问题。

        字节序问题不是指多个字节传输的先后,这个是固定的无异议的。而是指一个多字节编码在机器中的表示方式问题。 char str[] = “abaksdkakskasklasflk”; 这个无字节序问题。但 int str[] = {0x11223344, 2, 3 }就有字节序问题了。因为str[0]同样数值不同机器中表示不同。

        而剩下的, 就是字符编码内部的字节序了。比如UTF-16是用两个字节表示一个字符,但是这两个字节内部如何排序,系统并不知道,所以必须指定字节序。但是UTF-8由于几个字节表示并不相同,一定要从那个表示长度的字节开始读,相当于一开始就知道该从哪里是队头队尾,所以不存在字节序问题。

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用C#实现低功耗蓝牙BLE数据读写功能的示例代码: ```C# using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.Devices.Bluetooth; using Windows.Devices.Bluetooth.GenericAttributeProfile; using Windows.Devices.Enumeration; namespace BleCommunication { class Program { static void Main(string[] args) { var task = MainAsync(args); task.Wait(); } static async Task MainAsync(string[] args) { // 查询所有蓝牙设备 string selector = BluetoothLEDevice.GetDeviceSelector(); var devices = await DeviceInformation.FindAllAsync(selector); // 过滤出指定名称的设备 var device = devices.FirstOrDefault(d => d.Name == "My BLE Device"); if (device != null) { // 连接设备 var bleDevice = await BluetoothLEDevice.FromIdAsync(device.Id); // 查询服务 var serviceUuid = Guid.Parse("0000fff0-0000-1000-8000-00805f9b34fb"); var serviceResult = await bleDevice.GetGattServicesForUuidAsync(serviceUuid); var service = serviceResult.Services.FirstOrDefault(); if (service != null) { // 查询特征值 var characteristicUuid = Guid.Parse("0000fff1-0000-1000-8000-00805f9b34fb"); var characteristicResult = await service.GetCharacteristicsForUuidAsync(characteristicUuid); var characteristic = characteristicResult.Characteristics.FirstOrDefault(); if (characteristic != null) { // 订阅特征值通知 var status = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); if (status == GattCommunicationStatus.Success) { characteristic.ValueChanged += (sender, args) => { // 处理接收到的数据 var data = args.CharacteristicValue.ToArray(); Console.WriteLine("Received data: {0}", BitConverter.ToString(data)); }; // 发送数据 var dataToSend = new byte[] { 0x01, 0x02, 0x03 }; var writeStatus = await characteristic.WriteValueAsync(dataToSend.AsBuffer()); if (writeStatus == GattCommunicationStatus.Success) { Console.WriteLine("Data sent successfully."); } else { Console.WriteLine("Failed to send data."); } } else { Console.WriteLine("Failed to subscribe to notifications."); } } else { Console.WriteLine("Characteristic not found."); } } else { Console.WriteLine("Service not found."); } } else { Console.WriteLine("Device not found."); } Console.ReadLine(); } } } ``` 请注意,此示例仅用于演示BLE通信的基本过程。在实际应用,您需要根据设备的具体规格和特性来编写更复杂的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值