蓝牙,直接来自于一位国王的名字--King Harald ‘Bluetooth' Gromsson。这位国王因两件事留名于史,其一是在公园958年统一了丹麦和挪威,其二是在其死后,其牙齿呈现出暗蓝色的颜色,因而得名蓝牙为绰号。而蓝牙联盟之所以选择它作为联盟的名字,则是看中了King Harald在统一丹麦和挪威上的贡献。联盟希望,该技术能够像他一样,将PC和无线产业用短距离无线传输连接在一起。
人们日常使用的蓝牙,是在1996年由英特尔、爱立信和诺基亚共同发起而成立的联盟,意在为短距离无线传输制定标准,低功耗、低成本的无线通信连接的方法,以支持不同产品和行业之间的连通与协作
蓝牙分为经典蓝牙(BT-Bluetooth)和低功耗蓝牙(BLE-Bluetooth Low Energy)。这两套原理和实现都不一样,也无法实现互通。
Basic Rate(BR)/AMP
最初的蓝牙技术,包括可选的EDR(Enhanced Data Rate)技术和交替使用的MAC层和PHY层扩展 AMP(Alternate MAC and PHY layer extension)【优化传输速度的过程】
蓝牙诞生之初使用的BR技术,传输速率很低,随着发展而变得无法支持,所以引入了EDR,这时还没有修改软硬件架构,但是之后又落伍了,所以直接引入了WiFi的底层协议,也就是MAC/PHY扩展,但这部分的实现就无法直接更替,所以BR/EDR只能与AMP交替使用。
经典蓝牙主要用于数据量较大的传输,如蓝牙耳机/音箱等
Low Energy(LE)
蓝牙低功耗,则不关心传输速率,而是从降低功耗的角度实现的另一套技术,跟前面的协议没有丝毫关系。
BLE分了很多个版本,现在用的比较多的就是4.2和5.X。那4.2到5.0之间有哪些升级呢?首先,4.2版本传输速度只有1Mbps,广播包最大长度为31字节。而5.0版本开始,传输速度就已经增加到2Mbps了,并且广播包的最大长度也增加为254字节。除此之外,5.X版本还增加了Mesh的功能,且通讯距离也增加至300米以上。
蓝牙协议将蓝牙整体分成了两层架构,底层是核心协议,描述了蓝牙核心技术的基础和规范,应用层协议则基于具体需求,使用核心协议提供的机制,实现不同的功能策略
核心协议包含两部分,Host和Controller,这两部分在不同的蓝牙协议版本中略有区别,但大致上是,Controller完成硬件侧的规范制订,包括信号调制解调,会抽象出用于通信的逻辑链路,可能存在一个或多个,如LE Controller、BR/EDR Controller;Host则在逻辑链路的基础上完成更友好的封装,屏蔽掉技术细节,方便应用层对数据的使用。
应用层(App Layer)为不同场景定义规范,提出Profile(一项服务)的概念,实现各种应用功能
L2CAP(Logical Link Control and Adaptation Protocol Layer)
L2CAP对LL进行了一次简单的封装,LL只关心传输的数据本身,L2CAP就要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。
GAP层(Generic access profile-通用访问配置文件)
GAP是对LL层payload(有效数据包)如何进行解析的两种方式的一种,而且也是最简单的一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接。
SMP(Secure manager protocol-加密管理协议)
SMP用来管理BLE连接的加密和安全。如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作。
ATT(Attribute protocol-属性协议)
简单来说,ATT层用来定义用户命令及命令操作的数据。比如读取某个数据或者写某个数据。BLE协议栈中,开发者接触最多的就是ATT。BLE引入了attribute概念,用来描述一条一条的数据。Attrubute除了定义数据,同时定义该数据可以使用的ATT命令,因此这一层被称为ATT层。
GATT(Generic attribute profile-通用属性配置文件)
GATT用来规范attribute中的数据内容,并运用group(分组)的概念对attribute进行分类管理。没有GATT,BLE协议栈也能跑。但互联互通就会出问题,也正是因为有了GATT和各种各样的应用profile,BLE摆脱了Zigbee等无线协议的兼容性困境,成为了出货量最大的2.4G无线通信产品。
物理层(Physical Layer)
PHY层用来指定BLE所用的无线频段,调制解调方式和方法等。PHY层做的好不好,直接决定了BLE芯片的功耗、灵敏度等射频指标。
LL层(Link Layer-链路层)
LL层是整个协议栈的核心。LL层要做的事情非常多,比如具体选择哪个射频通道进行通信。怎么识别空中数据包。具体在哪个时间点把数据包发送出去。怎么保证数据的完整性。ACK如何接收。如何进行重发。以及如何对链路进行管理和控制等等。LL层只负责把数据发送出去或者接收回来,对数据进行怎样的解析则由GAP或ATT来负责。
- Standby:初始状态,不收发数据,接受上层协议命令与其他状态切换
- Advertising:通过广播发送数据的状态,建立连接后可进入Connection
- Scanning:接收广播的数据的状态
- Initiating:特殊的接收状态,类似Scanning,接收Advertiser广播的连接数据,建立连接后进入Connection
- Connection:建立连接后拥有单独的通道
HCI(Host controller interface)
HCI是可选择的。HCI主要用于2颗芯片实现BLE协议栈的场合,用来规范两者之间的通讯协议和通信命令等。
说明:
ATT和GATT的关系就像车辆和交通规则一样。ATT就是车辆,而GATT就是规范车辆该如何行驶的交通规则。只有GATT存在的时候,多个ATT见面才知道该如何行驶,到底是拐弯让直行还是坐车道超车。
从上边的名字可以看到,主要分为protocol和profile。其中L2CAP、SMP、ATT属于protocol,而GAP和GATT属于profile。
profile和protocol有什么区别呢? 在蓝牙核心规范(Bluetooth Core Specification)中,profile的定义不同于protocol的定义。Protocol被定义为各层协议。而Profile从使用蓝牙核心规范中各层协议的角度,定义蓝牙应用互操作性的实现。Profile定义Protocol中的可用特性和功能,以及蓝牙设备互操作性的实现,使蓝牙协议栈适用于各种场景的应用开发。
在蓝牙核心规范中,Profile和Protocol的关联如下图
Profile由红色矩形框表示,包括GAP、Profile#1、Profile#2和Profile#3。蓝牙核心规范中的Profile分为两种类型:GAP,途中红色矩形框所示的GAP;基于GATT的Profile,图中红色矩形框所示的Profile#123。
蓝牙的通信是双向的,为了创建和维护一个BLE通信连接,在蓝牙中引入了“角色”这一概念,一个BLE设备不是主机(集中器)就是从机(外围设备)角色,这是根据是谁发起这个连接来确定的。主机(集中器)设备总是连接的发起者,而从机(外围设备)总是被连接者。整个访问与连接过程都是在GAP(Generic Access Profile-通用访问规范)进行实现的。
BLE的物理通道即“频道,分别是‘f=2402+k*2 MHz, k=0, … ,39’,带宽为2MHz”的40个RF Channel。其中,有3个信道是advertising channel(广播通道),分别是37、38、39,用于发现设备(Scanning devices)、初始化连接(initiating a connection)和广播数据(broadcasting date);其他的37个信道为data channel(数据通道),用于两个连接的设备间的通讯。
在低功耗蓝牙规范中,数据包格式分广播报文和数据报文两种。
广播报文:设备发现、连接建立、传输广播
数据报文:自适应跳频以及设备间数据传输
设备利用广播报文发现、连接其它设备,而在连接建立之后,便开始使用数据报文。无论是广播报文还是数据报文,链路层只使用一种数据包格式。
它由“前导码”(preamble)、“访问码”(access code)、”有效载荷“和”循环冗余校验“(Cyclical Redundancy Check,CRC)校验码组成。其中,”访问码“又称为”访问地址/接入地址“(access address)。
前导码:1个字节长度,接收中用于频率同步、数据速率同步、自动增益控制调整。前导是一个8比特的交替序列。对于在LE 1M物理层上发送的数据包前导码为8比特;对于在LE 2M物理层上发送的数据包前导码为16比特。不是01010101就是10101010,取决于接入地址的第一个比特。
若接入地址的第一个比特为0:01010101
若接入地址的第一个比特为1:10101010
访问地址:4个字节长度,访问地址有两种类型(广播访问地址和数据访问地址)
广播访问地址:固定为0x8E89BED6,在广播、扫描、发起连接时使用。
数据访问地址:随机值地址,不同的连接有不同的值。在连接建立之后的两个设备间使用。
PDU(Protocol Data Unit): 数据载荷
CRC:数据循环冗余校验
GAP:以应用程序角度进行功能封装,提供一套统一的、通用的广播规范
HCI:将LL提供的功能抽象成Command/Events的形式,供上层使用
LL:负责广播通信相关功能的定义和实现,包括信道选择、链路状态定义、PDU定义、设备过滤机制等
Advertising:广播状态,周期性地广播,数据发送方
Scanning:扫描状态,扫描并接受广播数据,数据接收方
Initiating:初始化状态,扫描到可连接的广播时,发起连接请求,连接发起方
广播PDU
Type是指PDU的类型,如不同的状态下也有不同的消息类型,TxAdd和RxAdd都是地址类型flag,针对不同的type有不同的含义,RFU都是保留字段,Length标明payload的长度.
PDU type | PDU name | Description | Physical Channel |
Permitted PHYs | ||
LE 1M | LE 2M | LE coded | ||||
0000b | ADV_IND | 常规广播,可连接可扫描 【后续建立点对点连接,监听CONNECT_REQ请求】 |
Primary | ● |
||
0001b | ADV_DIRECT_IND | 点对点连接,已知双方蓝牙地址,无广播数据,可被指定设备连接不可扫描 【快速建立连接,不关心广播数据,监听CONNECT_REQ请求】 |
Primary | ● | ||
0010b | ADV_NONCONN_IND | 同ADV_IND,不可连接不可扫描 【用于定时传输简单数据】 |
Primary | ● | ||
0011b | SCAN_REQ | 接收ADV_IND/ADV_SCAN_IND后,请求更多信息 【接收广播数据后请求更多信息】 |
Primary | ● | ||
AUX_SCAN_REQ | Secondary | ● | ● | ● | ||
0100b | SCAN_RSP | SCAN_REQ的响应,返回更多信息 | Primary | ● | ||
0101b | CONNECT_REQ | 接收ADV_IND/ADV_DIRECT_IND后,请求建立连接 【请求建立连接】 |
Primary | ● | ||
AUX_CONNECT_REQ | Secondary | ● | ● | ● | ||
0110b | ADV_SCAN_IND | 同ADV_IND,不可连接可扫描 【用于传输额外数据,监SCAN_REQ请求】 |
Primary | ● | ||
0111b | ADV_EXT_IND | Primary | ● | ● | ||
AUX_ADV_REQ | Secondary | ● | ● | ● | ||
AUX_SCAN_RSP | Secondary | ● | ● | ● | ||
AUX_SYN_IND | Secondary | ● | ● | ● | ||
AUX_Chain_IND | Secondary | ● | ● | ● | ||
1000b | AUX_CONNECT_RSP | Secondary | ● | ● | ● |
Payload
ADV_IND
这个比较经典和常用的 ADV PDU 了,它代表了咱们发出去的这个 ADV 包,是一个可连接的,并且可扫描的广播包。什么是可连接呢?意思是,我发出去这个包,别人想连接我,OK,没问题。可扫描指的是,有人处于 Scanning 状态,收到我的这个 ADV_IND 后,对端发起 SCAN_REQ,咱们回复他 SCAN_RSP。
AdvA:本机地址 48bits
AdvData:携带的数据 0 - 31 字节
ADV_DIRECT_IND
顾名思义,咱们可以知道这种类型的数据包,是可连接的并且带指向性的(不可扫描),什么叫指向性呢,也就是,我指着对端的鼻子说,我这个包是专门给你准备的(来连接我啊)。所以这个包携带了本机地址和指着的那个地址。同时不允许携带数据:
AdvA:本机地址 48bits
TargetA:对端地址 48bit
ADV_NONCONN_IND
这种类型的 ADV PDU,属于不可连接,不可扫描,不定向的 ADV 包,包含了本机地址和数据(类似于,在空中散布谣言类型)
AdvA:本机地址 48bits
AdvData:携带的数据 0 - 31 字节
ADV_SCAN_IND
这种类型的 ADV PDU 是只能扫描的不定向的,不连接的 ADV
AdvA:本机地址 48bits
AdvData:携带的数据 0 - 31 字节
BLE设备地址类型:
TxAdd:发送地址字段
RxAdd:接收地址字段
发送地址字段和接收地址字段指示了设备使用公共地址(Public Address)还是随机地址(Random Address)。公共地址和随机地址的长度一样,都包含6个字节共48位。BLE设备至少要拥有这两种地址类型中的一种,当然也可以同时拥有这两种地址类型。
1. 公共地址(Public Address)
公共地址由两部分组成,如下图。公共地址由制造商从IEEE申请,由IEEE注册机构为该制造商分配的机构唯一标识符OUI(Organizationally Unique Identifier)。这个地址是独一无二,不能修改的。
2. 随机地址
随机地址有包含两种:静态地址(Static Device Address)和私有地址(PrivateDevice Address)。
静态地址有如下要求:
a)静态地址的最高2位有效位必须是1。
b)静态地址最高2位有效位之外的其余部分不能全为0和1。
在私有地址的定义当中,又包含了两个子类:不可解析私有地址(Non-resolvable Private Address)和可解析私有地址(Resolvable Private Address,RPA)。CH57x使用的是静态地址,芯片在出厂时自带全球唯一的48位MAC地址。在提供的driver代码中,有获取MAC的接口,可以直接调用。
总结:
Static Device Address:上电生成,46-bit的random+11,断电后可变
Private Device Address:进一步提供定时更新和地址加密提高可靠行和安全性
Non-resolvable Private Address:按周期定时更新,46-bit的random+00
Resolvable Private Address:通过随机数和IRK(Identity Resolving Key)生成,24-bit的hash+22-bit的random+10
Public Device Address:IEEE分配,24-bit的company_id+24-bit的company_assigned,类似MAC
Random Device Address:随机生成,解决费用和维护、设备身份绑定的问题
Payload 长度
广播报文:长度域包含6个比特,有效值的范围是6~37。
数据报文:长度域包含5个比特,有效值的范围是0~31。
广播报文和和数据报文的长度域有所不同,主要原因是:广播报文除了最多31个字节的数据之外,还必须要包含6个字节的广播设备地址。6+31=37,所以需要6比特的长度域。
再次强调:广播时必须要包含6个字节的广播设备地址。
将Link Layer提供的功能封装成Command/Event组
Command格式
OCF(Opcode Command Field)表示特定的HCI命令,OGF(Opcode Group Field)表示该HCI命令所属组别,他们共同组成16位操作码;
Parameter Total Length表示所有参数总长度
所有BLE相关的HCI Command的OGF都是0x08
Event格式
这些Command/Event包括广播、扫描、连接建立的相关操作,这些都可以通过hcitool命令进行测试
会从应用程序角度对各种状态和操作再一次进行封装,包括设备角色,通信的模式和操作的定义
与GAP广播通信相关的是广播和发现模式
Broadcast mode and observation procedure,广播模式及对应的解析过程,对应状态下的角色双方就是Broadcaster和Observer
Discovery modes and procedures,发现模式及对应的发现过程,对应的角色就是Peripheral和Central
广播数据格式
广播/扫描应答数据,包含有意义部分和无意义部分(补齐为0),有意义部分是由一个个广播块(AD Structure)组成,每个广播块包含1字节长度(指示数据部分长度)和剩下的数据部分,数据部分又分为数据类型和数据内容,数据类型会指示真实Data部分的内容,例如0x01
表示Data内容是描述设备物理连接状态,再例如0x08
表示Data内容是设备名称,更多可以参考generic-access-profile.
蓝牙广播包的最大长度是37个字节,其中设备地址占用了6个字节,只有31个字节是可用的。31个可用的字节又按照一定的格式来组织,被分割为n个AD Structure。如下图所示:
每个AD Structure包含又包含三部分:Length(1字节),AD Type(1字节),AD Data(n字节)
其中Length = AD Type 长度 + AD Data 长度
例如广播数据:
0x05,0x09,0x31,0x32,0x33,0x34,0x02,0x0A,0x08,0x06,0xFF,0x41,0x50,0x50,0x4C,0x45
分割后如下所示
0x05,0x09,0x31,0x32,0x33,0x34
0x02,0x0A,0x08
0x06,0xFF,0x41,0x50,0x50,0x4C,0x45
一共可以分割成三个AD Structure:
第一个AD Structure的长度为0x05,类型为0x09(完成的设备名称),那么余下的数据含义就是完整的设备名称,0x31,0x32,0x33,0x34 按照UTF-8编码,就是1234。
第二个AD Structure的长度为0x02,类型为0x0A(发射功率),那么后面的数据0x08表示的就是发射功率。
第三个AD Structure 的长度为 0x06,类型为0xFF(厂商自定义数据),余下的数据0x41,0x50,0x50,0x4C,0x45就是厂商自定义的内容。
从机要被主机连接,那么它就必须先被主机发现。这个时候,从机设备把自身信息通过广播的形式发射出去。
比如设备A需要先进行广播,即设备A(Advertiser)不断发送广播信号,t 为广播间隔。每发送一次广播包,我们称为一次广播事件(advertising event),因此 t 也称为广播事件间隔。广播事件时间是一段一段的,每次都会持续一段时间,蓝牙芯片也只有在广播事件期间才会打开射频模块发射广播,这个时间功耗比较高(几十毫安),其余时间蓝牙芯片都处于idle待机状态,因此平均功耗就非常低(几微安)。
当广播发出的时候,每个广播事件包含了三个广播包,分别在37/38/39三个广播信道上进行发送。广播的内容是相同的。下图observer为主机观察者,advertiser就是从机广播者。
设备A不断发送广播给主机(Observer),如果主机不开启扫描窗口,是收不到设备A的广播的。主机不但要开启射频接收窗口,而且主机的射频接收窗口要跟从机的广播发送窗口匹配才行。由于这种配对成功时一个概率事件,所以主机扫到设备A也是一个概率事件。也就是说,从机(Advertiser)可能很快就被主机(Observer)发现,也有可能从机(Advertiser)要很久才能被主机(Observer)发现。
下图表示了主机主动扫描广播的过程:
主机设置自身的扫描参数,设置成功后,控制器根据设置参数开启扫描窗口。当控制器收到扫描数据包后,向主机发送给一个广播报告事件(adv_report),该事件同样包括了链路层数据包的广播类型。因此,主机能够判断对端设备是否可以连接或扫描,并且区分出广播数据包和扫描响应数据包。
既然有主动扫描,当然也就有被动扫描。在被动扫描中,扫描者设备应该仅仅去监听广播包,而不向广播者设备发送任何数据。
一旦上面的扫描参数设置完毕,主机就可以启动扫描。如果控制器接收到的符合过滤策略和其他规划的广播数据包,则发送一个Advertising Report事件给主机。除了广播者的设备地址外,报告事件还包括广播数据包中的数据,以及接收广播数据包时的信号接收强度。可以利用该信号强度以及位于广播数据包中的发射功率,共同确定信号的路径损失,从而给出大致的范围,这个应用就是防丢器和蓝牙定位。被动扫描不需要向主机发送任何数据。
经典蓝牙中保持连接非常耗费资源,但是每次连接建立效率又非常低,为了优化体验,BLE简化了连接过程(毫秒级),极大的降低了面向连接通信的代价
蓝牙通信系统中,对于连接的定义是:在约定的时间段内,双方都到一个指定的物理Channel上通信。
角色定义。BLE为处于连接状态的两个设备定义了两个角色,Master和Slave。Master作为连接发起方,定义和连接相关的参数,Slave是连接的接收方,请求连接参数。
面向连接的通信使用特定的PDU,称为Data channel PDU
LLID(逻辑链路ID):指示Data Channel传输的PDU类型,传输数据是LL Data PDU,传输控制信息是LL Control PDU,0x01表示该数据包是一个帧的延续内容,或者这是一个空的“逻辑链路控制及适配协议”数据包;0x02表示一个“逻辑链路控制及适配协议”数据包的开始;0x03表示这是一个“逻辑链路控制”数据包的内容
NESN:下一个期望的序列号,用于对接收到的数据包进行确认,NESN(Next Expected Sequence Number)和SN(Sequence Number)用于数据传输过程中的应答和流控
MD:更多数据字段,主要是为了说明发送方是否还有要发给接收者的数据,用于关闭连接。
RFU :保留位
Length:用以表示包含“信息完整性校验码”(Message Integrity Check,MIC)在内的“有效载荷数据”的长度,包括Payload和MIC。
数据PDU数据
同广播报文PDU数据
校验码:3个字节长度,“循环冗余校验”(Cyclical Redundancy Check,CRC),可检查数据的正确性。
可连接状态的设备(Advertiser)按照一定周期广播可连接数据包
主动连接的设备(Initiator)收到广播包后回应一个连接请求(约定时间点、物理信道等)
Initiator发送完毕后进入连接状态,成为Master
Advertiser接收到连接请求后也进入连接状态,成为Slave
双方按照参数约定,定时切换到某一物理信道,开始依次收发数据,直至连接断开
主机在收到A1广播包ADV_IND后,以此为初始点,T_IFS时间后,给Advertiser(从机)发送一个connection request命令,即A2数据包,告诉advertiser(从机)将要进行连接,做好准备。Advertiser(从机)根据connect_req命令信息做好接收准备。connect_req其实就是告诉advertiser手机(主机)将在Transmit Window期间发送第一个同步包(P1),请advertiser(从机)在这段时间内打开接收窗口。设备B收到P1后,T_IFS时间后将给手机(主机)回复数据包P2。一旦手机(主机)收到数据包P2,连接即认为建立成功。后续手机(主机)将以P1为锚点(原点),Connection Interval为周期,周期性地给设备B发送Packet。
封装Link Layer的功能,主要包括连接的建立、关闭、参数设置和管理,以及数据封装和转发
定义设备具有的能力和操作
连接成功后,主机和从机在每一个connection interval开始的时候,都必须交互一次,即主机给从机发一个包,从机再给主机发一个包。整个交互过程被称为一个connection event。蓝牙芯片只有在connection event期间才把射频模块打开,此时功耗比较高,其余时间蓝牙芯片都处于idle状态,因此平均功耗非常低。
主机不可能时时刻刻都有数据给从机,所以主机大部分时间都是发的空包(empty packet)给从机。同样从机也不是时时刻刻都有数据给主机。因此从机回复给主机的包,大部分也是空包。另外,一个connection event期间,主机可以发多个包给从机,以提高吞吐率(IOS一个连接间隔最多交互4次,安卓一个连接间隔最多交互6次)。综上所述,连接成功后的通信时序图如下:
图中,主从数据发送的数据包TX和RX表示方向性的数据通道,也就是蓝牙的空中属性,空中操作时间都是采用蓝牙操作句柄来进行的。因为句柄能够唯一表示各个属性。空中特性的性质包括:
从机->主机方向:
通知:从机端上报数据给主机,不需要主机回复一个响应
指示:从机端上报数据给主机,需要主机端回复一个确认
通知和指示之间不同之处在于指示有应用层上的确认,而通知没有。
主机->从机方向:
写
没有回应的写
读