深入理解蓝牙BLE之“扩展广播”-创新互联

目录

创新互联建站主营潜江网站建设的网络公司,主营网站建设方案,重庆APP开发公司,潜江h5小程序开发搭建,潜江网站营销推广欢迎潜江等地区企业咨询

前言:

4.2版本广播:

5.0版本广播:

实现原理:

格式定义:

广播事件类型:

扩展广播:

周期广播:

广播集:

HCI接口定义:

4.2版本:

5.0版本:

周期广播:

疑问与解答:


前言:

BLE 5.0的扩展广播特性,网上的资料很少,我觉得写一点关于扩展广播的内容是有意义的。蓝牙BLE的4.2版本及其之前版本,有一个很大的限制,就是广播数据的payload太小了,只有31个字节。原因是广播物理信道(37,38,39)只有三个,并且大家都在使用,因此无法像数据信道那样,修改信道上传输的数据包的大小来解决问题(数据信道有一个好处,就是有37个信道,可以跳频,大家彼此冲突的几率小,但是广播信道没有这个条件)。

为了解决广播数据payload小的这个问题,蓝牙BLE在5.0版本中,新增了扩展广播的特性,包含了广播集,周期广播等概念,了解扩展广播实现机制后,我们可以明显的感受到一个信息:“5.0扩展广播的实现是在模仿GATT连接的实现”。

4.2版本广播:

我们首先回顾一下4.2版本的广播定义,4.2的蓝牙广播根据PDU Type来区分,一共有7种类型,这7种类型的广播都是在37,38,39三个无线信道上收发的。

图1

将4.2的蓝牙广播分为2组,这样更方便记忆:

1组:ADV_IND,ADV_DIRECT_IND,ADV_NONCONN_IND,ADV_SCAN_IND

这四个广播从名字上来区分,它们更容易理解为的广播概念(ADV),它们根据是否可以处理连接请求和扫描请求两个维度分为四种,如图2。

图2

2组:CONNECT_REQ,SCAN_REQ,SCAN_RSP,这三个类型的广播,是带有一定功能性的,之所以将它们也划分到广播类型中,是因为它们也是在广播信道上收发的,蓝牙4.2版本的BLE将在BLE广播信道上发送的PDU,都分类为广播数据。蓝牙BLE4.2版本的链路层的广播PDU的格式汇总如图3,本文主要介绍扩展广播,因此此部分内容一张图带过。 

图3

其中需要说明的2点:

1.广播PDU的access address是固定的,它的值为0x8E89BED6。

2.Link Layer packet format中的PDU大值是39(2字节header,37字节Payload)。

5.0版本广播:

5.0版本协议发布之后,新增广播类型的叫做extend adv,而将4.2以及之前版本的广播叫做legacy adv,5.0版本协议中在4.2的7种广播类型基础上,又新增了8种广播类型的PDU,如图4。

图4

实现原理:

4.2版本的蓝牙规范中,提到过它的广播通道只有 37,38,39 这三个,剩余的37个信道都是数据信道,数据信道用于发送连接的数据,payload比广播信道的数据要长(从Link Layer packet format来看,可以发送257个字节PDU)。在5.0的广播信道定义中,将37,38,39三个信道定义为Primary Advertising,可以叫做主广播信道,将剩余37个信道叫做Secondary Advertising,Secondary Advertising也可以用来发送广播数据,可以叫做辅助广播信道或者第二广播信道,说白了就是使用4.2的数据信道作为辅助广播信道,用来发送广播数据,将单包广播数据的payload提升到和“连接ACL数据payload”一样,辅助广播信道上发送和接收的包,也叫做辅助包(auxiliary packet)。这就是5.0扩展广播的核心思想,“将广播数据用数据信道来传输”。

将广播数据用数据信道来传输,确实可以提升单包数据的payload,但是也需要解决一个核心问题,对端设备无法同时在40个信道上扫描广播包,扫描端设备必须要确定广播设备在什么时候使用了哪个数据信道来传输广播数据,这个核心问题在BLE的GATT连接通信上也是存在的(它的解决方式是跳频,跳频的策略是在“建立连接时由两端设备同步Channel Map和hop”的基础上来实现,然后就可以按照双方已知的规则进行跳频通信)。另外一个核心问题是如何向下兼容4.2版本的广播实现。

5.0新增的8个广播类型,7个是工作在Secondary Advertising上的,都是AUX_***命名的广播,AUX是Auxiliary(辅助)的缩写,只有一个ADV_EXT_IND是工作在Primary Advertising上。

格式定义:

