JN5169 NXP ZigBee PRO 无线网络应用所需的常见操作
Posted Calvin Chan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JN5169 NXP ZigBee PRO 无线网络应用所需的常见操作相关的知识,希望对你有一定的参考价值。
JN5169 NXP ZigBee PRO 无线网络应用所需的常见操作(二)
4、绑定
为了在不同节点上运行的应用程序之间进行数据通信,“绑定”相关的源和目标端点可能很有用。当数据随后从源端点发送时,它会自动路由到绑定的目标端点,而无需指定目标地址。例如,可以在恒温器节点上的温度传感器端点和加热控制器节点上的开关端点之间创建绑定。绑定的详细信息保存在源节点上的绑定表中。其中绑定是一对一、一对多或多对一。
本节介绍如何设置绑定请求服务器以及如何将两个节点绑定在一起,以及如何解除它们的绑定。还描述了对绑定表的访问。
注意:在 64 位 IEEE/MAC 地址用于识别远程节点的情况下,相应的 16 位网络地址必须在本地地址映射中可用。
① 设置绑定请求服务器
必须在将成为绑定数据传输源节点的每个设备上设置绑定请求服务器。该服务器管理绑定的数据传输,以便应用程序处理不会被并发请求阻塞到传输的多个目的地。它通过限制目的地的数量并在绑定传输的连续传输之间插入时间延迟来实现这一点。
服务器在 ZPS 配置编辑器中配置。必须设置两个参数值:
- 同时请求
这是指绑定数据传输的最大目的地数。设置的值必须小于或等于 ZigBee 网络参数 Maximum Number of Simultaneous Data Requests 或 MaximumNumber of Simultaneous Data Requests with Acks 的值。 - 时间间隔
这是指连续传输到绑定数据传输的不同目的地之间的时间间隔,以毫秒为单位。
在 ZPS 配置编辑器中,通过单击设备的 ZDO 配置下的绑定请求服务器来访问这些参数(参数显示在底部窗格的属性选项卡中)。
注意:绑定服务器一次只能处理一个绑定请求。在尝试发送第二个绑定请求之前,应用程序必须等待第一个绑定请求的确认。
② 绑定端点
可以使用以下函数将本地节点上的端点绑定到远程节点上的一个或多个端点:
- zps_eAplZdoBind() 创建到单个远程端点的一对一绑定。
- zps_eAplZdoBindGroup() 创建一对多绑定,通过组地址为其指定目标端点。
还提供了函数 zps_eAplZdpEndDeviceBindRequest(),它允许通过协调器将一个终端设备上的端点绑定到另一个终端设备上的端点。必须在两个终端设备上调用此函数,其中函数调用通常由用户操作(例如按下节点上的按钮)触发。该函数向协调器提交 End_Device_Bind_req 请求,协调器以 End_Device_Bind_rsp 响应进行回复。然后堆栈将自动更新终端设备上的绑定表(作为来自协调器的绑定请求的结果),这些更新将由每个终端设备上的 zps_EVENT_ZDO_BIND 事件指示。
③ 解除绑定端点
可以使用以下函数删除绑定:
- 之前使用 zps_eAplZdoBind() 绑定的两个端点可以使用函数 zps_eAplZdoUnbind() 解除绑定。
- 之前使用 zps_eAplZdoBindGroup() 绑定的端点可以使用函数 zps_eAplZdoUnbindGroup() 解除绑定。
④ 访问绑定表
有关已建立绑定的信息保存在相关节点上的绑定表中。通常,绑定表保存在包含至少一个用于绑定的源端点的节点上——因此,该表包括涉及本地节点上的源端点的所有绑定的条目。或者,特定源节点的绑定表条目可以保存在节点的父节点或另一个上升节点上的主绑定表缓存中。但是,如果主绑定表缓存存在于上升节点上,则源节点可以通过调用函数 zps_eAplZdpBindRegisterRequest() 来选择退出该表的成员资格,以指示源节点将在本地存储其自己的绑定表条目。
提供了允许远程访问和修改绑定表的功能。这些功能在实施调试工具应用程序时特别有用。
通过请求修改远程节点上的相关绑定表,可以远程创建或删除绑定。远程绑定表可以是主绑定表缓存或源节点的本地绑定表,以与特定绑定相关的为准。
- 函数 zps_eAplZdpBindUnbindRequest() 可用于请求将新绑定添加到远程绑定表。此绑定的添加由远程节点上的 zps_EVENT_ZDO_BIND 事件发出信号。
- 函数 zps_eAplZdpBindUnbindRequest() 还可用于请求从远程绑定表中删除现有绑定。此绑定的删除由远程节点上的 zps_EVENT_ZDO_UNBIND 事件发出信号。也可以使用函数 zps_eAplAibRemoveBindTableEntryForMacAddress() 在本地删除绑定表条目,该函数请求删除包含特定 IEEE/MAC 地址的条目。
此外,可以使用函数 zps_eAplZdpReplaceDeviceRequest() 修改远程主绑定表缓存中的绑定条目,以替换 IEEE/MAC 地址和/或端点编号。此操作在绑定表中以“搜索和替换”为基础进行工作,要替换的地址/端点号可能出现在一个或多个表条目的源或目标中。
还提供了 zps_eAplZdpMgmtBindRequest() 函数,可用于请求远程节点的绑定表。
5、传输数据
本节介绍如何向远程节点发送数据并在目的地接收数据。 还描述了数据轮询方法,该方法由终端设备用于在终端设备处于睡眠状态时获取到达其父设备的数据。
① 发送数据
数据在应用协议数据单元 (APDU) 中通过无线网络发送。在调用函数发送数据之前,必须首先使用 PDUM 函数 PDUM_hAPduAllocateAPduInstance() 分配一个 APDU 实例,然后使用 PDUM 函数 PDUM_u16APduInstanceWriteNBO() 填充数据。
有五种方法可以将数据发送到一个或多个远程节点:
- 单播:将数据发送到单个目标端点
- 广播:向(可能)所有端点发送数据
- 组播:向一组端点发送数据
- 绑定传输:将数据发送到绑定端点
- PAN 间传输:将数据发送到另一个 ZigBee PRO 网络
这些方法在下面的小节中描述。但是,在除 PAN 间传输之外的所有情况下,都可以使用通用函数 zps_eAplAfApsdeDataReq(),它对目标地址、目标集群和目标端点号没有限制——这些目标参数不需要为堆栈或在 ZPS 配置中定义。
注 1:在所有情况下,一旦成功发送数据包,就会生成“DATA_CONFIRM”堆栈事件。当向一个或多个单独节点发送数据(非广播)时,在从“下一跳”节点收到 MAC 级确认后生成此事件。
注 2:在 64 位 IEEE/MAC 地址用于识别远程节点的情况下,相应的 16 位网络地址必须在本地地址映射中可用。
a、单播
单播是到单个目的地的数据传输 - 在这种情况下,单个端点。可以使用节点的网络地址或 IEEE/MAC 地址指定单播的目标节点:
- zps_eAplAfUnicastDataReq() 用于将数据包发送到具有给定网络地址的节点上的端点。
- zps_eAplAfUnicastIeeeDataReq() 用于将数据包发送到具有给定 IEEE/MAC 地址的节点上的端点。
这些功能都没有提供数据包已成功传送到其目的地的任何指示。单播数据包可能无法到达其目的地,因为数据包丢失 - 例如,它陷入循环路由中。但是,可以使用等效函数来请求目标节点提供接收到的数据的确认——这些“带有确认”的函数是 zps_eAplAfUnicastAckDataReq() 和 zps_eAplAfUnicastIeeeAckDataReq(),分别需要网络和 IEEE/MAC 地址。这些函数请求端到端确认,收到后会生成 zps_EVENT_APS_DATA_ACK 事件(注意“下一跳”zps_EVENT_APS_DATA_CONFIRM 事件也将生成)。对确认应用大约 1600 毫秒的超时。如果在超时期限内未收到确认,则重新发送数据,并且在完全放弃数据传输之前最多可以再执行 3 次重试(发生在初始发送后大约 3 秒)。
注意:如果消息单播到尚未建立路由的目的地,则不会发送消息,而是执行路由发现。如果是这种情况,单播函数将返回 zps_NWK_ENUM_ROUTE_ERROR。然后,应用程序必须等待堆栈事件 zps_EVENT_NWK_ROUTE_DISCOVERY_CONFIRM(成功或失败),然后再尝试通过再次调用相同的单播函数来重新发送消息。
来自休眠节点的单播
为了允许如上所述接收单播确认,源节点必须在等于超时周期的时间内保持清醒。在休眠的电池供电节点上,从节能的角度来看,使用确认和重试可能是不可取的。在这种情况下,不应使用确认,但应用程序通过定期尝试读取节点上的属性并等待响应来监视到远程节点的路由是一种很好的做法。如果在预定义的时间内未观察到响应,则应用程序应采取下面列出的操作之一,具体取决于源节点是终端设备还是路由器。
- 如果是终端设备,应用程序应通过使用函数 zps_vNwkSendNwkStatusCommand() 向父节点发送单播网络状态命令来通知父节点路由问题,状态为“无可用路由(0x00)”
- 如果是路由器,则应用程序应通过调用函数 zps_eAplZdoRouteRequest() 启动到目标节点的显式路由发现
对大型单播数据包进行分片
单播“带确认”函数 zps_eAplAfUnicastAckDataReq() 和 zps_eAplAfUnicastIeeeAckDataReq() 也允许发送大数据包,在传输过程中可能会被分成多个消息。
b、广播
广播是对所有网络节点的数据传输,尽管可以选择节点的子集。 以下目的地是可能的:
- 所有节点
- “空闲时接收器打开”的所有节点 - 这些包括协调器、路由器和非休眠终端设备
- 所有路由器和协调器
函数 zps_eAplAfBroadcastDataReq() 用于广播数据包。 可以指定节点上的特定目标端点(所有接收节点的端点编号相同)或所有端点。 在此函数调用之后,该数据包最多可被广播四次(此外,该数据包随后可能被每个中间路由节点重新广播最多四次)。
c、组播
组播是一种数据传输,旨在选择网络节点,或者更具体地说,选择这些节点上的端点。 目标端点集必须预先组装成具有关联“组地址”的组。
函数 zps_eAplAfGroupDataReq() 用于向具有给定组地址的端点组发送数据包。 在实践中,数据包被广播到网络中的所有节点,每个接收节点有责任确定它是否在目标组中具有端点(因此是否对数据包感兴趣)。
d、绑定传输
一个数据包可以从一个端点发送到所有源端点先前绑定的远程端点。函数 zps_eAplAfBoundDataReq() 用于实现这种类型的数据传输。此方法提供了组播的替代方法,用于将数据发送到选定的端点。
提供了一个等效于上述函数的函数,它也请求来自目的地的“端到端”确认 - zps_eAplAfBoundAckDataReq()。如果在初始请求的大约 1600 毫秒内未收到确认,则重新发送数据,在完全放弃数据传输之前最多再进行 3 次重试。
zps_eAplAfBoundAckDataReq() 还允许发送大数据包,在传输过程中可能需要将其分成多个消息。
在调用上述绑定传输函数之一之后,发送节点上会生成一个延迟的 zps_EVENT_BIND_REQUEST_SERVER 事件。该事件总结了传输的状态,包括传输失败的绑定端点的数量.该事件仅在从“下一跳”节点接收到 MAC 级确认后生成,或者,如果请求,在从目标节点接收到端到端确认后生成。
注意:在绑定传输的情况下,“下一跳”zps_EVENT_APS_DATA_CONFIRM 事件和“端到端”zps_EVENT_APS_DATA_ACK 事件被消耗并且不会到达应用程序。
e、PAN 间传输
数据包可以发送到其他 IEEE 802.15.4 网络中的节点 - 这称为 PAN 间传输或传输。通常,此机制可用于向不属于本地网络的可选低成本设备发送信息。请注意,不能对 PAN 间传输应用安全性(加密/解密),并且设备上只有一个应用程序可以执行 PAN 间传输。 PAN 间消息不会被转发,因此只会被发射机直接无线电范围内的节点接收。
PAN 间功能通过 ZPS 配置编辑器启用。在设备的高级属性的 APS 层配置部分中,Inter PAN 值设置为 true。
函数 zps_eAplAfInterPanDataReq() 用于请求跨 PAN 传输。此功能需要传输到指定的目的地:
- 特定网络中的单个目标节点(必须指定 PAN ID 和节点地址)
- 特定网络中的多个目标节点(必须指定节点的 PAN ID 和组地址)
- 特定网络中的所有节点(必须指定PAN ID和0xFFFF的广播地址)
- 所有可达网络中的所有节点(必须指定广播PAN ID和广播地址,均为0xFFFF)
成功发送数据包后,堆栈将生成事件 zps_EVENT_APS_INTERPAN_DATA_CONFIRM(对于单个目的地,一旦收到“下一跳”确认,就会生成此事件)。
未为此类数据传输指定目标端点,但必须为目标指定集群。在接收到数据包时,接收节点会自动将数据包传递给支持给定集群的端点。
② 接收数据
当目的节点收到一个数据包时,它被放入消息队列中。 zps_EVENT_AF_DATA_INDICATION 堆栈事件在目的节点上生成,以指示数据包已到达(目的端点在此事件中指示)。然后必须使用函数 ZQ_bZQueueReceive() 从消息队列中收集数据包。
注 1:在通过跨 PAN 传输从另一个网络接收到数据包的情况下,将生成 zps_EVENT_APS_INTERPAN_DATA_INDICATION 堆栈事件。数据包将被传递到支持指定集群的端点。应用程序必须始终处理这些 PAN 间数据包并释放 APDU 实例(见下文)。仅当通过 ZPS 配置编辑器启用了跨 PAN 功能时,才会生成该事件。如果应用程序传输 PAN 间消息但不需要接收它们,则应用程序必须在 ZPS 配置编辑器中启用 PAN 间消息并通过释放 APDU 实例来处理任何 zps_EVENT_APS_INTERPAN_DATA_INDICATION 事件。
注 2:在发往 ZDO 的响应数据包到达的情况下,将生成一个 zps_EVENT_AF_DATA_INDICATION 堆栈事件,目标端点为 0。应用程序需要调用函数 zps_bAplZdpUnpackResponse() 来提取来自事件的响应数据。
处于休眠状态的终端设备将无法直接接收数据包,因此数据由其父设备缓存以备后用。一旦唤醒,终端设备必须明确请求此数据。这种接收数据的方法称为数据轮询。
一旦从消息队列中收集到数据包,就可以使用 PDUM 函数 PDUM_u16APduInstanceReadNBO() 从 APDU 实例中提取数据。然后必须使用 PDUM 函数 PDUM_eAPduFreeAPduInstance() 释放 APDU 实例。
③ 轮询数据
对于能够休眠的终端设备,消息不会直接传送到设备,因为当消息到达时它可能处于休眠状态。相反,消息由终端设备的父级临时缓冲。一旦唤醒,终端设备就可以向其父设备询问或“轮询”数据。
注:未启用睡眠的终端设备可以直接接收消息,因此不需要轮询。终端设备通过 ZPS 配置编辑器中的终端设备参数睡眠预配置为睡眠或非睡眠。
使用终端设备应用程序中的函数 zps_eAplZdoPoll() 执行数据轮询。此函数请求缓冲的数据,通常应在从睡眠中唤醒后立即调用。如果轮询请求成功发送到父级,则终端设备上将发生 zps_EVENT_NWK_POLL_CONFIRM 堆栈事件。来自父级的数据的后续到达由堆栈事件 zps_EVENT_AF_DATA_INDICATION 指示。然后应该使用函数 ZQ_bZQueueReceive() 从相关消息队列中收集从父转发的任何消息,就像第 5.5.2 节中描述的正常数据接收一样。
④ 数据传输的安全性
用于单播、广播、组播和绑定传输的“发送数据”功能包含一个参数,用于选择保护已发送消息所需的安全设置。 在 NXP ZigBee PRO 软件中,目前有三个安全选项,如下:
- 没有安全
- 网络级安全
- 应用级安全
应用级安全仅适用于单播和绑定传输,而网络级安全适用于除 PAN 间传输之外的所有传输类型。
注 1:PAN 间传输(到其他网络)没有安全性可用。
注 2:当应用级安全用于发送数据时,目标节点的 IEEE/MAC 地址和网络地址必须可通过本地地址映射表获得。
6、离开和重新加入网络
本节描述节点如何离开网络,然后重新加入同一网络或不同网络。
① 离开网络
一个节点可能有意或无意地离开网络:
- 节点可能会有意(和临时)从网络中移除以进行维护工作,例如更换电池。
- 由于不可预见的情况,节点可能会无意中离开网络,例如与其父节点的无线电链路断开(可能在信号路径中引入了障碍物)。
可以使用发出离开请求的函数 zps_eAplZdoLeaveNetwork() 有意地从网络中删除节点。目标节点可以是请求节点本身或请求节点的子节点。应用程序可以设计为在请求节点上按下按钮时调用此函数。
调用 zps_eAplZdoLeaveNetwork() 时:
- 可以指定是否也应请求离开节点的子节点离开网络。如果是这种情况,离开节点将首先为其每个子节点自动调用 zps_eAplZdoLeaveNetwork()。
- 可以指定离开节点是否应在离开后立即尝试重新加入同一网络。
堆栈事件 zps_EVENT_NWK_LEAVE_INDICATION 在请求离开的节点上生成(当相邻节点离开网络时也会生成此事件)。一旦由于调用 zps_eAplZdoLeaveNetwork() 成功地将节点从网络中删除,在请求节点上生成堆栈事件 zps_EVENT_NWK_LEAVE_CONFIRM。
还提供了 zps_eAplZdpMgmtLeaveRequest() 函数,可用于请求远程节点离开网络。
默认情况下,路由器将始终对请假请求消息执行操作。然而,为了防止恶意节点破坏网络,路由器可能需要忽略离开请求消息。如果调用函数 zps_vNwkNibSetLeaveAllowed() 时 bLeave 参数为 FALSE,则路由器将忽略网络离开请求。终端设备总是响应来自其父节点的离开请求而忽略来自其他节点的离开请求。
或者,可以定义在收到请假请求时调用的回调函数,其中该函数确定是否要遵守请假请求 - 该决定可能取决于请假请求的来源。回调函数使用 zps_eAplZdoRegisterZdoLeaveActionCallback() 注册。
② 重新加入网络
一个节点可能会离开它的网络——例如,通过:
- 失去与其父节点的无线电联系 - “孤立”节点上的堆栈将检测到此丢失并自动尝试重新加入网络
- 调用 zps_eAplZdoLeaveNetwork() - 如果在函数调用中请求立即重新加入,节点将自动尝试重新加入网络(尽管可以将节点配置为在离开后始终重新加入网络,使用函数 zps_vNwkNibSetLeaveRejoin())
如果节点成功重新加入网络,则在父节点上生成堆栈事件 zps_EVENT_NWK_NEW_NODE_HAS_JOINED,并在加入的节点上生成以下堆栈事件之一:
- zps_EVENT_NWK_JOINED_AS_ROUTER(如果作为路由器加入)
- zps_EVENT_NWK_JOINED_AS_ENDDEVICE(如果作为终端设备加入)
这些事件包含父节点分配给加入节点的网络地址(这可能与节点先前拥有的网络地址不同)。
如果加入请求不成功,则在请求节点上生成 zps_EVENT_NWK_FAILED_TO_JOIN 事件。
如果自动重新加入失败或未被请求,则可以使用函数 zps_eAplZdoRejoinNetwork() 来请求重新加入(必须在需要重新加入的节点上调用该函数)。应用程序可以设计为在节点上按下按钮时调用此函数。此函数调用的结果将通过上述事件指示。
还提供了函数 zps_eAplZdpMgmtDirectJoinRequest(),它向远程父节点提交请求以允许特定节点加入它。此外,还提供了 zps_eAplZdpMgmtPermitJoiningRequest() 函数,它允许在远程节点上启用/禁用加入。
注 1:当设备重新加入网络时,潜在父设备上的“允许加入”状态将被忽略。
注 2:当设备加入网络时,其应用程序可能会调用 zps_eAplZdpDeviceAnnceRequest() 向网络的其余部分通告设备的成员身份和网络地址。该信息在 Device_annce 公告中发送,必须由接收节点使用函数 ZQ_bZQueueReceive() 收集。
注意:如果节点重新加入同一个安全网络,但在重新加入之前其堆栈上下文数据已被清除(通过调用 PDM_vDelete()),则该节点发送的数据将被目标节点拒绝,因为已在源上重置帧计数器节点。因此,不建议您在重新加入之前清除堆栈上下文数据。
7、返回码和扩展错误处理
调用 ZigBee PRO API 函数时,通常会在函数完成时返回代码以指示结果。此代码取自以下之一:
- zps_E_SUCCESS
- APS 返回代码
- NWK 返回代码
- MAC 返回码
可以选择性地实现扩展的错误处理机制,该机制允许获取有关在函数执行期间可能发生的某些错误的更多详细信息。具体错误如下:
- 0xA3:zps_APL_APS_E_ILLEGAL_REQUEST
- 0xA6:zps_APL_APS_E_INVALID_PARAMETER
- 0xC2:zps_NWK_ENUM_INVALID_REQUEST
为了实现扩展的错误处理机制,必须使用函数 zps_vExtendedStatusSetCallback() 注册一个回调函数。在调用需要扩展错误处理的第一个 API 函数之前,必须调用此注册函数。如果发生上述错误之一,则将在 API 函数执行期间调用注册的回调函数。回调函数将返回扩展错误代码,但 API 函数将仅返回基本错误代码。
8、实施 ZigBee 安全性
NXP ZigBee PRO API 允许实施 ZigBee 安全性,将基于密钥的加密应用于网络节点之间的通信。 在 NWK 层和更高层生成的消息帧内容使用基于 128 位 AES 的加密进行加密。 帧的 NWK 负载经过加密,NWK 标头和负载使用 32 位消息完整性代码 (MIC) 进行完整性保护。
本节描述具有集中安全性的网络中的安全性,该网络由单个信任中心(通常是协调器节点)管理。 也可以使用分布式安全方案。
① 安全级别
在 ZigBee 网络中可以应用两种类型或级别的安全性:
- 网络级安全性:这使用在整个网络中通用的“网络密钥”,用于加密/解密所有节点之间的所有通信。 网络密钥在任何节点加入网络之前由信任中心随机生成。
- 应用程序级安全性:这使用应用程序“链接密钥”(除了网络密钥之外)用于加密/解密一对节点之间的通信。 该链接密钥对于一对节点可能是唯一的。
② 安全密钥类型
当节点加入网络时,信任中心必须将网络密钥传递给加入节点,以便该节点可以参与与现有网络节点的网络级加密通信。当网络密钥传递给加入节点时,它本身必须受到加密保护。对于这种加密,使用了信任中心和加入节点都知道的预先配置的链接密钥。这可以是全局链接键或唯一链接键:
- 预配置的全局链接密钥:该链接密钥对于网络中的所有节点都是相同的。它可能是 ZigBee 定义的密钥或制造商定义的:
- ZigBee 定义的密钥(称为 ZigBee“09”密钥)将允许来自不同制造商的节点加入网络。
- 制造商定义的密钥将只允许来自特定制造商的节点加入网络。
- 预配置的唯一链接密钥:此链接密钥是信任中心和加入节点的专有密钥。在这种情况下,每个节点都有不同的链接键。
预配置的链接密钥必须在工厂或调试期间预编程到相关节点中。
活动网络密钥随后可以随时更改。
一旦设置了网络级安全性,就可以设置应用程序级安全性以实现更安全的通信——这种安全性级别应用在网络级安全性之上。如果两个节点之间需要应用级安全性,则必须为节点建立链接密钥。此密钥可以是以下任何一项:
- 预配置的全局链接密钥(如上详述):用于信任中心和所有其他节点之间的通信
- 预配置的唯一链接密钥(如上所述):这是用于信任中心和另一个节点之间的通信
- 信任中心链接密钥 (TCLK):这是用于信任中心和另一个节点之间的通信。它由信任中心随机生成并传递给相关节点,使用网络密钥对其进行加密,如果存在,则使用该节点预先配置的唯一链接密钥。然后,TCLK 将用于加密与信任中心的所有后续通信,替换任何预配置的链接密钥(应用程序应保留预配置的密钥,以防将来需要恢复,例如重新-加入)。
- 应用程序链接密钥:这是用于不包括信任中心的一对节点之间的通信。它是由两个节点之一从信任中心请求的。信任中心随机生成密钥并将其与两个节点的 IEEE/MAC 地址相关联。信任中心将密钥传递给每个节点,并使用网络密钥以及为节点预先配置的唯一链接密钥(如果存在)对其进行加密。
ZigBee 安全密钥摘要
安全密钥 | 说明 | |
---|---|---|
网络级安全 | ||
网络密钥 | • 用于加密网络所有节点之间通信的基本密钥 • 由信任中心随机生成 • 分发给加入节点,使用预先配置的链接密钥加密(见下文) | |
应用级安全 | ||
全局链接密钥(预配置) | • 在信任中心和所有其他节点之间使用 • 在所有节点中预先配置(除非预先配置了唯一的链接密钥 - 见下文) • 也用于加入加密从信任中心传输到加入节点的网络密钥 • 如果 ZigBee 定义,则允许所有制造商的节点加入网络 • 如果制造商定义,则只允许来自一个制造商的节点加入网络 • Touchlink 预配置链接密钥是此类密钥 • 分布式安全全局链接密钥是这种类型的密钥 | |
唯一链接密钥 | 用于加密一对节点之间通信的可选密钥 - 可能是以下之一: | |
预配置的唯一链接密钥 | • 在信任中心和另一个节点之间使用 • 在信任中心和相关节点中预先配置 • 也用于加入加密从信任中心传输到加入节点的网络密钥 • 安装代码衍生的预配置链接密钥是此类密钥 | |
信任中心链接密钥 (TCLK) | • 在信任中心和另一个节点之间使用 • 由信任中心随机生成 • 分发给使用网络密钥和预配置链接密钥(如果有)加密的节点 • 替换预配置的链接密钥(如果有),但应用程序必须保留预配置的密钥,以防需要恢复 | |
应用链接键 | • 在一对节点之间使用,不包括信任中心 • 由信任中心随机生成 • 分发给使用网络密钥和预配置链接密钥(如果有)加密的每个节点 |
注 1:节点的预配置唯一链接密钥可以使用 zps_eAplZdoAddReplaceInstallCodes() 函数从信任中心上的安装代码派生。 ZigBee 3.0 设备用户指南 (JN-UG-3114) 中描述了安装代码。
注 2:为了在使用 ZigBee 基础设备的 ZigBee 3.0 应用程序中使用预配置的链接密钥,必须启用基础设备属性 bbdbJoinUsesInstallCodeKey 并将其设置为 TRUE - 有关更多信息,请参阅 ZigBee 3.0 设备用户指南 (JN-UG-3114)。
③ 设置 ZigBee 安全性
本节介绍如何在应用程序代码中设置 ZigBee 安全性。请注意,如果在 ZigBee 网络中启用安全性,则始终使用网络级安全性,而应用程序级安全性是可选的。
通过 ZPS 配置编辑器中的设备参数 Security Enabled 在节点上启用安全性。启用安全性还可以实现到信任中心的多对一路由,信任中心成为网络集中器。
必须使用 ZPS 配置编辑器指定信任中心。协调员通常被选为信托中心。必须使用 ZPS 配置编辑器中的网络参数路由记录表大小(默认数量为 4)在指定节点上设置需要信任中心服务的最大节点数。
可以使用函数 zps_vAplSecSetInitialSecurityState() 在应用程序代码中设置安全性,该函数必须在 zps_eAplAfInit() 和 zps_eAplZdoStartStack() 之前调用。
注:作为在应用程序代码中使用函数 zps_vAplSecSetInitialSecurityState() 的替代方法,可以在 ZPS 配置编辑器中设置 ZigBee 安全性。
一旦 zps_vAplSecSetInitialSecurityState() 被调用并且堆栈已经启动,堆栈将自动管理随后的网络级安全设置和实现。
注:可以使用 zps_vSetTCLockDownOverride() 函数禁用信任中心上的某些功能。
a、网络级安全设置
上面描述的函数 zps_vAplSecSetInitialSecurityState() 启动网络级安全的设置过程,并要求将初始安全密钥的类型指定为以下之一:
- 预配置的全局链接密钥
- 预配置的唯一链接密钥
它们用于在网络密钥传输到加入节点时对其进行加密。
信任中心和其他节点必须使用相关的预配置链接密钥进行预编程。此密钥可以在节点的应用程序代码中指定并由 zps_vAplSecSetInitialSecurityState() 引用,也可以通过信任中心和其他节点上的 ZPS 配置编辑器中的密钥描述符参数 Key 进行设置。在唯一链接密钥的情况下,节点的 IEEE/MAC 地址也必须与链接密钥一起预编程到信任中心。
注:通过 ZPS 配置编辑器输入的预配置链接密钥保存在信任中心的密钥描述符表中,每个节点/密钥都有一个条目。可以使用函数 zps_psGetActiveKey() 从该表中(本地)获取具有给定 IEEE/MAC 地址的节点的密钥。
信任中心生成一个随机网络密钥,用于所有节点之间的网络级通信。当新节点加入网络时,信任中心将使用适当的预配置链接密钥加密的网络密钥传输到新加入的节点。
注 1:信任中心上的应用程序可以通过用户定义的回调函数(从堆栈中)控制是否允许节点加入网络(可能使用其预配置的链接密钥)。如果需要,必须使用函数 zps_vTCSetCallback() 注册此回调函数。
注 2:当设备加入 ZigBee 网络并需要涉及向其传输网络密钥的身份验证时,父设备会打开一个身份验证间隔,在此期间加入设备必须向网络宣布自己。此间隔从重新加入响应(如果设备通过 NWK 层重新加入)或关联响应(如果它通过 IEEE 802.15.4 关联加入)的传输开始。如果设备未能在此时间间隔内宣布自己,则父设备会删除加入设备的邻居表条目,以确保保持父设备的子容量。必须通过网络参数 APS Security Timeout Period(在所有潜在父节点上设置此身份验证间隔,默认情况下为 1 秒,但 6 秒是更合理的设置。
b、应用程序级安全设置
一旦设置了网络级安全性,就可以根据需要设置应用程序级安全性。在应用程序级安全中,两个节点之间的通信使用可能是全局或唯一的链接密钥进行加密/解密:
- 全局链接密钥:这在网络上的所有节点之间共享,并在所有节点中预先配置。使用全局链接密钥时,不会检查帧计数器的新鲜度。
- 唯一链接密钥:这是一对需要私下通信的节点专有的。它可以是预先配置的唯一链接密钥、信任中心链接密钥 (TCLK) 或应用程序链接密钥。检查帧计数器的新鲜度以防止恶意节点重放陈旧的消息。这提供了最安全的应用程序安全方法。
为了使用两个节点之间的唯一链接密钥设置应用程序级安全性,必须在其中一个节点上调用函数 zps_eAplZdoRequestKeyReq() 以从信任中心请求链接密钥。有两种可能:
- 为本地节点和信任中心之间的通信请求信任中心链接密钥 (TCLK) - 信任中心将使用请求的链接密钥进行响应
- 要请求应用程序链接密钥与不是信任中心的另一个节点通信(在这种情况下,必须在函数调用中提供另一个节点的 IEEE/MAC 地址) - 信任中心会将请求的链接密钥发送到两个节点
如果不允许节点发送 APS 安全数据,则信任中心将忽略该请求。信任中心响应加密如下:
- 如果存在用于信任中心和目标节点之间通信的链接密钥(例如预先配置的链接密钥),则该密钥和网络密钥都用于加密请求的链接密钥。
- 否则,仅使用网络密钥来加密请求的链接密钥。
收到链接密钥后,节点上的 ZigBee 堆栈将自动保存该密钥。生成事件 zps_EVENT_ZDO_LINK_KEY 以指示链接密钥可用。这两个节点之间的任何后续单播或绑定数据传输都可以选择使用此密钥 (zps_E_APL_AF_SECURE_APL)。
注:应用程序可以使用函数 zps_eAplZdoAddReplaceLinkKey() 直接引入应用程序链接密钥。
注 1:当使用链路密钥对数据包进行加密时,在应用层使用链路密钥对数据包有效载荷进行加密,然后在 ZigBee 堆栈 NWK 层使用网络密钥对数据包进行加密(因此,两个密钥都是用过的)。
注 2:当应用级安全用于发送数据时,目标节点的 IEEE/MAC 地址和网络地址必须可通过本地地址映射表获得。
④ 安全密钥修改
网络密钥和应用程序链接密钥可以在网络运行时更改,如下所述。
a、网络密钥修改
可以在一个节点上存储多个网络密钥,尽管在任何时候只能激活一个密钥。 每个网络密钥都通过信任中心应用程序分配的唯一“密钥序列号”进行标识。
可以通过以下两种方式之一在节点中安装新的网络密钥:
- 由信任中心使用函数 zps_eAplZdoTransportNwkKey() 分发到网络的一个或多个节点,该函数需要指定关联的密钥序列号
- 通过在需要网络密钥的节点上调用函数 zps_eAplZdoRequestKeyReq() 从信任中心请求
到达目的地后,传送的钥匙会自动保存但不会激活。 使用函数 zps_eAplZdoSwitchKeyReq() 可以采用存储的网络密钥作为活动密钥,该函数在信任中心调用并通过其唯一序列号识别所需的密钥。
b、应用链接密钥修改
应用程序可以使用 zps_eAplZdoAddReplaceLinkKey() 引入或替换应用程序链接密钥。 如果同一个节点对的链接密钥已经存在,它将被新的链接密钥替换。 必须在对中的两个节点上调用该函数。
9、使用支持软件功能
本节介绍某些支持软件功能以及如何将它们包含在应用程序代码中:
- 消息队列
- 软件定时器
① 消息队列
节点上应用程序任务之间的通信是通过消息队列实现的。 应用程序可以为特定的通信通道创建专用的消息队列。 提供了一组函数来实现消息队列。 堆栈需要某些标准队列。
注意:要允许 JN516x/7x 设备进入睡眠模式,消息队列不得包含任何消息。 必须首先清空所有消息队列。
a、常规队列管理
可以使用函数 ZQ_vZQueueCreate() 创建队列。 此函数允许指定队列大小(它可以容纳的消息数)和消息的大小。 队列被赋予一个唯一的句柄,它是一个指向包含有关队列的最新信息的 tszQueue 结构的指针。
可以使用函数 ZQ_bZQueueSend() 将消息放入(创建的)队列中,使用函数 ZQ_bZQueueReceive() 从队列中检索消息。 这在下面的图中进行了说明。
当调用上述两个函数时,队列的 tszQueue 结构会自动更新以反映队列的新状态。 检索消息会导致该消息从队列中删除。
应用程序必须定期轮询希望通过其接收消息的消息队列。 它可以通过定期调用 ZQ_bQueueIsEmpty() 函数来完成此操作,该函数检查队列是否为空。 如果队列不为空,它应该调用 ZQ_bZQueueReceive() 直到队列中没有更多消息。 可以使用函数 ZQ_u32QueueGetQueueMessageWaiting() 获取当前等待从队列中收集的消息数。
b、标准堆栈队列
应用程序必须创建三个标准队列以供堆栈使用:
- 带有句柄 zps_msgMlmeDcfmInd 的队列以接收来自其他节点的 IEEE 802.15.4 MAC 命令数据包
- 带有句柄 zps_msgMcpsDcfmInd 的队列以接收来自其他节点的 IEEE 802.15.4 MAC 数据包
- 带有句柄 zps_TimeEvents 的队列以接收内部软件计时器事件(例如计时器到期事件)
下面提供了创建这些队列的示例代码:
ZQ_vZQueueCreate(&zps_msgMlmeDcfmInd, MLME_QUEUE_SIZE, sizeof(MAC_tsMlmeVsDcfmInd),(uint8*)asMacMlmeVsDcfmInd);
ZQ_vZQueueCreate(&zps_msgMcpsDcfmInd, MCPS_QUEUE_SIZE, sizeof(MAC_tsMcpsVsDcfmInd),(uint8*)asMacMcpsDcfmInd);
ZQ_vQueueCreate(&zps_TimeEvents,TIMER_QUEUE_SIZE,sizeof(zps_tsTimeEvent),(uint8*)asTimeEvent);
只需将上述代码包含在应用程序中。 不需要在代码中处理这些队列。
② 软件定时器
ZigBee 3.0 SDK 提供的资源允许应用程序在本地节点上实现软件定时器并与之交互。 多个软件定时器可以同时使用,它们都来自同一个源计数器,即 JN516x/7x 滴答定时器。
注意:要允许 JN516x/7x 器件进入睡眠模式,不应激活任何软件定时器。 任何正在运行的软件计时器必须首先停止,并且所有计时器必须关闭。
a、设置定时器
要在应用程序代码中设置软件定时器,您必须:
- 声明一个 ZTIMER_tsTimer 结构数组,其中每个元素/结构包含有关一个计时器的信息
- 在应用程序的 while 循环中调用函数 ZTIMER_vTask() - 这允许堆栈软件在计时器运行时自动更新每个计时器的结构
对于每个定时器,必须提供一个用户定义的回调函数,它是从定时器的结构中引用的。此回调函数 ZTIMER_tpfCallback() 在计时器到期(达到其计时周期)时调用,以执行应用程序因计时器到期而需要的任何操作。
在使用任何软件定时器之前,它们必须通过调用函数 ZTIMER_eInit() 共同初始化。此函数将定时器结构数组作为输入。
在使用单个计时器之前,必须使用函数 ZTIMER_eOpen() 打开它。同样,当不再需要计时器时,应使用函数 ZTIMER_eClose() 将其关闭。在这些函数中,定时器是通过定时器结构数组中的索引来指定的。
b、操作定时器
打开单个软件计时器后,它可以在关闭之前运行一次或多次。 可以通过调用函数 ZTIMER_eStart() 来运行计时器。 时间段必须以毫秒为单位指定。 在计时器到期时,将调用用户定义的回调函数 ZTIMER_tpfCallback() 以执行应用程序所需的任何操作。
可以通过调用函数 ZTIMER_eStop() 在运行的计时器到期之前停止它。
可以随时使用函数 ZTIMER_eGetState() 获取单个计时器的状态。 可能的报告状态为正在运行、已停止、已过期和已关闭。
③ 临界区和互斥 (Mutex)
ZigBee 3.0 堆栈软件提供了防止应用代码部分被抢占和/或重新输入的功能。例如,当应用程序将数据写入内存时,可能不希望此操作被中断并且中断服务例程开始写入同一内存块。
提供了两个功能来保护应用程序代码部分:
- 临界区:应用程序代码的一段可以指定为“临界区”,这意味着该代码段的执行不能被优先级小于 12 的中断抢占。临界区应该是短的避免长时间暂停中断。
- 互斥(Mutex):一段代码最好不要重入。 “互斥锁”可以与代码段相关联,以防止在该段的当前执行完成之前再次输入它。
这些功能在下面的小节中有更详细的描述。
a、实现临界区
应用程序代码的关键部分的执行不能被优先级小于 12 的中断抢占(更高优先级的中断总是可以抢占关键部分)。 下面的图对此进行了说明,该图显示了主应用程序线程和中断服务例程 (ISR) 之间的相互作用。
代码的关键部分必须由以下两个函数分隔:
- zps_eEnterCriticalSection() 必须在临界区开始时调用。
- zps_eExitCriticalSection() 必须在临界区结束时调用。
互斥锁也可以选择性地与临界区相关联,以保护该部分免于重入。如果需要,可以在 zps_eEnterCriticalSection() 的参数中指定互斥锁。
要实现临界区,应用程序必须维护一个“优先级”值 u8Level,其中包含主应用程序线程的当前优先级(当临界区未执行时)。当进入临界区时,主线程的优先级会增加,这样优先级小于等于 11 的中断就无法抢占主线程。在临界区结束时,主线程的优先级返回到进入临界区之前 u8Level 中包含的值。
b、实现互斥
互斥体可以与应用程序代码的一部分相关联,以防止在该部分的当前执行完成之前重新进入该部分。将应用互斥锁的代码部分必须由以下两个函数分隔:
- zps_u8GrabMutexLock() 必须在代码部分的开头调用。
- zps_u8ReleaseMutexLock() 必须在代码部分的末尾调用。
也可以将互斥锁应用到临界区。应用互斥锁时,必须提供指向用户定义的互斥锁函数的指针,其原型如下:
((bool_t*) (*) (void))
此函数必须定义并维护一个布尔标志,指示相应的互斥锁是活动 (TRUE) 还是非活动 (FALSE)。 API 函数使用此标志来确定指定的互斥锁是否可用。如果此标志在相关代码部分的开头读为 FALSE,则应用互斥锁,并且上述互斥锁函数必须将该标志设置为 TRUE,但如果该标志已经为 TRUE,则无法应用互斥锁(并且 API 函数返回失败)。
要实现互斥保护,应用程序必须维护一个“优先级”值 u8Level,其中包含主应用程序线程的当前优先级(当互斥保护部分没有被执行时)。当应用互斥锁时,主线程的优先级会增加,这样优先级为 11 或更低的中断无法抢占主线程。当互斥锁被释放时,主线程的优先级将返回到应用互斥锁之前包含在 u8Level 中的值。
10、高级功能
本节介绍了 ZigBee 3.0 中引入的高级 ZigBee 功能的实现。
① 终端设备老化
作为父节点的路由器需要维护其邻居表,这涉及丢弃不活动的子节点(可能已经离开网络)以便为潜在的新子节点让路。 终端设备老化机制可用于支持此维护。
在这种机制中,超时应用于路由器的邻居表中的每个子条目。 如果在超时到期之前没有从终端设备子节点接收到称为“保持活动”的数据包,则假定子节点不再处于活动状态并从表中删除(因此从路由器的子节点中删除)。
a、超时期限
超时期限特定于单个子进程,并使用函数 zps_bAplAfSetEndDeviceTimeout() 在终端设备上设置。当终端设备加入(或重新加入)网络时,该时间段通过终端设备超时请求传达给父设备。超时由路由器应用于终端设备的邻居表条目。来自终端设备的保活数据包的到达将导致超时从头重新开始。如果允许超时到期(没有保持活动的数据包),路由器将从邻居表中删除相关的子条目。
注 1:路由器最初将所有终端设备子设备的超时设置为 NIB 中定义的默认值,在 NXP 软件中为 256 分钟。超时将保持在此值,除非终端设备更改,如上所述。
注2:Parent 收到End Device Timeout Request 后,会向End Device 发送End Device Timeout Response,表示请求的结果。如果请求成功,终端设备可以随后发送保活数据包。
b、保持活动数据包
可以使用函数 zps_eAplAfSendKeepAlive() 从终端设备发送保持活动数据包。建议在为终端设备定义的超时期限内至少调用此函数 3 次,以防止子设备因父设备丢失保持活动数据包而意外从网络中删除。
保持活动数据包可以是以下类型之一:
- MAC 数据轮询:在这种情况下,父设备可能会将挂起的数据发送回终端设备。此数据到达终端设备将由 zps_EVENT_AF_DATA_INDICATION 事件指示。
- 终端设备超时请求:这种数据包类型只是在父级上重新启动终端设备的超时,它将向终端设备返回终端设备超时响应,指示请求的结果。
要使用的保持活动数据包类型由路由器父级确定,并在父级上的 NIB 中配置 - 在 NXP 软件中,默认情况下,路由器被配置为接受任一数据包类型。该信息在初始终端设备超时响应中传达给终端设备,该响应在加入网络时发送到终端设备。 zps_eAplAfSendKeepAlive() 函数然后将自动发送适当的保持活动的数据包类型 - 当父节点接受任一数据包类型时,该函数会发送一个数据轮询数据包。
② 分布式安全网络
在传统的 ZigBee 网络中,安全由信任中心实现,它通常是协调器 - 这使用集中式安全方案。在分布式安全网络中,任何路由器节点都可以管理安全,因此安全管理分布在整个网络中。分布式安全网络没有协调器/信任中心,仅由路由器和终端设备组成——任何路由器都可以创建网络。
在分布式安全网络中,只能实现网络级别的安全。网络密钥由创建网络的路由器生成,并随着网络的增长传递给其他节点,包括其他路由器。在此分发过程中,网络密钥使用“分布式安全全局链接密钥”进行加密,这是一种预先配置的全局链接密钥。
可以使用函数 zps_eAplFormDistributedNetworkRouter() 在路由器节点上启动分布式安全网络。启动参数通过 zps_tsAftsStartParamsDistributed 结构指定。这些参数包括:
- PAN ID
- 扩展 PAN ID (EPID)
- 广播频道
- 指向接收网络密钥的位置的指针
网络的第一个节点将生成网络密钥(保存到上述位置)并将此密钥传递给加入它的节点。
函数 zps_eAplFormDistributedNetworkRouter() 也可以在其他路由器节点上调用以将它们加入网络。可以使用函数 zps_eAplInitEndDeviceDistributed() 将终端设备加入分布式网络。但是,这些节点更有可能通过其他调试方法引入网络,例如 Touchlink 和 NFC 调试。
③ 根据 LQI 值 / 链路成本过滤数据包
本节介绍基于 LQI 值(检测到的信号强度)过滤接收数据包的操作和配置。 数据包过滤会导致一些接收到的 LQI 值较低的数据包被丢弃。
在实践中,测量的数据包 LQI 值被转换为用于过滤的“链路成本”值。
数据包过滤是可选的,在以下情况下可能有益:
- 网络加入
- 路由发现
- 正常网络运行
可以使用函数 zps_vAplAfEnableMcpsFilter() 启用数据包过滤。
a、链接成本
出于数据包过滤的目的,LQI 值被转换为“链路成本”值。 因此,一系列 LQI 值映射到单个链路成本,这是一个整数值。 ZigBee PRO 堆栈实现的默认映射如下表所示。
LQI 范围 | 链接成本 |
---|---|
≥ 51 | 1 |
46 ⎯ 50 | 2 |
41 ⎯ 45 | 3 |
39 ⎯ 40 | 4 |
36 ⎯ 38 | 5 |
25 ⎯ 35 | 6 |
≤ 24 | 7 |
可以修改上述映射。NXP ZigBee PRO 堆栈使用链路成本 5 作为数据包过滤阈值。 因此,链路成本大于 5 的数据包可能会被丢弃。 对于 JN516x/7x 设备,这个阈值比 ZigBee 规范中提出的值 3 更合适。 但是,阈值是可配置的。
b、运行中的数据包过滤
数据包过滤是由 IEEE 802.15.4 MAC 层应用的 ZigBee PRO 堆栈的可选功能。 在网络加入、路由发现和正常网络操作期间,优化接收数据包的处理非常有用。
入网
在网络加入期间,对网络发现阶段的结果应用一种包过滤形式。任何已发现的潜在父节点都将被过滤,从而丢弃链接成本大于 5(低 LQI 值)的节点。此功能有助于形成邻居之间具有强链接的网络,并且在密集网络中最有效。有关加入网络期间此过程的更多信息,请参阅 ZigBee 规范。
路由发现和正常网络运行
在大型网络中,路由发现和正常运行期间的流量级别都很高,并且一个节点可能会收到许多数据包。然而,节点上的存储容量有限,无法保存这些数据包,直到它们可以被处理。为了限制提交到接收队列的接收数据包的数量,应用了以下过滤系统:
- 如果接收队列中有足够的可用空间,则所有单播数据包都会排队(不进行过滤)。
- 如果接收队列容量的至少 50% 空闲,则广播数据包将排队,否则将应用数据包过滤机制,并且只有链路成本为 5 或更少的数据包才会排队。
在路由发现期间,此过滤可防止关联 LQI 值较低的节点进入邻居表,从而建立可靠的路由。例如,与具有较差LQI值的单跳相比,可能更希望建立包括具有良好LQI值的多跳的路由。
c、包过滤配置
默认情况下禁用数据包过滤,但可以按如下所述启用和重新配置。
基本配置
函数 zps_vAplAfEnableMcpsFilter() 允许启用堆栈的包过滤并调整链路成本阈值(从默认值 5 开始)。 如果需要,可以在 zps_eAplAfInit() 之后随时调用它。
链路成本配置
LQI 值和链路成本之间的映射可以从默认映射中修改。 要修改映射,以下函数必须是用户定义的,它将 LQI 值(输入)转换为链路成本(输出):
uint8 APP_u8LinkCost(uint8 u8Lqi);
实现默认映射的示例函数如下所示:
PRIVATE uint8 APP_u8LinkCost (uint8 u8Lqi)
{
uint8 u8Lc;
if (u8Lqi > 50)
{
u8Lc = 1;以上是关于JN5169 NXP ZigBee PRO 无线网络应用所需的常见操作的主要内容,如果未能解决你的问题,请参考以下文章
JN5169 ZigBee 3.0 协议栈之 ZigBee 网络参数
JN5169 JN-AN-1217-Zigbee-3-0-Base-Device
在 BeyondStudio for NXP 使用 Gawk(for JN5169)
在 BeyondStudio for NXP 使用 Gawk(for JN5169)