赞
踩
目录
蓝牙Mesh协议是在BLE广播的基础上设计实现的,因此接入Mesh网络的设备,就需要有足够的时间片来进行扫描操作,以接收其他设备随时可能发送的mesh消息。开启扫描对于BLE芯片来说是一个比较费电的操作,一般的蓝牙芯片扫描功率一般为 6mA左右(以Telink 8253为例,它的扫描功耗Whole Chip RX mode: 5.3mA,发射功耗Whole Chip TX mode: 4.8mA ),这对使用纽扣电池的低功耗设备很不友好,例如CR2450纽扣电池只有550mAh的容量。5号电池一般在2500mAh左右。
因此Mesh协议为了满足低功耗设备的需求,设计了LPN(Low Power Node)和Friend的特性,核心思想是LPN低功耗的Mesh设备,不需要一直打开扫描去被动的接收其他设备的消息,而是主动的周期性的去Friend设备那里去询问,是否有发给我的消息。化“被动扫描”为“主动查询”,而主动查询的周期可以配置为相对较长时间,进而实现了降低功耗的需求。Friend设备来帮助LPN设备缓存一定数量的消息,供LPN设备来查询,Friend设备一般是常带电的。
低功耗设备有一个前提,就是它不需要频繁的发送消息和接收消息。不可能既让它频繁的工作,又让它保持一个较低的功耗,这个是不合理的。典型的低功耗设备就是传感器。
Mesh设备是否为LPN设备,是在它的Composition Data的Features字段里面定义的,无法动态改变。一个Mesh设备的Friend特性,也是在Composition Data的Features字段中定义的,如果支持Friend特性,是可以通过config model的消息来打开/关闭该特性的。Friend特性涉及的消息大部分为“控制消息”,不上报到access layer层。
既然LPN节点依赖Friend节点来帮助其缓存消息,那么LPN的第一步操作,就是去找到一个合适的Friend节点,和这个Friend设备建立起“Friendship的关系”
LPN设备上电之后,开始去“找朋友”,它向Friend Node的组地址(0xFFFD),发送Friend Request消息,支持Friend特性并且打开了Friend特性的节点,会回复Friend Offer消息,如果周边的Friend节点很多,最终LPN会选择其中一个Friend节点与之建立FriendShip关系,后面就是进行Friend Poll和Friend Update的正常通信了,完整过程如图1。
图1
消息格式如图2:
图2
该消息中,定义了Friend设备通信中使用的PollTimeout,ReceiveDelay这两个时序参数,这两个参数的作用,本文后面有介绍。另外比较重要的是Criteria字段,它的详细定义如图3,其中最重要的是RSSIFactor和ReceiveWindowFactor这两个因子。Criterai的作用是为了让LPN从众多Friend节点中选出一个最优的设备建立Friendship关系,其他的非最优的设备则被忽略,LPN同一时间只能与一个Friend设备建立FriendShip关系。
图3
详细格式如图4:
图4
此消息中的ReceiveWindow表示这个Friend需要LPN节点支持的扫描窗口,详细后面有介绍。QueueSize表示的是Friend可以为LPN缓存的消息队列的大小。RSSI信号强度,可以变相理解为Friend和LPN之间的距离(RSSI越大,表示两个设备越近,RSSI越小,表示两个设备越远)。
介绍完Friend Request消息和Friend Offer消息的格式之后,再讲解一下LPN选择最优Friend的逻辑,根据协议定义,Friend设备收到Friend Request之后等待Friend Offer Delay时间之后,再回复Friend offer消息。这个Delay的时间计算如下:
图5
这里面涉及到了RecevieWindow和RSSI两个核心参数以及前面提到两个因子。ReceiveWindow和RSSI是Friend offer消息中的字段,两个因子是Friend request消息的字段。我们从LPN的角度来看,它肯定最想要RSSI最强的,要求自己的扫描窗口最小(可以降低功耗)的设备来与它建立FriendShip,从上面的公式可以算出,越是符合LPN理想型的Friend设备,Local Delay的值越小,回复的越快。因此LPN节点会选择回复Offer最快的那个Friend设备来建立FriendShip关系。但是一个Friend设备有可能不同时拥有最优的RecevieWindow和RSSI。这时候就需要LPN来做取舍了,LPN的Friend request消息中这两个因子开始起作用了:更需要“小receiveWindow”的话,就把ReceiveWindowFactor调大,增加“大ReceiveWindow”Friend设备回复的delay时间,减少它被选择可能性;更在乎RSSI的话,就把RSSIFactor调大,减少“信号强度高”的Friend设备回复的时间,增加它被选择的可能性。
另外,在Friend建立过程中,确定了三个时序参数:ReceiveDelay,ReceiveWindow,和PollTimeout。
ReceiveDelay:LPN节点发送request之后,等待ReceiveDelay这么长时间后,再打开扫描以接收Friend Node的response。RecevieDelay主要是为了给Friend节点一定的时间来准备response。
ReceiveWindow:ReceiveWindow与BLE的scan Window类似,即打开扫描的窗口,以接收Friend的response消息。此参数设置的过大,会增大LPN设备的功耗(这个参数是Friend节点来确定的,如果这个Friend节点的发送性能差,它就会要求LPN开启更大的扫描窗口来接收它的消息)。
PollTimeout:Friend节点连续收到两个LPN的poll消息的最大时间间隔。在Friend节点收到LPN节点的poll消息后,又过了PollTimeout这么长时间,如果没有收到任何LPN节点的poll消息,则仍认为是LPN节点已经离线了,这时候Friend节点可以单方面终止FriendShip关系。
根据深入理解蓝牙Mesh的消息格式之“格式与长度”的文章可知,Friend request,Friend offer和Friend Poll等消息属于transport layer control消息,格式中有一个7bit的opcode的定义,图2和图3中的数据是实际上是transport layer control消息中的部分内容,Friend request的opcode是0x03,Friend offer的opcode是0x04。
建立起FriendShip关系之后,LPN节点和Friend节点就开始正常通讯了。
图6
Friend节点扫描到有发给“与自己建立了FriendShip的LPN节点”的消息时,会帮LPN设备缓存,缓存在自己的队列中,等待LPN设备来查询。Friend节点接收到LPN设备的Friend Poll消息,则回复它缓存的消息,当有IV更新或者缓存队列为空时,则发送Friend Update给LPN设备。另外Friend设备还可以接收LPN设备的Mesh消息,并替它relay出去。
当LPN设备通过Friend Poll消息来查询时,Friend发送它缓存的Mesh消息,如果缓存队列为empty,则发送Friend Update消息(MD=0)通知LPN设备。只有当缓存队列为空,或者IV Index更新时,才会发送Friend Update消息。
LPN节点周期发送Friend poll消息去Friend节点处查询,是否有发给自己的access layer消息,Friend节点则回复相应的access layer消息给LPN节点,如果IV发生了变化,则通过Friend update消息告知。这里的access layer消息指的是开关/设置亮度等。当然也可以是SNB消息。
当LPN节点需要向外发送消息时(这里指的是access消息,并非是Friend相关的control消息),可以选择通过Friend Node来relay转发,也可以直接跳出FriendShip的关系,直接发到Mesh网络中。向外发送的消息指的是开关状态,亮度状态等。
Friend Poll消息格式如下图:
图7
FSN:是FRIEND SEQ NUMBER的缩写,仅有一个bit,会从0,1,0,1之间跳变。当LPN设备发送的Friend Poll消息收到了的回复(Friend Update或者缓存的Mesh接入消息),下一包的Friend Poll消息中的FSN会变化。Friend节点也会根据LPN的Friend Poll消息中的FSN变化,判断上一条消息回复,LPN是否收到(如果LPN节点的Friend Poll消息中的FSN没有变化,Friend则重发上一条消息)。
Friend Update消息如下图:
图8
Flags,IV Index这两个参数,与SNB消息中的含义相同,MD表示队列是否为空。LPN节点可以一直频繁的Friend Poll,直到收到MD为0的Friend Update消息(MD为1,表示还有数据,MD为0,表示数据队列已为空)。
图9
管理Friendship相对来说,没有那么多可说的内容,图9基本上可以解释清楚了。当一个Friend节点掉电后,LPN会一直Friend Poll不到消息,进而主动终止FriendShip关系,寻找新的Friend节点。找到新的Friend节点并建立FriendShip关系之后,会由新Friend节点负责发送Friend Clear消息通知旧Friend节点:“你和LPN节点的友谊关系已经结束了,现在LPN已经跟了我了”,旧Friend节点收到后,回复Friend Clear Confirm,也终止了FriendShip关系,不再为LPN设备缓存消息。
新Friend节点是如何知道旧Friend节点的地址的呢?其实是LPN设备通过Friend request消息中的PreviousAddress字段告诉他的。看到这里明白了,LPN设备挺阴险呀,自己不愿意告诉旧Friend节点:“我们已经结束了”,而是告诉新Friend节点关于旧Friend的信息,让新Friend去当这个坏人。
图10
Friendship是Friend节点和LPN节点之间的私事,不想让其他节点知道,因此通信过程中使用了私有的密钥进行加解密,私有的EncryptionKey,PrivacyKey和NID,这三个元素的生成规则如图10,叫做friendship security material,阅读过我的前几篇文章的朋友,会知道这三个都是用来加密和混淆network层的数据包的。
Friend Poll,Friend Update,Friend Subscription List Add/Remove/Confirm message和Friend节点缓存的消息,这几个是使用friendship security material进行加解密和混淆的。
Friend Request,Friend Offer,Friend Clear和Friend Clear Confirm消息仍然使用网络主密钥进行加解密。
Friendship中的涉及的seq number,LPN的seq number也会引起主网络的IV Update。虽然没用使用主密钥,但是Mesh网路中每个设备的seq number只有一个,无论它有几个网络。
LPN节点在publish的时候,可以选择Friendship的密钥,也可以选择主密钥。选择前者需要Friend节点帮助它把消息relay出去,使用后者则相当于直接发送状态到网络中。根据Publish 消息的Friendship Credentials Flag的值,用来表示选择这两种方式中的哪一种。
图11
上图中,虚线表示使用friendship的密钥进行加密,实线表示使用网络主netkey的派生密钥进行加密。OutMsg1是通过Friend节点relay出去的,OutMsg2是直接发送去的。
这里要提到一点,如果使用ellisys抓包分析Friend和LPN节点的通信过程的话,需要把FriendShip建连时的Friend Request和Friend Offer也抓到,不然ellisys无法计算出friendship的密钥,无法解密出Friend Poll和Friend Update消息。
协议的设计可以很理想化,工程落地则应该接地气。应了那句话,理想很丰满,现实却是很骨感。很多IOT产品在硬件设计时,出于对成本的考虑,往往选择比较便宜BLE芯片,这在某种程度上增加了Mesh开发的难度,工程师们不仅仅要理解Mesh协议的细节,还要根据现有的硬件能力做优化,做妥协和增加额外的设计,可能这就是做设计和做工程的区别。
从事蓝牙Mesh的开发,经常会遇到各种硬件条件的限制:
1.没有使用独立的BLE芯片来支持Mesh,而是使用了WiFi/BT的combo芯片,很多时候Combo芯片只有一根天线,WiFi和BT分时复用,因此Mesh无法开启100%的扫描窗口,WiFi和BT对天线的使用进行切换时,也会有切换时间的损耗。
2.处理器能力偏弱,很多controller不支持多级中断,在各种状态切换时,会引入多余的时延。
3.LPN节点无法单独使用,需要在其周边配置Friend功能的Mesh节点,已给他缓存消息。
4.Friend节点搭配LPN节点一起使用时,需要二者的时序完美的配合才能正常工作,如果每次LPN来Friend节点Poll消息时,Friend节点都处于非BLE扫描的状态,就会导致LPN节点无法获取Mesh消息,或者Poll消息成功率低。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。