图4的表格中,PDU Type为0011b的SCAN_REQ和AUX_SCAN_REQ,这两个广播消息的PDU Type是相同的,并且PDU的Payload格式也是相同的,那么蓝牙BLE是如何区分这两个消息的不同呢,后来一想它们是工作在不同的信道上的,SCAN_REQ工作在37,38,39三个信道,AUX_SCAN_REQ工作在0~36信道,如果一个PDU Type为0011b的广播消息出现在Primary Advertising上,那么他就是SCAN_REQ,如果出现在Secondary Advertising上,那么他就是AUX_SCAN_REQ消息。CONNECT_IND和AUX_CONNECT_REQ消息也是靠着同样的逻辑进行区分的。

剩下6种广播类型,其中5个工作在Secondary Advertising上,是AUX_SCAN_RESP,AUX_ADV_IND,AUX_SYNC_IND,AUX_CHAIN_IND和AUX_CONNECT_RSP,另外1个工作在Primary Advertising上,叫做ADV_EXT_IND,这6种广播的payload格式均符合Common Extended Advertising Payload Format格式,如图5所示,该图中的Payload部分只列出了扩展广播相关的新增的数据格式,兼容4.2版本的legacy部分没有列出(可以参考图3中的Payload)。

图5

Common Extended Advertising Payload Format格式详解:

  • Extended Header Length:表示Extended Header字段的长度,取值范围是0~63个字节。
  • AdvMode:广播模式,因为这5个广播消息的PDU TYPE是0111b或者1000b,无法充分表示可连接,可扫描的特性类型,因此额外增加了这个AdvMode字段来实现legacy adv中的PDU TYPE的功能。并且从图5中可以了解到,扩展广播的“PDU TYPE”中,没有Connectable + Scannable的广播类型。
  • Extended Header:由Extended Header Length字段的内容是可变长的特性可知,Extended Header的几个字段不是全部必须存在的。
  1. Extended Header Flags:共占用一个字节,共8bit,每一位表示对应的AdvA~ACAD字段是否存在,AdvA到ACAD正好是8个字段。
  2. AdvA:6字节,表示发起广播设备的mac地址。
  3. TargetA:6字节,是该广播的目的地址。
  4. RFU:预留字段,5.0的协议中尚未使用。
  5. AdvDataInfo:共2个字节。SID占用4个bit,表示广播集合的ID。DID占用12个字节,表示的是该集合中,该广播数据的ID。
  6. AuxPtr:共占用3字节,AuxPtr字段的存在的话,表示一些或所有广播数据存在后续的辅助广播包中。Channel Index表示下一个辅助包出现在哪个Secondary Advertising上,Aux Offset表示时间偏移的值,Offset Units表示Aux Offset的计算单位,这两个值表示下一个辅助包什么时间出现在Secondary Advertising上,AUX PHY字段表示是工作在2M PHY,还是1M PHY,还是coded PHY。CA表示的是晶震时钟精度。发送广播设备在发送该包之后,下一包需要在Aux Offset * Offset Units ~ (Aux Offset + 1)*Offet Units之间发送在指定的Secondary Advertising上。如果这个字段存在,则说明后面还有数据可以接收,如果不存在,则表示本包广播的数据已经发送结束了。
  7. SyncInfo:共占用了18个字节,这个字段是给周期广播用的,AUX_SYNC_IND和AUX_ADV_IND会涉及这个字段。除了Event Counter之外,其他的几个字段与legacy的CONNECT_IND字段基本相同,有一个跳频的ChannelMap,Interval,offset等,周期广播和GATT的链接有着相同的实现逻辑,不过它相对于链接的优势是可以一对多,劣势是数据只能单向传输。Event Counter包含了paEventCounter的值,在AUX_SYNC_IND会用到(虽然不存在于AUX_SYNC_IND PDU中),我们后面再说。
  8. TXPower:一个字节,表示发射功率。
  9. ACAD:Additional Controller Advertising Data的缩写,ACAD的内容和格式与AdvData相同,不同的是ACAD不允许被多个广播包分包传输,它必须是一包传输。
  • AdvData:最终的广播数据,在扩展广播功能的8种新增的广播类型中,有的广播类型的AdvData字段是可以不存在的,这个后面会详细介绍各种扩展广播的格式和功能。Controller理论上单次发送的广播数据最多可以是1650个字节(实际上要看芯片能力),不过在链路层Controller会进行分包传输,单包的大小是根据蓝牙芯片的实际性能和资源来定的,好的方案是大程度的增加单包的payload,进而减少分包数量。如果Host下发的广播数据已被链路层的Controller分包,但是随后无法传输所有分包,则controller会在最后一个分包中的Extended Header字段中的AuxPtr字段的AuxOffset设置为0,则对端的扫描设备会了解到分包已被截断了。

