3928 views|0 replies

6609

Posts

0

Resources
The OP
 

Thoroughly understand the state switching of terminal devices in TI ZigBee protocol stack [Copy link]

This post was last edited by Jacktang on 2018-1-24 17:44 This article mainly introduces the detailed description of the switching between different states during the working process of the terminal device End Device in TI ZigBee protocol stack Z-Stack, and further understands the working process of TI ZigBee protocol stack Z-Stack and the states of the terminal device involved in the protocol stack by analyzing the data packets interacting in the air. typedef enum { DEV_HOLD, // Initialized - not started automatically DEV_INIT, // Initialized - not connected to anything DEV_NWK_DISC, // Discovering PAN's to join DEV_NWK_JOINING, // Joining a PAN DEV_NWK_SEC_REJOIN_CURR_CHANNEL, // ReJoining a PAN in secure mode scanning in current channel, only for end devices DEV_END_DEVICE_UNAUTH, // Joined but not yet authenticated by trust center DEV_END_DEVICE, // Started as device after authentication DEV_ROUTER, // Device joined, authenticated and is a router DEV_COORD_STARTING, // Started as Zigbee Coordinator DEV_ZB_COORD, // Started as Zigbee Coordinator DEV_NWK_ORPHAN, // Device has lost information about its parent.. DEV_NWK_KA, // Device is sending KeepAlive message to its parent DEV_NWK_BACKOFF, // Device is waiting before trying to rejoin DEV_NWK_SEC_REJOIN_ALL_CHANNEL, // ReJoining a PAN in secure mode scanning in all channels, only for end devices DEV_NWK_TC_REJOIN_CURR_CHANNEL, // ReJoining a PAN in Trust center mode scanning in current channel, only for end devices DEV_NWK_TC_REJOIN_ALL_CHANNEL // ReJoining a PAN in Trust center mode scanning in all channels, only for end devices } devStates_t; Different device types have different device states. The devices that may be used for terminal devices are as follows. DEV_HOLD, // Initialized - not started automatically DEV_INIT, // Initialized - not connected to anything DEV_NWK_DISC, // Discovering PAN's to join DEV_NWK_JOINING, // Joining a PAN DEV_NWK_SEC_REJOIN_CURR_CHANNEL, // ReJoining a PAN in secure mode scanning in current channel, only for end devices DEV_END_DEVICE_UNAUTH, // Joined but not yet authenticated by trust center DEV_END_DEVICE, // Started as device after authentication DEV_NWK_ORPHAN, // Device has lost information about its parent.. DEV_NWK_BACKOFF, // Device is waiting before trying to rejoin DEV_NWK_SEC_REJOIN_ALL_CHANNEL, // ReJoining a PAN in secure mode scanning in all channels, only for end devices DEV_NWK_TC_REJOIN_CURR_CHANNEL, // ReJoining a PAN in Trust center mode scanning in current channel, only for end devices DEV_NWK_TC_REJOIN_ALL_CHANNEL // ReJoining a PAN in Trust center mode scanning in all channels, only for end devices State machine switching of terminal devices During the operation of the terminal device, the state machine switching diagram is as follows, which is from C:\Texas Instruments\Z-Stack Home 1.2.2a.44539\Documents\Z-Stack Terminal device state switching is handled in Z-Stack After the terminal device is powered on and starts running, it will first run to ZDApp_Init( uint8 task_id ) to initialize the ZDO layer Task. Then use the following code to determine the initial state of the node, ? // Start the device? if ( devState != DEV_HOLD ) { ZDOInitDevice( 0 ); } else { ZDOInitDevice( ZDO_INIT_HOLD_NWK_START ); // Blink LED to indicate HOLD_START HalLedBlink ( HAL_LED_4, 0, 50, 500 ); } The definition of the initialization state is implemented by the following code. HOLD_AUTO_START can be defined in Project->Options of the IAR project. DEV_HOLD means the device is in Hold state. The protocol stack will not automatically start the device, but will trigger it through other means, such as button triggering. If the initial state is DEV_INIT, the node will automatically start the device. #if defined( HOLD_AUTO_START ) devStates_t devState = DEV_HOLD; #else devStates_t devState = DEV_INIT; #endif Start the device through the ZDOInitDevice( uint16 startDelay) function. The parameter startDelay indicates whether to start immediately or after a delay. DEV_INIT state to DEV_NWK_DISC state (1) In the ZDOInitDevice( uint16 startDelay) function, the device is finally started by triggering ZDApp_NetworkInit( extendedDelay );. The relevant code is in the ZDApp_event_loop( uint8 task_id, UINT16 events ) function else { if ( continueJoining ) { #if defined ( MANAGED_SCAN ) ZDApp_NetworkInit( MANAGEDSCAN_DELAY_BETWEEN_SCANS ); #else zdoDiscCounter++; ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY + ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) ); #endif } } As mentioned above, ZDApp_NwkDescListProcessing calls nwk_getNwkDescList() to obtain the number of network devices by selecting a device from the searched network list. In fact, it is to select the appropriate network and device from the NwkDescList list. So when are the networks and devices put into this NwkDescList list? It is during the search process. The node searches for the network by sending a beacon request. The coordinator or router in the channel will return a beacon with its own device and network information after receiving the beacon request. After receiving the beacon, the node will trigger the callback function ZDO_beaconNotifyIndCB (NLME_beaconInd_t *pBeacon), then save the information of the network device and make some selections. DEV_NWK_DISC state to DEV_NWK_JOIN state (2) If the node meets the two conditions if ( ( (pChosenNwk = ZDApp_NwkDescListProcessing()) != NULL ) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) ), it will start to join the network and send an Associate Request to the parent device through the NLME_JoinRequest function to request the allocation of a device address. At this time, the state has been switched to the DEV_NWK_JOIN state. if ( ( (pChosenNwk = ZDApp_NwkDescListProcessing()) != NULL ) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) ) { if ( devStartMode == MODE_JOIN ) { ZDApp_ChangeState( DEV_NWK_JOINING ); ZDApp_NodeProfileSync( pChosenNwk->stackProfile); if ( NLME_JoinRequest( pChosenNwk->extendedPANID, pChosenNwk->panId, pChosenNwk->logicalChannel, ZDO_Config_Node_Descriptor.CapabilityFlags, pChosenNwk->chosenRouter, pChosenNwk->chosenRouterDepth ) != ZSuccess ) { ZDApp_NetworkInit( (uint16)(NWK_START_DELAY + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) ); } } // if ( devStartMode == MODE_JOIN ) DEV_NWK_JOIN state to DEV_END_DEVICE_UNAUTH state (4) After the node sends the Associate Request by calling NLME_JoinRequest, the parent device will assign it a 16-bit short address through Associate Response. After obtaining the short address, the node will call ZDO_JoinConfirmCB( uint16 PanId,The callback function ZStatus_t Status ) will eventually reach the case ZDO_NWK_JOIN_IND: of the ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ) function. In the ZDApp_ProcessNetworkJoin( void ) function, if the network has SECURE enabled, the device enters the DEV_END_DEVICE_UNAUTH state, which is actually the state of waiting for the Trust Center to authorize the distribution of keys. If the network does not have SECURE enabled, ZDApp_AnnounceNewAddress() is called directly to tell the devices in the network that the network has been successfully connected, and the state is changed to ZDApp_ChangeState( DEV_END_DEVICE ); state, which means that the network has been successfully connected. So what does the node do when SECURE is enabled? DEV_END_DEVICE_UNAUTH state to DEV_END_DEVICE state (5) After entering the DEV_END_DEVICE_UNAUTH state, a timer event for authentication failure will be started, ZDApp_ResetTimerStart( MAX_DEVICE_UNAUTH_TIMEOUT ); If the key sent by the parent device has not been received within the MAX_DEVICE_UNAUTH_TIMEOUT time, or the received key is incorrect, then (18) it will return to DEV_INIT and reset and restart the network joining process. If the key sent by the parent device is received during the timer running, ZDSecMgrTransportKeyInd( ZDO_TransportKeyInd_t* ind )-> ZDSecMgrAuthNwkKey()->ZDApp_DeviceAuthEvt();->ZDApp_ChangeState( DEV_END_DEVICE ), and the previously started timer will be stopped at this time. Finally, it switches to the DEV_END_DEVICE state. From the DEV_END_DEVICE state to the DEV_END_ORPHAN state (13) After the terminal device successfully joins the network, the state becomes DEV_END_DEVICE. Under normal circumstances, the terminal device can smoothly send data to the parent device, and can also obtain the data sent to the child device from the parent device through the Data Request method. In the actual application layer, the terminal device may move, the parent device may lose power, and the communication with the parent device may fail multiple times due to interference, causing the terminal device to become an isolated device. If the MAC ACK of the parent device is not received after continuous data transmission, the device is triggered to enter the isolated device state, and the ZDO_SyncIndicationCB(uint8 type, uint16 shortAddr) function is called. Finally, the following program is triggered in ZDApp_ProcessOSALMsg(osal_event_hdr_t *msgPtr). case ZDO_NWK_JOIN_REQ: if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE ) { retryCnt = 0; devStartMode = MODE_RESUME; _tmpRejoinState = true; osal_cpyExtAddr( ZDO_UseExtendedPANID, _NIB.extendedPANID ); zgDefaultStartingScanDuration = BEACON_ORDER_60_MSEC; ZDApp_NetworkInit( 0 ); } break; The startup status is already MODE_RESUME. The program has re-executed the following code in ZDApp_event_loop( uint8 task_id, UINT16 events ) to start the device again. if ( events & ZDO_NETWORK_INIT ) { // Initialize apps and start the network ZDApp_ChangeState( DEV_INIT ); ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode, DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER ); // Return unprocessed events return (events ^ ZDO_NETWORK_INIT); } Finally execute the following code in ZDO_StartDevice else if ( startMode == MODE_RESUME ) { if ( logicalType == NODETYPE_ROUTER ) { ZMacScanCnf_t scanCnf; ZDApp_ChangeState( DEV_NWK_ORPHAN ); /* if router and nvram is available, fake successful orphan scan */ scanCnf.hdr.Status = ZSUCCESS; scanCnf.ScanType = ZMAC_ORPHAN_SCAN; scanCnf.UnscannedChannels = 0; scanCnf.ResultListSize = 0; nwk_ScanJoiningOrphan(&scanCnf); ret = ZSuccess; } else { ZDApp_ChangeState( DEV_NWK_ORPHAN ); //set timer for scan and rejoin osal_start_timerEx( ZDAppTaskID, ZDO_REJOIN_BACKOFF, zgDefaultRejoinScan ); ret = NLME_OrphanJoinRequest( runtimeChannel,zgDefaultStartingScanDuration ); } } At this time, the device has switched from DEV_END_DEVICE to DEV_END_ORPHAN. By calling the NLME_OrphanJoinRequest function, an Orphan Notification is sent to the channel to tell the devices in the network that it is an isolated device. This Orphan Notification will be sent once on each defined channel. DEV_END_ORPHAN state to DEV_END_DEVICE state (6) After the node sends the Orphan Notification, the node state switches from DEV_END_ORPHAN to NWK_JOINING_ORPHAN state. In this state, the node will send an Orphan Notification message on the previously defined channel. If the original parent device replies to the Coord Realignment, the node believes that the original parent device has been found again and will call ZDO_JoinConfirmCB( PanId, Status ); and then call case ZDO_NWK_JOIN_IND in ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ): if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE ) { ZDApp_ProcessNetworkJoin(); } break; and then call ZDApp_AnnounceNewAddress() again to tell other devices in the network that the network has been successfully joined again. At this time, the node's state switches to DEV_END_DEVICE state. DEV_END_ORPHAN state to DEV_INIT state (12) When the node switches from End Device state to Orphan state, it is not always possible to find the original parent device again through Orphan Scan. For example, the parent device loses power, is moved away, or the Coord Realignment reply from the parent device is not received due to interference from other data in the network. In this case, the node starts to search the network again instead of just looking for its original parent device. If the join fails in the Orphan state, the void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status ) callback function will also be called. Then call ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ) but the status at this time becomes a failed state. Enter the following code. void ZDApp_ProcessNetworkJoin( void ) ...... else if ( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_SEC_REJOIN_CURR_CHANNEL || devState == DEV_NWK_TC_REJOIN_CURR_CHANNEL || devState == DEV_NWK_TC_REJOIN_ALL_CHANNEL || devState == DEV_NWK_SEC_REJOIN_ALL_CHANNEL ) ...... else { if ( devStartMode == MODE_RESUME ) { if ( ++retryCnt <= MAX_RESUME_RETRY ) { if ( _NIB.nwkPanId == 0xFFFF ) devStartMode = MODE_JOIN; else { devStartMode = MODE_REJOIN; _tmpRejoinState = true; prevDevState = DEV_NWK_SEC_REJOIN_CURR_CHANNEL; } } // Do a normal join to the network after certain times of rejoin retries else if( AIB_apsUseInsecureJoin == true ) { devStartMode = MODE_JOIN; } } else if(devStartMode == MODE_REJOIN) 此时设备的状态devState=DEV_NWK_ORPHAN,并且devStartMode=MODE_RESUME,所以程序会运行到devStartMode = MODE_REJOIN。 最后在ZDApp_ProcessNetworkJoin里面运行到下面代码,开始重新搜索网络了。 ZDApp_NetworkInit( (uint16)(NWK_START_DELAY + (osal_rand()& EXTENDED_JOINING_RANDOM_MASK)) ); 程序再次执行到ZDApp_event_loop( uint8 task_id, UINT16 events )下面代码,此时的状态就变成了DEV_INIT状态。 11 if ( events & ZDO_NETWORK_INIT ) { // Initialize apps and start the network ZDApp_ChangeState( DEV_INIT ); ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode, DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER ); // Return unprocessed events return (events ^ ZDO_NETWORK_INIT); } DEV_INIT状态到DEV_NWK_DISC(1) 在进入DEV_INIT状态以后,进入ZDO_StartDevice()函数,因为设备的startmode是MODE_REJOIN,所以按照下面的代码,进入discover状态 if ( ZG_BUILD_JOINING_TYPE && (logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE) ) { if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) ) { ZDApp_ChangeState( DEV_NWK_DISC ); #if defined( MANAGED_SCAN ) ZDOManagedScan_Next(); ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC ); #else ret = NLME_NetworkDiscoveryRequest( runtimeChannel, zgDefaultStartingScanDuration ); #if defined ( ZIGBEE_FREQ_AGILITY ) if ( !( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE ) && ( ret == ZSuccess ) && ( ++discRetries == 4 ) ) { // For devices with RxOnWhenIdle equals to FALSE, any network channel // change will not be recieved. On these devices or routers that have // lost the network, an active scan shall be conducted on the Default // Channel list using the extended PANID to find the network. If the // extended PANID isn't found using the Default Channel list, an scan // should be completed using all channels. runtimeChannel = MAX_CHANNELS_24GHZ; } #endif // ZIGBEE_FREQ_AGILITY DEV_NWK_DISC status to DEV_NWK_REJOIN(8) Just like in the previous state 2, after entering the discovery state, scan the original network on the channel. However, this time, it will not scan all channels, but only the channel of the previous network, because the default channel of the network is It won't change. After the scanning process is completed, the program also executes to NLME_NetworkDiscoveryConfirm(uint8 status)-> ZDO_NetworkDiscoveryConfirmCB(status)-> ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(osal_event_hdr_t), (uint8 *)&msg );-> ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ) case ZDO_NWK_DISC_CNF: case ZDO_NWK_DISC_CNF: if (devState != DEV_NWK_DISC) break; if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE ) { // Process the network discovery scan results and choose a parent // device to join/rejoin itself networkDesc_t *pChosenNwk; if ( ( (pChosenNwk = ZDApp_NwkDescListProcessing()) != NULL ) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) ) { ......................... else if ( devStartMode == MODE_REJOIN ) { ZStatus_t rejoinStatus; // Transition state machine to correct rejoin state based on previous state before network discovery if ( ZDApp_RestoreNwkKey( FALSE )== TRUE ) ........................ // Perform Secure or Unsecure Rejoin depending on available configuration if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey( TRUE ) == TRUE ) ) { rejoinStatus = NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); } else { rejoinStatus = NLME_ReJoinRequestUnsecure( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); } if ( rejoinStatus != ZSuccess ) { ZDApp_NetworkInit( (uint16)(NWK_START_DELAY + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) ); } Due to the start mode status before this scan, Start entering the rejoin state by calling NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); to send Rejoin Request message. DEV_NWK_REJOIN state to DEV_END_DEVICE (15) If after sending Rejoin Request, a Rejoin Response message is received from the parent device, the program will enter the following code of ZDApp_ProcessNetworkJoin (void), else if (devState == DEV_NWK_ORPHAN || devState == DEV_NWK_SEC_REJOIN_CURR_CHANNEL || devState == DEV_NWK_TC_REJOIN_CURR_CHANNEL || devState == DEV_NWK_TC_REJOIN_ALL_CHANNEL || devState == DEV_NWK_SEC_REJOIN_ALL_CHANNEL ) { ...................... // results of an orphaning attempt by this device // results of an orphaning attempt by this device if (nwkStatus == ZSuccess) { //When the device has successfully rejoined then reset retryCnt retryCnt = 0; // Verify NWK key is available before sending Device_annce if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey( TRUE ) == false ) ) { // wait for auth from trust center ZDApp_ChangeState( DEV_END_DEVICE_UNAUTH ); // Start the reset timer for MAX UNAUTH time ZDApp_ResetTimerStart( MAX_DEVICE_UNAUTH_TIMEOUT ); } else { ZDApp_ChangeState( DEV_END_DEVICE ); osal_stop_timerEx( ZDAppTaskID, ZDO_REJOIN_BACKOFF ); // setup Power Manager Device #if defined ( POWER_SAVING ) osal_pwrmgr_device( PWRMGR_BATTERY ); #endif // The receiver is on, turn network layer polling off. if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE ) { // if Child Table Management process is not enabled if ( zgChildAgingEnable == FALSE ) { NLME_SetPollRate( 0 ); NLME_SetQueuedPollRate( 0 ); NLME_SetResponseRate( 0 ); } } if ( ZSTACK_ROUTER_BUILD ) { // NOTE: first two parameters are not used, see NLMEDE.h for details if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE ) { NLME_StartRouterRequest( 0, 0, false ); } } ZDApp_AnnounceNewAddress(); if ( ( (ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE) == 0 ) || ( (ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE) && (zgChildAgingEnable == TRUE) ) ) { NLME_SetPollRate( ZDApp_SavedPollRate ); } } } ? 1 ? 1 Finally, the terminal sends ZDApp_AnnounceNewAddress(); to broadcast the devices in the network again. The node Rejoins the network successfully and the state is migrated to DEV_END_DEVICE again. ? 1 DEV_NWK_REJOIN status to DEV_END_DEVICE_UNAUTH (20) When the node sends a Rejoin Request, it will first read the network key that it saved in the previous network, through NLME_NetworkDiscoveryConfirm(uint8 status)-> ZDO_NetworkDiscoveryConfirmCB(status)-> ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(osal_event_hdr_t), (uint8 *)&msg );-> ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ) and the code below case ZDO_NWK_DISC_CNF. else if ( devStartMode == MODE_REJOIN ) { ZStatus_t rejoinStatus; // Transition state machine to correct rejoin state based on previous state before network discovery if ( ZDApp_RestoreNwkKey( FALSE )== TRUE ) ............. // Perform Secure or Unsecure Rejoin depending on available configuration if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey( TRUE ) == TRUE ) ) { rejoinStatus = NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); } else { rejoinStatus = NLME_ReJoinRequestUnsecure( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); } if ( rejoinStatus != ZSuccess ) { ZDApp_NetworkInit( (uint16)(NWK_START_DELAY + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) ); } If the network key is read incorrectly during ZDApp_RestoreNwkKey( uint8 incrFrmCnt ), or the previously saved network key is no longer available, then an Unsecure Rejoin is sent. At this time, if a Rejoin Response is received from the parent device, the node will not immediately change to the End Device state. Instead, it will enter DEV_END_DEVICE_UNAUTH because the correct network key has not yet been obtained. The processing code is if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey( TRUE ) == false ) ) in ZDApp_ProcessNetworkJoin( void ) ) { // wait for auth from trust center ZDApp_ChangeState( DEV_END_DEVICE_UNAUTH ); // Start the reset timer for MAX UNAUTH time ZDApp_ResetTimerStart( MAX_DEVICE_UNAUTH_TIMEOUT ); } else {
This post is from RF/Wirelessly
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

快速回复 返回顶部 Return list