当终端节点的ZDO向网络层发送完发现网络请求后,网络层操作完成后会向ZDO层发送发现网络确认,ZDO层利用ZDO_NetworkDiscoveryConfirmCB函数来对确认进行处理。下面看一下该函数的代码:
ZStatus_t ZDO_NetworkDiscoveryConfirmCB( uint8ResultCount,
networkDesc_t *NetworkList )
{
networkDesc_t *pNwkDesc = NetworkList;
ZDO_NetworkDiscoveryCfm_t msg;
uint8 i = ResultCount;
uint8 stackProfile;
uint8 stackProfilePro;
uint8 selected;
#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
if ( zdappMgmtNwkDiscReqInProgress )
{
zdappMgmtNwkDiscReqInProgress = false;
ZDO_FinishProcessingMgmtNwkDiscReq( ResultCount, NetworkList);
return (ZSuccess );
}
#endif
// 以下为 检查网络描述符中的各项参数
stackProfilePro = FALSE;
selected = FALSE;
for ( stackProfile = 0; stackProfile< STACK_PROFILE_MAX; stackProfile++ )
{
pNwkDesc =NetworkList;
for ( i = 0;i < ResultCount; i++, pNwkDesc =pNwkDesc->nextDesc )
{
if ( zgConfigPANID != 0xFFFF )
{
// PAN Id is preconfigured. check if it matches
if ( pNwkDesc->panId != zgConfigPANID )
continue;
}
if ( nwk_ExtPANIDValid( ZDO_UseExtendedPANID) == true )
{
// If the extended Pan ID is commissioned to a non zero value
// Only join the Pan that has match EPID
if ( osal_ExtAddrEqual( ZDO_UseExtendedPANID,pNwkDesc->extendedPANID) == false )
continue;
}
// check that network is allowing joining
if ( ZSTACK_ROUTER_BUILD )
{
if ( stackProfilePro == FALSE )
{
if ( !pNwkDesc->routerCapacity )
{
continue;
}
}
else
{
if ( !pNwkDesc->deviceCapacity )
{
continue;
}
}
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
if ( !pNwkDesc->deviceCapacity )
{
continue;
}
}
// check version of zigbee protocol
if ( pNwkDesc->version != _NIB.nwkProtocolVersion)
continue;
// check version of stack profile
if ( pNwkDesc->stackProfile !=zgStackProfile )
{
if ( ((zgStackProfile == HOME_CONTROLS)&&(pNwkDesc->stackProfile == ZIGBEEPRO_PROFILE))
|| ((zgStackProfile == ZIGBEEPRO_PROFILE)&&(pNwkDesc->stackProfile ==HOME_CONTROLS)) )
stackProfilePro = TRUE;
if ( stackProfile == 0 )
{
continue;
}
}
break;
}
if (i< ResultCount)
{
selected = TRUE;
break;
}
// break ifselected or stack profile pro wasn't found
if ((selected == TRUE) || (stackProfilePro == FALSE) )
{
break;
}
}
if ( i == ResultCount )
{
msg.hdr.status = ZDO_FAIL; //couldn't find appropriate PAN to join !
}
else
{
msg.hdr.status = ZDO_SUCCESS;
msg.panIdLSB= LO_UINT16( pNwkDesc->panId );
msg.panIdMSB= HI_UINT16( pNwkDesc->panId );
msg.logicalChannel = pNwkDesc->logicalChannel;
msg.version= pNwkDesc->version;
osal_cpyExtAddr( msg.extendedPANID,pNwkDesc->extendedPANID );
}
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF,sizeof(ZDO_NetworkDiscoveryCfm_t), (uint8 *)&msg);//向ZDO层发送一个ZDO_NWK_DISC_CNF消息
return (ZSuccess);
} // ZDO_NetworkDiscoveryConfirmCB
那么接下来看看ZDApp是怎么处理ZDO_NWK_DISC_CNF消息的。在ZDO层找到处理消息的函数ZDApp_ProcessOSALMsg
源代码如下:
case ZDO_NWK_DISC_CNF:
if (devState != DEV_NWK_DISC)
break;
if ( ZG_BUILD_JOINING_TYPE &&ZG_DEVICE_JOINING_TYPE) //条件成立
{
if ( (((ZDO_NetworkDiscoveryCfm_t*)msgPtr)->hdr.status == ZDO_SUCCESS)&& (zdoDiscCounter >NUM_DISC_ATTEMPTS) )//条件成立
{
if ( devStartMode == MODE_JOIN )//条件成立
{
devState =DEV_NWK_JOINING; //修改设备状态为网络加入状态
ZDApp_NodeProfileSync((ZDO_NetworkDiscoveryCfm_t*)msgPtr);//根据发现的网络信息进行一些节点的配置操作
if ( NLME_JoinRequest( ((ZDO_NetworkDiscoveryCfm_t*)msgPtr)->extendedPANID,
BUILD_UINT16( ((ZDO_NetworkDiscoveryCfm_t*)msgPtr)->panIdLSB, ((ZDO_NetworkDiscoveryCfm_t*)msgPtr)->panIdMSB ),
((ZDO_NetworkDiscoveryCfm_t*)msgPtr)->logicalChannel,
ZDO_Config_Node_Descriptor.CapabilityFlags ) != ZSuccess)//根据发现的网络信息向网络层发起加入网络请求
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()&EXTENDED_JOINING_RANDOM_MASK))) );
}
}
网络层加入完网络后,会发送一个加入确认到ZDO层,利用ZDO_JoinConfirmCB函数,对确认信息进行处理,下面看下源代码:
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
{
(void)PanId; // remove if thisparameter is used.
nwkStatus =(byte)Status; //更新网络状态
if ( Status == ZSUCCESS )
{
// LED onshows device joined
HalLedSet (HAL_LED_3, HAL_LED_MODE_ON ); //打开LED_3
// LED offforgets HOLD_AUTO_START
HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);//关闭LED_4
if ((devState == DEV_HOLD) )
{
// Began with HOLD_AUTO_START
devState = DEV_NWK_JOINING;
}
if (!ZG_SECURE_ENABLED )
{
// Notify to save info into NV
ZDApp_NVUpdate();
}
}
else
{
#if defined(BLINK_LEDS)
HalLedSet (HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED toshow failure
#endif
}
// Notify ZDApp
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND,sizeof(osal_event_hdr_t), (byte*)NULL);//向ZDO层发送一个ZDO_NWK_JOIN_IND消息。
}
我们看是ZDO如何处理这个消息的,在 ZDApp_ProcessOSALMsg中看下源代码:
case ZDO_NWK_JOIN_IND:
if ( ZG_BUILD_JOINING_TYPE &&ZG_DEVICE_JOINING_TYPE )
{
ZDApp_ProcessNetworkJoin();
}
break;
进入此函数中看下主要进行什么操作:
void ZDApp_ProcessNetworkJoin( void )
{
if ( (devState == DEV_NWK_JOINING) ||
((devState == DEV_NWK_ORPHAN) &&
(ZDO_Config_Node_Descriptor.LogicalType == NODETYPE_ROUTER)))
{
// Result ofa Join attempt by this device.
if (nwkStatus == ZSuccess )
{
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );//设置状态改变事件
#if defined ( POWER_SAVING )
osal_pwrmgr_device( PWRMGR_BATTERY );
#endif
if ( ZG_SECURE_ENABLED && (ZDApp_RestoreNwkKey() == false ) )
{
// wait for auth from trust center!!
devState = DEV_END_DEVICE_UNAUTH;
// Start the reset timer for MAX UNAUTH time
ZDApp_ResetTimerStart( 10000 );//MAX_DEVICE_UNAUTH_TIMEOUT );
}
else
{
if ( ZSTACK_ROUTER_BUILD )
{
if ( devState == DEV_NWK_ORPHAN
&&ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
// Change NIB state to router for restore
_NIB.nwkState = NWK_ROUTER;
}
}
if ( devState == DEV_NWK_JOINING )
{
ZDApp_AnnounceNewAddress();
}
devState = DEV_END_DEVICE;
if ( ZSTACK_ROUTER_BUILD )
{
// NOTE: first two parameters are not used, see NLMEDE.h fordetails
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE)
{
NLME_StartRouterRequest( 0, 0, false );
}
}
}
}
我们看ZDO层怎么对状态改变事件进行响应,在ZDApp_event_loop中找到:
if ( events & ZDO_STATE_CHANGE_EVT )
{
ZDO_UpdateNwkStatus( devState ); //调用更新网络状态函数。
if (zgConcentratorEnable == TRUE )
{
osal_start_timerEx( NWK_TaskID, NWK_MTO_RTG_REQ_EVT, 100 );
}
return (events ^ ZDO_STATE_CHANGE_EVT);
}
更新网络状态函数源代码:
void ZDO_UpdateNwkStatus(devStates_t state)
{
epList_t *pItem = epList;
while (pItem != NULL)
{
if(pItem->epDesc->endPoint !=ZDO_EP)
{
zdoSendStateChangeMsg(state,*(pItem->epDesc->task_id));//把状态改变的消息通知给在AF层注册过的端口的task
}
pItem =pItem->nextDesc;
}
#if defined MT_ZDO_CB_FUNC
zdoSendStateChangeMsg(state, MT_TaskID);
#endif
ZDAppNwkAddr.addr.shortAddr =NLME_GetShortAddr();
(void)NLME_GetExtAddr(); //Load the saveExtAddr pointer.
}
由于我们是在sapi层注册的端口,因此我们可以去SAPI_ProcessEvent函数中找到状态改变消息的响应。源代码如下:
case ZDO_STATE_CHANGE:
// If the device has started up, notify the application
if (pMsg->status == DEV_END_DEVICE ||
pMsg->status == DEV_ROUTER ||
pMsg->status == DEV_ZB_COORD )
{
SAPI_StartConfirm( ZB_SUCCESS ); //开始启动确认
}
else if (pMsg->status == DEV_HOLD||
pMsg->status == DEV_INIT)
{
SAPI_StartConfirm( ZB_INIT );
}
break;
查看启动确认源码:
void SAPI_StartConfirm( uint8 status )
{
#if defined ( MT_SAPI_CB_FUNC )
if ( SAPICB_CHECK( SPI_CB_SAPI_START_CNF ))
{
zb_MTCallbackStartConfirm( status );
}
else
#endif //MT_SAPI_CB_FUNC
{
#if ( SAPI_CB_FUNC )
zb_StartConfirm( status );//执行此函数
#endif
}
}
查看源码:
void zb_StartConfirm( uint8 status )
{
if ( status == ZB_SUCCESS )
{
myAppState =APP_START; //将应用状态修改为启动状态
// Setevent to bind to a collector
osal_start_timerEx( sapi_TaskID, MY_FIND_COLLECTOR_EVT,myBindRetryDelay);//向sapi层发送MY_FIND_COLLECTOR_EVT事件,来进行绑定一个协调器。
}
else
{
// Tryjoining again later with a delay
osal_start_timerEx( sapi_TaskID, MY_START_EVT, myStartRetryDelay);
}
}