下面详细介绍一下这几种新增的广播包的格式:

  • AUX_CONNECT_REQ和AUX_SCAN_REQ:这两个扩展广播的消息格式与对应的4.2版本的legacy广播一样,不同的点是legacy广播工作在Primary Advertising上,扩展广播的扩展扫描和连接工作在Secondary Advertising上。
  • ADV_EXT_IND:这个广播是扩展广播特性中,唯一一个工作在Primary Advertising上的广播包,它符合Common Extended Advertising Payload Format的格式,扫描设备需要先在Primary信道扫描到该消息,然后才可以知道什么时候,去哪个辅助信道扫描,来获取想要的扩展广播数据。之前提到过Extended Header中的字段,并不是全部field都强制必须存在的,详细信息如图6所示。

图6

从图6可知,ADV_EXT_IND里面是不带AdvData和ACAD,说明它本身不包含最终的广播数据。另外with auxiliary packet的广播类型,一定要包含ADI和AuxPtr字段,ADI标识本广播属于哪个广播集合(SID),广播数据的ID(DID)是多少。AuxPtr会告诉扫描设备,它的辅助包的广播数据在什么时间点出现在哪个辅助信道上。他的第一个辅助包的格式是AUX_ADV_IND。

  • AUX_ADV_IND:工作在Secondary Advertising上,符合Common Extended Advertising Payload Format的格式,fields的配置选项如图7。

图7

ADI是强制存在的字段,并且要求和指向它的ADV_EXT_IND中的ADI是相同的,这样子才可以表示这两个广播是关联的,它们协作起来发送同一个payload比较大的广播数据。如果数据广播的payload比较短,一个AUX_ADV_IND就可以发送完成,则它的AuxPtr可以没有,如果广播数据没有发完,则它的AuxPtr字段指向下一个辅助包,它可以是AUX_CHAIN_IND。如果是周期广播的话,那么它的SyncInfo字段指向下一个AUX_SYNC_IND(周期广播)。

  • AUX_SYNC_IND:工作在Secondary Advertising上,符合Common Extended Advertising Payload Format的格式,fields的配置选项如图8。它的作用主要是发送周期广播,并且只可以发送不可连接不可扫描的广播,不存在ADI,也不存在SyncInfo,如果单包无法将所有的广播数据到AdvData和ACAD中,则可以通过AuxPtr来指向其辅助包来携带其他数据,它的辅助包是AUX_CHAIN_IND。从GATT的实现机制类比来看,AUX_SYNC_IND可以看作是GATT传输的ACL数据包。SyncInfo字段,只可能出现在AUX_ADV_IND中,在实现发送周期广播的机制中,AUX_ADV_IND可以类比于legacy的CONNECT_REQ,AUX_SYNC_IND可以类比于GATT的ACL数据包。

图8 

  • AUX_CHAIN_IND:工作在Secondary Advertising上,符合Common Extended Advertising Payload Format的格式,fields的配置选项如图9。它的上级的数据包,可以是 AUX_ADV_IND,AUX_SYNC_IND,AUX_SCAN_RSP或者是另外一个AUX_CHAIN_IND类型的广播。

图9

  • AUX_SCAN_RESP:工作在Secondary Advertising上,符合Common Extended Advertising Payload Format的格式,fields的配置选项如图10。是AUX_SCAN_REQ的回复包,它的辅助包是AUX_CHAIN_IND。

图10

  • AUX_CONNECT_RSP:工作在Secondary Advertising上,符合Common Extended Advertising Payload Format的格式,fields的配置选项如图11。

图11

扩展广播的spec中,经常会出现上级包(superior PDU),辅助包(auxiliary PDU)的概念,我们可以把扩展广播理解为一个单向链表,表头是工作在Primary Advertising上的ADV_EXT_IND PDU(其中AUX_SCAN*和AUX_CONNECT*除外),它里面的AuxPtr指向了下一个工作在Secondary Advretising上的AUX_ADV_IND PDU,如果有更多的数据的话,它里面的AuxPtr还会指向下一个AUX_CHAIN_IND PDU,依次向后,可能会存在n个AUX_CHAIN_IND PDU,直到数据结束,最后一个AUX_CHAIN_IND的AuxPtr字段为空,AuxPtr就像是链表里面的next节点指针。

扩展广播

PDU

上级包 (superior PDU)

辅助包 (auxiliary PDU)

ADV_EXT_IND

-

AUX_ADV_IND

AUX_ADV_IND

ADV_EXT_IND

