<!--
小编在前面的几个章节讲解了MESH各层的帧格式、入网的整个过程以及基础模型的作用,基本上构筑了SIG MESH的理论地基;接下来让读者们跟随着小编的步伐趁热打铁,继续讲解节点中各角色的工作流程是怎么样的;对于各角色的功能,不知道大家脑海里是否还有印象,小编在SIG MESH各个角色的功能简介中就提及到,节点的角色是由其特性所决定,而这个特性是可选的,一个节点可以存在零个或者多个特性。那么,接下来小编要讲的就是Proxy特性,即代理节点。
既然是要讲解到代理节点,那么就不得不提及代理协议了。小编在PB-GATT入网过程以及BLE Mesh各层帧包格式详解这两个篇章均有稍微提及,那么在这篇章节小编将增加更多的细节内容。其中,代理协议的作用:
使用代理协议可以收发Network PDUs、Mesh Beacons、Proxy Configuration Messages和Provisioning PDUs;
除了Provisioner之外,支持代理协议的节点基本支持GATT承载和ADV承载,即代理节点;
仅支持GATT承载的节点想要跟其他同一个Mesh网络中仅支持ADV承载的节点或者unprovisioned device进行数据交互,必须使用代理协议收发这些信息;
代理角色当且仅当只有两种Server和Client,其主要的作用如下:
Proxy Server
Proxy Client
小编在上述Proxy Protocol中的代理协议提及的内容,除了Proxy Configuration Messages之外,其他的均已经细述;可能敏感的读者已经察觉;没错,Proxy Configuration Messages就是用于配置Proxy Filter。顾名思义,Proxy Filter主要是用于Proxy Client过滤掉它不想要的数据,仅接收想要的一些目标地址的信息。这里的过滤指的是不向Proxy Client发送数据,并不是Proxy Server过滤掉不想要的数据,这个举个例子:
如果过滤器类型为白名单,其中白名单中有0xC000的地址;这个时候有一个目标地址也是0xC000的消息,让与Proxy Client相连接的Proxy Server扫描到了,这个时候Proxy Server就会通过GATT承载将该消息发送给Proxy Client;前提是当前的Proxy Server使能了中继特性,且TTL >= 2;否则,传到Proxy Server的Lower Transport Layer就被丢弃了
其中过滤器类型如下所示:
白名单
除了白名单里的目标地址,其他的目标地址均不被Proxy Client所接收;其中目标地址可以是单播地址、组地址或者虚拟地址;
由上图可以看到,由于Msg1/2中的目标地址均没有在白名单中,所以都被丢弃了;
黑名单
跟白名单相反的操作,但凡在黑名单中的目标地址均不被Proxy Client所接收;
由上图可以看到,同样的原因,Msg1被丢弃是因为其目标地址没有在白名单中 (具体原因,参考上述的Proxy Server.2);然而Msg2之所以可以被传送到Proxy Client,是因为其目标地址没有在黑名单中;
一般Proxy Filter默认为白名单类型且名单的列表内容为空,这个时候有读者可能会有这样的疑问:
既然默认为白名单且名单列表也为空,而且上述的Proxy Server.2也加强了这个观点,但是为什么小编之前篇章所提及的内容中,Proxy Client和Proxy Server却仍然能正常通信呢?白名单列表不是为空吗?是不是小编在胡说八道?
不管怎么样,小编都不会忽悠你们的哈;除了上述之后,其实还有如下几个比较特殊的点:
这也是为什么我们并没有设置白名单的内容,Proxy Client和Proxy Server仍然能正常通信的原因。
从上图的1中可知,白名单列表默认就是空的,只有增加了一个目标地址之后,其白名单列表才变成1;可能这个时候又会有读者有疑问:“Proxy Client不是已经发了Set Filter Type和 Add Addresses To Filter吗?为什么它的源地址没有添加至白名单?”
原因如下:
在没有收到任意来自于Proxy Client的有效信息时,是不会往白名单中添加的。上述的疑问中提及到的Set Filter Type和 Add Addresses To Filter中的目标地址均为unassigned address,放在Network PDU中这不算是一个有效的Mesh Message。因此,当收到这些消息时则不会将其源地址添加至白名单中;
接下来,我们再来看看上图中的2,当收到来自于Proxy Client的有效信息---Mesh Generic OnOff Get时,此时就会将该消息的源地址添加至白名单中;我们往白名单新增一个地址之后,可以从返回的Filter状态中看出此时的白名单中存放了两个地址了。
小编在上文就已经提及,代理协议还可以传输Proxy Configuration Messages,专门用于配置Proxy Server的Proxy Filter;其中该消息的帧格式跟NetWork PDU是一致的,只不过下面的域的值有些许不同:
该消息的Transport PDU帧格式如下所示:
Field Name | Size(octets) | Notes |
---|---|---|
Opcode | 1 | Message opcode |
Parameters | variable | Message parameters |
其中,该消息的Opcode如下表所示:
Value | Opcode | Notes |
---|---|---|
0x00 | Set Filter Type | Sent by a Proxy Client to set the proxy filter type |
0x01 | Add Addresses To Filter | Sent by a Proxy Client to add addresses to the proxy filter list |
0x02 | Remove Addresses From Filter | Sent by a Proxy Client to remove addresses from the proxy filter list |
0x03 | Filter Status | Acknowledgment by a Proxy Server to a Proxy Client to report the status of the proxy filter list |
0x04-0xFF | RFU | Reserved for Future Use |
Proxy Client发送该消息设置Proxy Filter类型,同时清空Proxy Filter列表的内容。其帧格式的内容如下所示:
Field Name | Size(octets) | Notes |
---|---|---|
Filter Type | 1 | The proxy filter type |
其中Filter Type有如下几种:
顾名思义,该消息用增加一个或者多个目标地址至Proxy Filter列表中,其中目标地址可以为:
具体的帧格式如下所示:
Field | Size(octets) | Notes |
---|---|---|
AddressArray | 2*N | List of addresses where N is the number of addresses in this message |
由上述可知,各种类型的地址的大小为16bits。
跟上述ADD Addresses To Filter相反的操作,该消息是从Proxy Filter列表中删除一个或者多个在Proxy Filter列表中的目标地址;但是你不能选择你要删除哪个目标地址,只能选择删除多少个目标地址;其帧格式跟上述的ADD Addresses To Filter是一样的,只不过Opcode不一样。
该消息用于应答上述的Set、Add、Remove消息,其帧格式内容如下所示:
Field | Size(octets) | Notes |
---|---|---|
FilterType | 1 | White list or black list |
ListSize | 2 | Number of addresses in the proxy filter list |
小编在上述中已经提及了代理协议、代理角色以及代理过滤器的配置;那么,Proxy Client与Proxy Server又是通过怎样进行数据收发的呢?这也就涉及到代理节点的工作流程是怎么样的;显然,它们之间的数据交互就是通过GATT承载来实现的。接下来小编将带大家好好讲讲它们的“庐山真面目”。
该服务的主要作用是用于Proxy Client配置Proxy Server,以使其加入Mesh网络;而且该服务只会存于unprovisioned device中,这也就是说一旦unprovisioned device入网变为node之后,Mesh Provisioning Service就会消失;而这里的消失只是说不暴露出来这个Service,并不是说彻底取消这个服务了,因为一旦node再次变成unprovisioned device的时候,这个服务就又会冒出来了;需要注意的是,该Service UUID为0x1827。
由上图我们可以清楚知道Provisioning Service的脉络:
如上述的Provisioning Protocol,Provisioning PDUs只不过是Proxy PDU的子集。对于该服务,读者无须有恐惧感,其跟我们平时普通的BLE服务是一模一样的,只不过该服务是专门用于配置Proxy Server,使其加入mesh网络;为了加强对这个概念的巩固,我们可以参考下图:
由于是Proxy Node,在还没有入网之前,unprovisioned device必须要发出可连接非定向广播;因为只有这样,Proxy Client才给跟Proxy Server建立连接,从而进行配置并使其加入Mesh网络;而且,Provisioning Service也要在该广播包中暴漏出来,其具体的帧格式如下所示:
AD Type | Total Length | Requirement | Comments |
---|---|---|---|
«Flags» | 3 | M | |
«Incomplete List of 16-bit Service UUIDs» or «Complete List of 16-bit Service UUIDs» | 4 | M | Include «Mesh Provisioning Service» |
«Service Data» | 22 | M | Service Data AD Type for «Mesh Provisioning Service» followed by Service Data for this service |
其中Service Data又包含如下几部分:
Field | Size(octets) | Notes |
---|---|---|
Device UUID | 16 | |
OOB Information | 2 |
除了可连接非定向广播之外,如果设备还支持PB-ADV,那么unprovisioned device还会发出不可连接的非定向广播,也就是Mesh Unprovisioned Device Beacon。关于该Beacon的详情请参考Mesh Beacon帧格式;这也就是说当device还没有入网之前,它会交替发送不可连接非定向广播和可连接非定向广播。
其中可连接非定向广播的帧格式如下所示:
至于,上述提到的Service Data中的内容细节,请参考Mesh Beacon帧格式;
由上述的Provisioning Service可知,Provisioning Service共有两个特征值分别为:
不知道读者对PB-GATT入网过程还有没有印象,其中Provisioning PDUs中长度最长的就是Provisioning Public Key共64字节;所以为了容纳这个最长的PDU,不管是In还是Out,这两个特征值的数据最大长度均为66字节,而且ATT_MTU值最好大于等于69字节 (不强制);这又是什么骚操作呢?
为了理清上述之间的数据依赖关系,小编又专门绘制一张它们的关系图如下所示:
如此,我相信读者如今可以理会明白它们之间的关系了吧;至于,该服务是如何对进行数据交互的,如下所示:
入网之后,Service就由Mesh Provisioning Service切换成Mesh Proxy Service;那么,这也就意味着入网完成之后,紧接着会有一个断开连接的动作,然后Node发出带Mesh Proxy Service内容的可连接非定向广播包,Provisioner再次与其建立联系,从此以后都是通过Mesh Proxy Service进行入网之后的数据交互。
跟上述的Mesh Provisioning Service-->Advertising一样,Node必须要发出可连接非定向广播;因为只有这样,Proxy Client才给跟Proxy Server建立连接,从而在Mesh网络中进行数据交互;而且,Proxy Service也要在该广播包中暴漏出来,其具体的帧格式如下所示:
AD Type | Total Length | Requirement | Comments |
---|---|---|---|
«Flags» | 3 | M | |
«Incomplete List of 16-bit Service UUIDs» or «Complete List of 16-bit Service UUIDs» | 4 | M | Include «Mesh Proxy Service» |
«Service Data» | 21 | M | Service Data AD Type for «Mesh Proxy Service» followed by Service Data for this service |
其中Service Data又包含如下几部分:
Field | Size(octets) | Notes |
---|---|---|
Identification Type | 1 | 0x00->Network ID type; 0x01->Node Identity type; 0x02-0xFF->Reserved for future use |
Identification Parameters | Variable | Format determined by Identification Type field |
Network ID type
如果存在多个子网,那么根据不同的NetKey交替发送携带不同NetWork ID的可连接非定向广播;那么Provisioner就可以根据所属的子网在众多的Mesh网络中连接到同一个Mesh网络的节点;而携带该标识类型的Service Data的内容如下表所示:
Field | Size(octets) | Notes |
---|---|---|
Identification Type | 1 | 0x00 (Network ID type) |
Network ID | Variable | Identifies the network |
其中,Network ID由如下公式计算得到:
Network ID = k3 (NetKey)
完整的一帧广播包如下图所示:
Node Identity type
至于Node Identity Type,小编这里不再细述;详情可以参考Configuration Model浅析;但是,需要注意的是:当设备入网完成之后,紧接着会有一个断开连接的动作,然后Node发出带Mesh Proxy Service内容的可连接非定向广播包,此时就是Node Identity类型的广播包;当然,其后续可以通过Configuration Model的Node Identity命令再次打开;还有一点就是,无论节点是否支持或启用代理功能,节点都可以使用Node Identity进行广播。;
除了可连接非定向广播之外,如果设备还支持PB-ADV,那么node还会发出不可连接的非定向广播,也就是Mesh Secure Network Beacon。关于该Beacon的详情请参考Mesh Beacon帧格式;这也就是说当device入网之后,它仍然会交替发送不可连接非定向广播和可连接非定向广播。
跟上述的Mesh Provisioning Service Characteristics一样,该服务也有两个特征值分别为:
小编在上述不断地再提及,Proxy Service还可以传输如下三个类型的数据:
由于这些类型帧的最大长度没有一个固定值,所以Spec规定Proxy Service的ATT_MTU最好是大于或等于33字节即可;可能读者会想:“为什么是33这个数字,而不是34或者35?”,敏感的读者可以会联想到上述的Mesh Provisioning Service Characteristics;是的,这种联想是完全正确,因为Provisioning PDUs中最大的数据包就是64字节,经过层层拼装 (如上图的mesh_provisioning_service_data_flow所示) 之后,ATT_MTU最好是大于或者69字节;而Mesh Proxy Service则以Network PDUs的最大传输单元为基准即29字节,层层拼装之后就是33字节了;如下图所示:
是不是基本上是一样的 “套路” ;至于,该服务又是如何对进行数据交互的,如下所示: