NXP

【ZigBee】ZigBee3.0设备入网过程

2019-07-12 11:58发布

硬件平台:JN5169 SDK:JN-SW-4170 参考文档:ZigBee-Base-Device-Behavior-Specification.pdf 
概要:分析设备首次入门的流程(bdbNodeIsOnANetwork属性为FALSE),设备入网规范遵循ZigBee-Base-Device-Behavior-Specification 8.3小节

1  节点首先将bdbcommitoningstatus设置为IN_PROGRESS,将vDoPrimaryScan设置为TRUE,将vScanChannels设置为bdbPrimaryChannelSet

BDB_PRIMARY_CHANNEL_SET = 0x02108800; BDB_SECONDARY_CHANNEL_SET = 0x07FFF800 ^ 0x02108800; BDB_eNsStartNwkSteering(void) { //有省略 sBDB.sAttrib.ebdbCommissioningStatus = E_BDB_COMMISSIONING_STATUS_IN_PROGRESS; bDoPrimaryScan = TRUE; u32ScanChannels = sBDB.sAttrib.u32bdbPrimaryChannelSet; u8ScanChannel = BDB_CHANNEL_MIN; bAssociationJoin = FALSE; vNsDiscoverNwk(); } 进入vNsDiscoverNwk()函数后,跳到12步进行判断

2  节点应进行信道扫描,以发现其无线电范围内的一组信道上有哪些网络可用

void vNsDiscoverNwk() { //此函数有省略 eNS_State = E_NS_WAIT_DISCOVERY; //状态机状态,注意 ZPS_eAplZdoDiscoverNetworks(u32ScanChannels & (1<

ZPS_eAplZdoDiscoverNetworks()函数调用最终都会在终端设备或路由器上导致生成堆栈事件ZPS_EVENT_NWK_DISCOVERY_COMPLETE 

bdb_taskBDB(); BDB_vNsStateMachine(&sZpsAfEvent); case E_NS_WAIT_DISCOVERY: case ZPS_EVENT_NWK_DISCOVERY_COMPLETE: //有省略

3  如果NLME-NETWORK-DISCOVERY确认原语的状态参数不等于SUCCESS,表明通道扫描不成功,则节点从步骤2继续。

意思就是判断sStackEvent.uEvent.sNwkDiscoveryEvent.eStatus状态不等于MAC_ENUM_SUCCESS,继续执行下面函数: vNsDiscoverNwk();

4  节点通过分析NetworkCount和NetworkDescriptor参数,判断是否有设置为TRUE的permit join flag合适的网络。

eNS_State = E_NS_WAIT_JOIN; vNsTryNwkJoin(TRUE, &(psZpsAfEvent->sStackEvent.uEvent.sNwkDiscoveryEvent)); //以下位于vNsTryNwkJoin()函数,有无关代码省略 if( (pNwkDescr[u8NwkIndex].u8PermitJoining) && ( (0 == ZPS_psAplAibGetAib()->u64ApsUseExtendedPanid) || (pNwkDescr[u8NwkIndex].u64ExtPanId == ZPS_psAplAibGetAib()->u64ApsUseExtendedPanid) ) ){ eNS_State = E_NS_WAIT_JOIN; eStatus = ZPS_eAplZdoJoinNetwork(&pNwkDescr[u8NwkIndex]); }

5  如果在通道扫描中没有找到合适的网络,节点从步骤2继续

vNsTryNwkJoin(TRUE, &(psZpsAfEvent->sStackEvent.uEvent.sNwkDiscoveryEvent)); DBG_vPrintf(TRACE_BDB," BDB: No suitable network! Continue Discovery "); vNsDiscoverNwk();

6  节点应尝试加入使用MAC关联发现的网络

vNsTryNwkJoin(TRUE, &(psZpsAfEvent->sStackEvent.uEvent.sNwkDiscoveryEvent)); //以下位于vNsTryNwkJoin()函数,有无关代码省略 eNS_State = E_NS_WAIT_JOIN; eStatus = ZPS_eAplZdoJoinNetwork(&pNwkDescr[u8NwkIndex]);

7  允许再次尝试加入同一网络,但每次尝试次数不得超过bdbcmaxsamenetworkretrytrytries次数

vNsTryNwkJoin(TRUE, &(psZpsAfEvent->sStackEvent.uEvent.sNwkDiscoveryEvent)); //以下位于vNsTryNwkJoin()函数,有无关代码省略 if(u8RecSameNwkRetryAttempts < BDBC_MAX_SAME_NETWORK_RETRY_ATTEMPTS) { eNS_State = E_NS_WAIT_JOIN; eStatus = ZPS_eAplZdoJoinNetwork(&pNwkDescr[u8NwkIndex]); }

ZPS_eAplZdoJoinNetwork()函数返回堆栈事件

//以下代码有省略,请注意 bdb_taskBDB(); BDB_vNsStateMachine(&sZpsAfEvent); case E_NS_WAIT_JOIN: switch(psZpsAfEvent->sStackEvent.eType) { case ZPS_EVENT_NWK_FAILED_TO_JOIN: break; case ZPS_EVENT_NWK_JOINED_AS_ROUTER: case ZPS_EVENT_NWK_JOINED_AS_ENDDEVICE: break; }

8  如果是堆栈事件为ZPS_EVENT_NWK_FAILED_TO_JOIN,再次尝试同一网络

//以下代码有省略,请注意 bdb_taskBDB(); BDB_vNsStateMachine(&sZpsAfEvent); case E_NS_WAIT_JOIN: switch(psZpsAfEvent->sStackEvent.eType) { case ZPS_EVENT_NWK_FAILED_TO_JOIN: vNsTryNwkJoin(FALSE, NULL); break; }

9  如果是堆栈事件为ZPS_EVENT_NWK_JOINED_AS_ROUTER或者ZPS_EVENT_NWK_JOINED_AS_ENDDEVICE,应相应地设置bdbNodeJoinLinkKeyType,以指示用于解密接收到的网络密钥的链路密钥类型。

//以下代码有省略,请注意 bdb_taskBDB(); BDB_vNsStateMachine(&sZpsAfEvent); case E_NS_WAIT_JOIN: switch(psZpsAfEvent->sStackEvent.eType) { case ZPS_EVENT_NWK_FAILED_TO_JOIN: break; case ZPS_EVENT_NWK_JOINED_AS_ROUTER: case ZPS_EVENT_NWK_JOINED_AS_ENDDEVICE: psApsKeyDesc = ZPS_psGetActiveKey(ZPS_u64AplZdoLookupIeeeAddr(psZpsAfEvent->sStackEvent.uEvent.sNwkJoinedEvent.u16Addr), &u32Index); /*根据接收到的网络密钥的链路密钥类型,相应地设置bdbNodeJoinLinkKeyType*/ if(!memcmp(sBDB.pu8DefaultTCLinkKey, &psApsKeyDesc->au8LinkKey[0], ZPS_SEC_KEY_LENGTH)) { sBDB.sAttrib.u8bdbNodeJoinLinkKeyType = DEFAULT_GLOBAL_TRUST_CENTER_LINK_KEY; } else if(!memcmp(sBDB.pu8DistributedLinkKey, &psApsKeyDesc->au8LinkKey[0], ZPS_SEC_KEY_LENGTH)) { sBDB.sAttrib.u8bdbNodeJoinLinkKeyType = DISTRIBUTED_SECURITY_GLOBAL_LINK_KEY; } else if(!memcmp(sBDB.pu8TouchLinkKey, &psApsKeyDesc->au8LinkKey[0], ZPS_SEC_KEY_LENGTH)) { sBDB.sAttrib.u8bdbNodeJoinLinkKeyType = TOUCHLINK_PRECONFIGURED_LINK_KEY; } else if(!memcmp(sBDB.pu8PreConfgLinkKey, &psApsKeyDesc->au8LinkKey[0], ZPS_SEC_KEY_LENGTH)) { sBDB.sAttrib.u8bdbNodeJoinLinkKeyType = INSTALL_CODE_DERIVED_PRECONFIGURED_LINK_KEY; }

10  节点将bdbNodeIsOnANetwork设置为TRUE,然后广播Device_annce ZDO命令。如果apsTrustCenterAddress等于0xffffffffffffff,节点应该并从步骤13继续。

//以下代码有省略,请注意 sBDB.sAttrib.bbdbNodeIsOnANetwork = TRUE; eNS_State = E_NS_WAIT_AFTER_NWK_JOIN; ZTIMER_eStart(u8TimerBdbNs, ZTIMER_TIME_MSEC(300)); //启动BDB_vNsTimerCb()任务 BDB_vNsTimerCb() switch(eNS_State) { case E_NS_WAIT_AFTER_NWK_JOIN: if(ZPS_psAplAibGetAib()->u64ApsTrustCenterAddress == 0xFFFFFFFFFFFFFFFFULL) { eNS_State = E_NS_IDLE; vNsAfterNwkJoin(); } }

11  节点应执行检索新的信任中心链接键的过程(参见子条款10.2.5)。

如果过程成功,节点将从步骤13继续。 如果该过程不成功,则节点应在其旧网络上执行休假请求并重置其网络参数。 然后节点将bdbNodeIsOnANetwork设置为FALSE,并将bdbcommitoningstatus设置为TCLK_EX_FAILURE。 为了执行休假请求,节点发出nlm - leave。向NWK层请求原语, DeviceAddress参数设置为NULL, RemoveChildren参数设置为FALSE, Rejoin参数设置为FALSE。在收到我的假期。确认原语,通知节点请求离开网络的状态。 节点然后终止
//以下代码有省略,请注意 sBDB.sAttrib.bbdbNodeIsOnANetwork = TRUE; eNS_State = E_NS_WAIT_AFTER_NWK_JOIN; ZTIMER_eStart(u8TimerBdbNs, ZTIMER_TIME_MSEC(300)); //启动BDB_vNsTimerCb()任务 BDB_vNsTimerCb() switch(eNS_State) { case E_NS_WAIT_AFTER_NWK_JOIN: if(ZPS_psAplAibGetAib()->u64ApsTrustCenterAddress == 0xFFFFFFFFFFFFFFFFULL) { eNS_State = E_NS_IDLE; vNsAfterNwkJoin(); } if(0x00 == sBDB.sAttrib.u8bdbTCLinkKeyExchangeMethod) { vNsStartTclk(); } else //检索新的信任中心链接键的过程,成功 { DBG_vPrintf(TRACE_BDB,"Only ApsReqKey is supported ! "); eNS_State = E_NS_IDLE; vNsAfterNwkJoin(); } }

12  如果vDoPrimaryScan等于FALSE或bdbSecondaryChannelSet等于0x00000000,节点将从步骤16继续。

如果bdbSecondaryChannelSet不等于0x00000000,节点将vDoPrimaryScan设为FALSE,将vScanChannels设为bdbSecondaryChannelSet,从步骤2继续。

bDoPrimaryScan = FALSE; u32ScanChannels = sBDB.sAttrib.u32bdbSecondaryChannelSet; u8ScanChannel = BDB_CHANNEL_MIN; vNsDiscoverNwk(); 13  节点广播Mgmt_Permit_Joining_req ZDO命令,将 PermitDuration 字段至少设置为bdbcMinCommissioningTime,将TC_Significance字段设置为0x01 vNsAfterNwkJoin(); vNsSendPermitJoin();

14. 如果节点能够允许新节点加入,则应激活其permit join标志。为此,节点发出nlm - permit - join。将PermitDuration参数设置为至少bdbcmincommission oningtime的request原语。收到NWK层的NLME-PERMIT- .confirm原语后,将通知节点激活许可证连接的请求的状态。

vNsAfterNwkJoin(); vNsSendPermitJoin();

15  然后节点将bdbcommitoningstatus设置为SUCCESS。如果节点支持touchlink,它将aplFreeNwkAddrRangeBegin、aplFreeNwkAddrRangeEnd、aplFreeGroupID-RangeBegin和aplFreeGroupIDRangeEnd属性的值设置为0x0000(表示节点使用MAC关联加入了网络)。然后,节点应终止对不在网络上的节点的网络指导过程。

sBDB.sAttrib.ebdbCommissioningStatus = E_BDB_COMMISSIONING_STATUS_SUCCESS; eNS_State = E_NS_IDLE; ZPS_eAplAibSetApsUseExtendedPanId(ZPS_u64NwkNibGetEpid( ZPS_pvAplZdoGetNwkHandle())); sBdbEvent.eEventType = BDB_EVENT_NWK_STEERING_SUCCESS; APP_vBdbCallback(&sBdbEvent); DBG_vPrintf(TRACE_SWITCH_NODE,"GoRunningState! "); vHandleJoinAndRejoin(); sDeviceDesc.eNodeState = E_RUNNING; ZTIMER_eStart(u8TimerPoll, POLL_TIME); ZTIMER_eStart(u8TimerTick, ZCL_TICK_TIME);

16. 节点可以使用制造商指定的程序重试,或者将bdbcommission oningstatus设置为NO_NETWORK,然后终止不在网络上的节点的网络转向过程。如果尝试制造商特定的过程,bdbcommitoningstatus和bdbNodeIsOnANetwork属性将在其终止时相应地更新,以便调试过程是一致的。

//有省略 vNsDiscoverNwk() {  if((!u32ScanChannels) || (u8ScanChannel > BDB_CHANNEL_MAX))     {          if(bDoPrimaryScan == FALSE)         {             vNsTerminateNwkSteering();             return;         } } }