AUX_CHAIN_IND PDU AUX_SYNC_IND PDU

AUX_SYNC_IND

AUX_ADV_INDAUX_CHAIN_IND

AUX_CHAIN_IND

AUX_ADV_IND

AUX_SYNC_IND

AUX_CHAIN_IND

AUX_CHAIN_IND

AUX_SCAN_REQ

--

AUX_SCAN_RSP

-AUX_CHAIN_IND

AUX_CONNECT_REQ

--

AUX_CONNECT_RSP

--

表1

广播事件类型:

图12中,描述了5.0版本支持的广播事件类型,兼容4.2的legacy的PDU Type我用红色框标注了,从该图中我们可以看到扩展广播是无法发送Connectable and Scannable Undirected Event的,只有legacy的广播可以发送此类型的广播事件。而Scannable Undirected Event广播,legacy和扩展广播都可以发送。

图12

扩展广播:

这部分内容比较多,我们只选取其中几个广播事件类型:

  • Non-Connectable and Non-Scannable Undirected Event:不可连接不可扫描的非定向广播,它不响应scan_req和connect_req消息,使用扩展广播发送时的时序图如图13。

  #1 ADV_EXT_IND(Primary Advertising 37,38,39)

  #2 AUX_ADV_IND(Secondary Advertising)

  #3 AUX_CHAIN_IND(Secondary Advertising)

  #4 AUX_CHAIN_IND(Secondary Advertising)

  ......

#n AUX_CHAIN_IND(Secondary Advertising)

  其中#2~#n处于不同的Secondary信道,由上级包中的AuxPtr指定。

图13

  • Scannable Undirected Event: 可扫描的非定向广播包,使用扩展广播发送时的时序图,如图14,它需要响应扫描请求,其中AUX_ADV_IND,AUX_SCAN_REQ,AUX_SCAN_RSP处于同一个Secondary Advertising。扫描设备在Primary信道监听到ADV_EXT_IND PDU之后,在它的AuxPtr指向的Secondary信道上找到AUX_ADV_IND,然后在该信道上发送AUX_SCAN_REQ,并在该信道上等待Advertising设备回复AUX_SCAN_RSP。AUX_SCAN_REQ和AUX_SCAN_RSP是不需要由ADV_EXT_IND通过AuxPtr指向来的,而是可以直接在Secondary信道上发送,这个和AUX_ADV_IND PDU不同。

图14 

  • Connectable Directed Event:可连接的定向广播,这个广播主要用来使用high duty进行快速回连,与扫描一样,AUX_ADV_IND,AUX_CONNECT_REQ,AUX_CONNECT_RSP是工作在同一个Secondary Advertising上。AUX_CONNECT_REQ虽然工作在Secondary上,但是它不需要ADV_EXT_IND PDU通过AuxPtr指向过来。扫描和连接还涉及了一个失败重试的问题,依赖两个参数backoffCount和upperLimit,退避重试的机制不在这里进行描述了。

图15

定向和非定向的区别,主要在于TargetA是否存在,关于时序部分相差无几,因此可扫描,可连接,不可扫描不可连接,分别找了1个例子来举例广播事件,其中的没有提到的内容还很多,

图16

限制:

  • ADV_DIRECT_IND不能用在LE Coded PHY上,但Connectable Directed Event Type的扩展广播可以用在LE Coded PHY上。
  • ADV_NONCONN_IND同样不能用在LE Coded PHY上,对应的扩展广播可以用在LE Codec PHY上。
  • 还有其他限制待补充。
周期广播:

周期广播是5.0扩展广播的一个功能,他用来周期的发送广播数据,同时它的数据是可以变化的,为什么不用非周期广播来发送呢(非周期广播也可以更改数据,也可以一直处于广播状态),我的理解是为了低功耗和更好的同步性,因为非周期广播的最小间隔是Adv Interval(20ms)+ delay(0~10ms),因为delay的不确定性,扫描者需要打开更多的扫描窗口来接收到需要的广播数据,同时它的同步性没有那么好,但是周期广播没有0~10ms的delay,并且使用跳频技术,因此扫描者可以更小的打开scan窗口,从而降低功耗,获得更好的同步性,周期广播有点类似于单向GATT传输,一对多的GATT连接。当周期广播被启动后,the periodic advertising interval不能被更改。从图8中,我们可以获取到周期广播只能用来发送不可扫描不可连接的广播事件。同时AUX_SYNC_IND如果无法承载全部的AdvData,可以在他后面通过AuxPtr指向下一个AUX_CHAIN_IND PDU。周期广播的AdvInterval为7.5 ms ~ 81.91875 s。

周期广播事件的广播顺序应该是:

#1:ADV_EXT_IND(Primary Advertising)

#2:AUX_ADV_IND(Secondary Advertising,他的SyncInfo字段不为空,类似于legacy的CONNECT_IND,包含着跳频所需的ChannelMap)

#3:AUX_SYNC_IND(如果AdvData超过单包大限制,需要跟着若干个AUX_CHAIN_IND PDU,这个PDU有点类似于GATT的ACL连接包,注意他的SyncInfo字段为空)

#4:AUX_SYNC_IND()

#5:AUX_SYNC_IND()

......

图17

AUX_ADV_IND PDU的SyncInfo field中的Event Counter字段,是这么定义的,每发一次AUX_SYNC_IND PDU,它就会+1,这个起初让我很疑惑它是干什么用的,因为Event Counter本身并不出现在AUX_SYNC_IND PDU中,但是它却会随着每次发送一次AUX_SYNC_IND PDU,它就+1。后来看到了下面这段定义才恍然大悟,原来这个值是用来计算跳频频谱的,发起AUX_ADV_IND的周期广播发起者,和扫描者,都需要实时计算这个Event Counter,为了可以获取下一次接收周期广播的跳频后的信道号。

图18

周期广播传输的AdvData是Host下发的,链路层使用AUX_SYNC_IND PDUs和他的辅助包来发送数据,如果Host不再更新数据的话,链路层会一直重复上次的数据,周期广播会一直发送,直到Host下发了停止周期广播的HCI Command。

图19

图19对我理解周期广播的概念造成了很大的困惑,困惑的点在于第二个AUX_SYNC_IND为什么是由ADV_EXT_IND和AUX_ADV_IND引过来的,周期广播嘛,按理说应该没有他们才对呀,想了很久才想明白,其实第二个ADV_EXT_IND和AUX_ADV_IND是不需要的,没有它,也可以继续发送周期广播,它存在的意义是为了让那些没有收到第一次ADV_EXT_IND和AUX_ADV_IND的扫描设备,也可以与当前的周期广播同步。但是对于第一次就收到了ADV_EXT_IND和AUX_ADV_IND的扫描设备来说,是没有什么意义的。扫描者不会尝试去同步一个已经同步的周期广播。

换个角度说,第一次的ADV_EXT_IND和AUX_ADV_IND确定了AUX_SYNC_IND的广播时序和跳频信道,第二次的ADV_EXT_IND和AUX_ADV_IND是为了让其他扫描设备也可以同步上AUX_SYNC_IND PDU,它不会更改AUX_SYNC_IND的广播时序和跳频信道。之前谈到过,周期广播的实现机制类似于GATT连接,但GATT的单次连接是一对一的,但是周期广播是希望可以很多扫描者都可以同步获取广播上的数据的,因此它会发送多次ADV_EXT_IND和AUX_ADV_IND来保证后面接入的扫描者,也可以同步得获取数据,因此也需要Event Counter这个东西,和前面的内容也严丝合缝的解释清楚了。这里面还涉及一个周期广播Interva和广播Interval的概念,第一次的ADV_EXT_IND,AUX_ADV_IND和第二次的ADV_EXT_IND,AUX_ADV_IND的间隔是广播Interval,AUX_SYNC_IND之间的间隔是周期广播的Interval。

  • 广播interval >周期广播interval:每个ADV_EXT_IND之间会有多个AUX_SYNC_IND出现。
  • 广播interval< 周期广播interval:多个ADV_EXT_IND最终指向同一个AUX_SYNC_IND。
广播集:

广播集的是扩展广播中的一个概念,它通过设置SID和DID,使得蓝牙芯片可以插空的“同时”发送多个不同类型的广播,比如可以“同时”发送可连接广播和不可连接广播,这样的功能对于Host的协议栈代码实现和Controller的实现有很大的帮助,Controller受限于硬件资源,支持的广播集的数量有限,这个需要在实际使用时,询问芯片原厂。

在4.2版本的蓝牙协议中,如果想要发送两个不同类型的广播数据的话,只能在Host层排队发送,发送完第一个类型的广播之后,再发送第二个类型的广播。但是5.0的广播集的概念,Host可以不用排队发送,他们只要设置为不同的广播集,Controller会插空的同时发送两个类型的广播,“插空”的意思是在发送广播集1的空闲的AdvInterval之间发送广播集2。

HCI接口定义:

以上内容大致解释了蓝牙5.0的扩展广播的原理和内容,实际使用上还是通过HCI Command和HCI Event来实现的,因此我们下面介绍一下扩展广播的HCI。

4.2版本:

广播相关:

  • LE Set Advertising Parameters Command:

  • LE Set Random Address Command:

  • LE Set Advertising Data Command:

  • LE Set Scan Response Data Command:

  • LE Set Advertise Enable Command:

扫描相关:

  • LE Set Scan Parameters Command:

  • LE Set Scan Enable Command:

广播上报:

  • LE Advertising Report Event

5.0版本:

新增的5.0广播相关的HCI Command:

  • LE Read Number of Supported Advertising Sets Command:读取controller支持的广播集数量。5.0协议定义的广播集的id范围是0x01~0xF0,共240个广播集合,但受限于Controller资源,通常这个值是个位数。我们实际使用时需要先读取Controller支持的广播集合的个数,广播集的索引总是从0x00开始。

  • LE Read Maximum Advertising Data Length Command:读取controller支持的单次发送的广播数据的大长度(不是单包,而是链式广播的单次)。5.0协议规定这个范围是31~1650,Controller根据自己的实际资源能力返回这个数值。

  • LE Set Extended Advertising Parameters Command:设置广播参数,也是针对指定的广播集Advertising _Handle进行设置,换句话说,就是每个广播集可以设置单独的广播参数, Advertising_Event_Properties用来控制PDU TYPE,其中bit4=1表示是legacy adv,bit4=0,表示是extend adv,PDU TYPE的具体值在其他bit表示。Advertising_SID的值,就是填写在ADI field中的值,其他的字段不依次介绍了。如果该广播集已经处于enable的状态,调用次HCI Command,Controller会返回error code 0x0C。

  • LE Set Advertising Set Random Address Command:设置广播PDU的随机地址,Advertising _Handle表示的是广播集对应的Handler。对比4.2的LE Set Random Address Command可以知道,这两个hci command就差了一个Advertising_Handle参数。

  • LE Set Extended Advertising Data Command:设置广播数据,Advertising_Handler表示设置的广播集对应的Handle,无论该广播集的广播数据的发送是否已经enable,该命令都会执行成功,即使enable,也会在后面更新广播数据,也就是说更新广播数据时,可以不停止当前广播。Data_Length大0~251个字节,表示Data的有效数据长度,我们之前提到过扩展广播单次最多可以发送1650个字节的数据(通过多个AUX_CHAIN_IND PDU来实现),因此如果Data数据量大于251时,这个hci command会被调用多次,一次最多设置251个字节给Controller,也就说1650字节的数据,在HCI层就已经开始分包传输了,并不是通过HCI Command一次传输1650个字节的数据,Operation就是用来帮助分包HCI数据传输的,0x00表示中间包,0x01表示第一个分包,0x02表示最后一个分包,0x03被用来表示分包结束或者用来表示legacy adv data,0x04表示没有数据更新,仅仅是告诉Controller去改变ADI field中的DID的值,Fragment_Preference是告诉Controller按照HCI Command下发的分包方式去分包,还是自行按照最小分包个数的方式去自行分包。

  • LE Set Extended Scan Response Data Command:与LE Set Extended Advertising Data Command的参数基本一致,设置SCAN_RSP的Data,它的Operation没有0x04。

  • LE Set Extended Advertising Enable Command:开启或者停止广播,Number_of_Sets表示打开/关闭的广播集个数,它支持同时打开/关闭多个广播集的广播数据,Advertising_Handle[i]表示的是具体操作的是哪几个广播集,Duration[i]和Max_Extended_Advertising_Event[i]对于发送Mesh广播来说是一个特别好的东西,把Host的任务交给了Controller来更精确的处理。4.2版本的实现Duration的方式是先Enable Adv,然后Host等待Duration这么久,然后再调用Disable Adv,并且具体发送了几个Event,完全是根据AdvInterval和Duration的值粗略的计算出来的,但是5.0很好的解决了这个问题,Host调用一次HCI Command就把Duration和Event的大数量设置好了,其中如果Duraion期间内,如果Max_Extended_Advertising_Events还没有发完的话,则以Duration为准,停止广播。如果Duration为0x00,则会一直发送广播,直到调用disable adv。

  • LE Remove Advertising Set Command:删除指定的广播集。
  • LE Clear Advertising Sets Command:清空所有Controller的广播集。

扫描相关:

  • LE Set Extended Scan Parameters Command:

  • LE Set Extended Scan Enable Command:duplicates是过滤重复包的策略,Duration表示每次扫描任务执行的时间,Period表示扫描任务的执行周期。Period要大于Duration,如果这两个值配置为0,则会一直扫描直到上层调用disable。

广播上报:

  • LE Extended Advertising Report Event:相对于4.2的广播上包相比,5.0的广播上包内容要多出来很多内容,首先它可以一次上报多个设备的广播数据,Num_Reports表示它上包的广播包个数,Event_Type表示每个上报的广播包的PDU TYPE,里面可以有legacy的广播包,也可以有extend的广播包,同时bit5~bit6用来帮助分包上报的,01表述后面还有数据,10表示数据没有收全,但是后面没有数据了,00表示广播数据已接收完成,如果接收的单次广播包很大,它也需要多次上传,Data_Length的大值是229,Advertising_SID表示对应的广播集合ID,用来将分包的数据合成一个完整的数据,Periodic_Advertising_Interva用来上报接收到的周期广播的广播周期(如果Advertising_SID[i]的Data没有周期广播的数据,则Periodic_Advertising_Interval配置为0x0000,如果有数据,除了说明Periodic_Advertising_Interval的值之外,还说明了这个这个SID是周期广播),其他字段不做详细介绍。

周期广播:

周期广播的原理已经介绍过了,通过分析hci的调用方式,我们可以更加理解它的实现机制。我们分为两部分来解释,分为扫描部分和发送部分。扫描部分又分为获取周期广播SID,同步周期广播,获取周期广播的数据。

扫描部分:

  • 获取周期广播SID:

LE Extended Advertising Report Event里面有一个字段叫做Periodic_Advertising_Interval[i],除了表示周期广播Interval之外,还可以表示这个广播集SID[i]代表着的是一个周期广播。

  • 同步周期广播:

然后上层业务就可以根据需要,选择是否监听这个周期广播,如果需要监听的话,调用LE Periodic Advertising Create Sync Command,来通知Controller和这个周期广播建立同步关系。同步成功之后,会上报LE Periodic Advertising Sync Established Event事件,表示成功与对方的周期广播建立了同步关系,该Event中的Advertising_SID和Sync_Handle,表明了所同步的周期广播的SID和对应的handle,后面Host就可以通过Sync_Handle来操作这个同步接收的任务。

  • 获取周期广播的数据:

扫描到的周期广播的数据是通过LE Periodic Advertising Report Event进行上报的(并不是通过LE Extended Advertising Report Event),该Event里面包括了Sync_Handle来表示数据来自哪个周期广播。LE Periodic Advertising Sync Lost Event用来通知Host,与对方的周期广播已经同步失败了(timeout的时间内没有收到任何AUX_SYNC_IND)。

我推测,如果Host不调用Periodic Advertising Create Sync Command的话,Controller虽然可以知道有周期广播存在,但是不会按照周期广播的ChannelMap去解析它的AUX_SYNC_IND的包,只解析道AUX_ADV_IND,知道它指向一个周期广播就可以了,这样子也节省了扫描的资源,如果每个周期广播,Controller都去跟随扫描的话,那么Controller的扫描效率会大打折扣。

创建周期广播(发送部分):

  • LE Set Periodic Advertising Parameters Command:设置周期广播的广播参数,也就是AUX_SYNC_IND的广播参数,这里面有一个很关键的点是这个Advertising_Handle一定要是一个已经存在的,如果不存在会返回错误,也就说周期广播的发起,一定要依附于一个已经存在的广播集。假设之前已经存在一个广播集,它的广播数据发送是这样的,ADV_EXT_IND,接着是一包AUX_ADV_IND PDU,AUX_ADV_IND它里面包含的SyncInfo field是空的,也就说它不关联任何周期广播,当Host选择这个SID来关联周期广播,Host就调用LE Set Periodic Advertising Parameters Command来配置这个SID和本周期广播进行关联。

  • LE Set Periodic Advertising Data Command:设置周期广播的数据,Operation字段与LE Set Extended Advertising Data Command中的Operation字段类似,也支持hci命令分包下分段的数据,其他字段也类似的功能。

  • LE Set Periodic Advertising Enable Command:启动/停止由Advertising_Handle指定的周期广播,这个函数很有意思,如果当前周期广播依附的扩展广播已经开启了,那么这个Cmd可以触发启动周期广播,如果扩展广播尚未开启,它就被pending,直到扩展广播启动后(Host发送LE Set Extended Advertising Enable Command),它接着被启动。另外一点,如果当前周期广播已经启动了,然后host停止了扩展广播,没有停止周期广播,那么周期广播还是会一直发送的,直到Host调用了停止周期广播的HCI Command。这里面可以再回顾一下介绍周期广播的内容,第一个周期广播SYNC包需要扩展广播引用出来,但是一旦引用结束了,理论上就不再需要再次引用了,SYNC包可以一直发送,但是这种情况会引入两个问题,一个是后续打开扫描的设备,无法检测到这个SYNC包了,因为它扫描不到扩展广播,无法找到扩展广播指向的SYNC包了,另外一个问题是晶震的温漂随着时间的流逝积累的越来越大,会给同步性造成影响,所以理论上应该是可行的,但是实际上应该被配置为,几个AUX_SYNC_IND包,接着就是一个指向它的ADV_EXT_IND和AUX_ADV_IND包。

关于HCI的接口这里面要再重提一下兼容性的问题,5.0版本的蓝牙协议定义了2套HCI的接口,这两套接口是可以同时存在的,一套是4.2的HCI Command,一套是5.0的新增的HCI Command,但这两套接口,Host不应该搅合起来用,也就说要不你就都用4.2的旧HCI Command,要不你就都用5.0的新HCI Command,LE Set Extended Scan Parameters Command和LE Set Advertise Enable Command这样的搭配使用是不被允许的。

疑问与解答:

问题1:蓝牙5.0版本的Controller,是否可以与4.2版本的Host兼容。

回答:可以,5.0版本的Controller应该同时实现4.2版本和5.0版本的HCI Command。与4.2版本的Host一起使用时,使用4.2版本的HCI就可以了,但是这样就浪费了Controller的5.0的能力。

问题2 :蓝牙4.2版本的controller,是否可以与5.0版本的host兼容。

回答:理论上可以,但需要Host实现的很复杂,需要Host支持两套HCI Command,并且更难的是,要根据不同的Controller版本调整程序的实现架构,所以一般可以不用兼容,更好的方案是直接一个宏定义控制,或者有不同的分支版本来控制两套代码。Host可以使用发送Read Local Version Information Command来读取Controller的版本,从而选择不同的HCI Command和代码架构。

问题3:蓝牙5.0版本的controller + host芯片方案,是否可以与对端4.2版本的设备兼容。

回答:当然是可以的,5.0也可以收发4.2的广播包,并且比4.2更高效。

问题4:蓝牙5.0版本的controller + host芯片方案,是否可以指定发送legacy广播或者extend 广播。

回答:当然是可以的,可以配置发送legacy广播,还是extend广播,还是周期广播,可以设置PDU Type。

问题5:官方SIG Mesh Profile,是否支持通过蓝牙5.0版本协议,发送大payload的扩展广播。

回答:Mesh Profile虽然是在5.0协议发布之后才发布的,但是它为了更好的兼容性,加上本身就没有那么大的控制需求,所以从设计的角度,就没有考虑使用扩展广播发送大payload的数据包,至少1.0版本是如此,即将release的1.1版本也没有使用到扩展广播。

问题6:官方SIG Mesh Profile与蓝牙5.0版本协议的关系。

回答:这个问题可以从两个角度来看:从协议设计的角度来讲,可以说没有什么关系(1.0版本和1.1版本来看),mesh协议设计之初,就考虑到了要兼容4.2版本的蓝牙协议(广播消息有效的payload只有31个字节),因此我们现在看到的mesh协议才是现在这个样子,mesh协议为什么需要设计IV Update的过程,为什么不在每一包mesh消息数据都带着完整的4字节IV Index或者简单的增加seq number的字节数,一切的一切,都是为了兼容4.2版本的蓝牙协议。如果当时考虑到了使用5.0的扩展广播上实现SIG Mesh协议,就不应该设计IV Update的机制。因此可以得出一个结论,从SIG Mesh release出来的协议来看,到目前为止,它没有想过放弃4.2版本蓝牙,也没有考虑使用扩展广播来发送Mesh消息,也没有考虑过通过Mesh协议发送长包(目前1.0版本协议,和即将release的1.1版本协议,没有涉及到使用扩展广播发送Mesh协议,但据说2.0版本的Mesh协议会涉及一部分扩展广播的功能,但是只要它不放弃4.2,那么也仅仅是某些功能使用5.0的扩展广播)。如果有需求希望通过5.0的扩展广播发送长包,我建议在5.0的基础上,重新设计一套私有的Mesh协议;从HOST的代码实现的角度来看,蓝牙5.0和Mesh协议还是有关系的,因为5.0不仅支持大payload的扩展广播,也支持多广播(也就是多广播集),多广播这个特性,可以很大程度的简化Host的mesh协议相关的实现,Host可以同发送SNB和Mesh控制消息,并且可以很方便的设置发包个数和发包的Duration。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


新闻标题:深入理解蓝牙BLE之“扩展广播”-创新互联
本文来源:http://myzitong.com/article/hdeip.html