路由器(自启动模式分析)
使用的协议栈版本信息: ZigBee2006\ZStack-1.4.3-1.2.1
Zigbee网络设备启动流程—路由器(自启动模式)—以SampleApp的路由器为例.
1、路由器预编译信息
通过project->options->c/c++compiler->extraOptions可以看到路由器器所带的配置文件为:
-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wRouter.cfg
-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wConfig.cfg
即编译了RTR_NWK.
通过project->options->c/c++compiler->Preprocessor->Defined symbols可以看到路由器预编译包含了:
CC2430EB; ZTOOL_P1; MT_TASK; LCD_SUPPORTED=DEBUG
没有编译HOLD_AUTO_START和SOFT_START.
2、具体流程
main()->osal_init_system()->osalInitTasks()->ZDApp_Init()
进入ZDApp_Init()函数:
**************************************
**************************************
void ZDApp_Init( byte task_id )
{
uint8 capabilities;
// Save the task ID
ZDAppTaskID = task_id;
// Initialize the ZDO global device short address storage
ZDAppNwkAddr.addrMode = Addr16Bit;
ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR;//0xFFFE
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.
// Check for manual"Hold Auto Start"
//检测到有手工设置SW_1则会设置devState = DEV_HOLD,从而避开网络初始化
ZDAppCheckForHoldKey();
// Initialize ZDO items and setup the device - type of device to create.
ZDO_Init(); //通过判断预编译来开启一些函数功能
// Register the endpoint description with the AF
// This task doesn't have a Simple description, but we still need
// to register the endpoint.
afRegister( (endPointDesc_t *)&ZDApp_epDesc );
#if defined( ZDO_USERDESC_RESPONSE )
ZDApp_InitUserDesc();
#endif // ZDO_USERDESC_RESPONSE
// set broadcast address mask to support broadcast filtering
NLME_GetRequest(nwkCapabilityInfo, 0, &capabilities);
NLME_SetBroadcastFilter( capabilities );
// Start the device?
if ( devState != DEV_HOLD )
{
ZDOInitDevice( 0 );
}
/*如果devState=DEV_HOLD,则不会调用ZDOInitDevice()来初始化网络
即不组网也不进网.LED4闪烁等待应用程序来开启设备并初始化网络
*/
else
{
// Blink LED to indicate HOLD_START
HalLedBlink ( HAL_LED_4, 0, 50, 500 );
}
ZDApp_RegisterCBs();
}
**************************************
路由器没有编译HOLD_AUTO_START,也没有手工设置SW_1,初始化devState = DEV_INIT(参见基本问题说明3).因此直接在ZDApp_Init()中进入ZDOInitDevice( 0 )开启设备.
**************************************
uint8 ZDOInitDevice( uint16 startDelay )
{
//初始化设备网络状态为ZDO_INITDEV_NEW_NETWORK_STATE:新的网络状态.
//可能意味着ZCD_NV_STARTUP_OPTION不能恢复,或没有任何网络状态恢复
uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
uint16 extendedDelay = 0;
devState = DEV_INIT; // Remove the Hold state
// Initialize leave control logic
//函数读取NV项目ZCD_NV_LEAVE_CTRL的值,ZDApp_LeaveCtrl指向这个值
ZDApp_LeaveCtrlInit();
// Check leave control reset settings
ZDApp_LeaveCtrlStartup( &devState, &startDelay );
// Leave may make the hold state come back
//以上两个函数设置了对设备离开时的控制,如果有延时则延时,没有则
//把设备状态设为DEV_HOLD
if ( devState == DEV_HOLD )
//ZDO_INITDEV_LEAVE_NOT_STARTED:该设备没有在网络中,下次调用才启用.
return ( ZDO_INITDEV_LEAVE_NOT_STARTED ); // Don't join - (on
#if defined ( NV_RESTORE )
// Get Keypad directly to see if a reset nv is needed.
// Hold down the SW_BYPASS_NV key (defined in On
// while booting(引导) to skip past NV Restore.
//SW_BYPASS_NV按键处于按下状态时,则避开网络层的NV存储
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //设备网络状态为新的网络状态
else
{
// Determine if NV should be restored
//函数返回的设备网络状态要么是新的网络状态;要么是恢复的网络状态;以此
//来确定要不要读取NV里相应条目来恢复网络先前状态
networkStateNV = ZDApp_ReadNetworkRestoreState();
}
//如果设备的网络状态为恢复的网络状态
if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
//恢复设备先前的网络状态参数并且
//设置devStartMode = MODE_RESUME!!!!
networkStateNV = ZDApp_RestoreNetworkState();
}
else//如果设备的网络状态为新的网络状态,在下面进行处理
{
// Wipe out(清除) the network state in NV
NLME_InitNV();
NLME_SetDefaultNV(); //设置默认NV条目
}
#endif
//如果设备的网络状态为新的网络状态
if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE )
{
//根据预编译来设置设备新的网络状态参数
ZDAppDetermineDeviceType();/*!!!!*/
// On
extendedDelay = (uint16)((NWK_START_DELAY + startDelay)
+ (osal_rand() & EXTENDED_JOINING_RANDOM_MASK));
}
// Initialize device security
ZDApp_SecInit( networkStateNV );
// Trigger the network start
ZDApp_NetworkInit( extendedDelay );
return ( networkStateNV );
}
**************************************
分两种情况:
(1)如果路由器预编译了NV_RESTORE,且函数ZDApp_ReadNetworkRestoreState()返回值为ZDO_INITDEV_RESTORED_NETWORK_STATE,则进入ZDApp_RestoreNetworkState(),因为这是路由器,因此只是设置devStartMode = MODE_RESUME.
****************
uint8 ZDApp_RestoreNetworkState( void )
{
…………
// Are we a coordinator
//设备的网络状态为恢复的网络状态.则进入这个函数进行恢复
//先判断如果短地址为0则设置设备逻辑类型为协调器且devStartMode = MODE_RESUME
//否则设置devStartMode = MODE_RESUME
ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();
if ( ZDAppNwkAddr.addr.shortAddr == 0 ) //如果短地址是0,即协调器
{
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR; //!!!!!
}
devStartMode = MODE_RESUME; //MODE_RESUME!!!!!!!!
…………
}
****************
(2)如果路由器没有预编译NV_RESTORE,networkStateNV ==ZDO_INITDEV_NEW_NETWORK_STATE,但由于路由器编译了RTR_NWK而没有编译SOFT_START,因此ZDAppDetermineDeviceType()不起作用.因此ZDO_Config_Node_Descriptor.LogicalType和devStartMode这两个关键参数保持初始化时的值:
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER(见基本问题说明6)
devStartMode = MODE_JOIN(见基本问题说明4)
对于路由器,这两种情况最终都是确定两个关键设备网络状态参数的值.对本例的SampleApp的路由器,没有编译NV_RESTORE,因此属于情况(2).
然后调用ZDApp_NetworkInit()启动网络:
****************
void ZDApp_NetworkInit( uint16 delay )
{
if ( delay )
{
// Wait awhile before starting the device
osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );
}
else
{
osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
}
}
****************
通过触发ZDAppTaskID的ZDO_NETWORK_INIT事件.来看下对ZDO_NETWORK_INIT 事件的处理:
****************
UINT16 ZDApp_event_loop( byte task_id, UINT16 events )
{
if ( events & ZDO_NETWORK_INIT )
{
// Initialize apps and start the network
devState = 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);
}
}
****************
可以看到调用了ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );
这里设备网络状态参数:
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER
devStartMode = MODE_JOIN
且路由器编译了RTR_NWK,未编译ZDO_COORDINATOR和MANAGED_SCAN .
****************
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
ZStatus_t ret;
ret = ZUnsupportedMode;
#if defined(ZDO_COORDINATOR)
if ( logicalType == NODETYPE_COORDINATOR )
{
if ( startMode == MODE_HARD ) //MODE_HARD
{
devState = DEV_COORD_STARTING;//Started as Zigbee Coordinator
//建网
ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,
zgDefaultStartingScanDuration, beaconOrder,
superframeOrder, false );
}
else if ( startMode == MODE_RESUME ) //MODE_RESUME
{
// Just start the coordinator
devState = DEV_COORD_STARTING;
ret = NLME_StartRouterRequest( beaconOrder, beaconOrder, false );
}
else //错误,启动模式未知
{
#if defined( LCD_SUPPORTED )
//HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
ClearScreen();
Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);
Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);
#endif
}
}
#endif // !ZDO_COORDINATOR
//#if !defined ( ZDO_COORDINATOR ) || defined( SOFT_START )
if ( logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE )
{
if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) )
{
devState = DEV_NWK_DISC; //!!!Discovering PAN's to join
#if defined( MANAGED_SCAN ) //管理扫描,由自己设定扫描参数.
ZDOManagedScan_Next();
ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC );
#else
ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
#endif
}
else if ( startMode == MODE_RESUME ) //MODE_RESUME 恢复
{
if ( logicalType == NODETYPE_ROUTER )
{
ZMacScanCnf_t scanCnf;
devState = 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
{
devState = DEV_NWK_ORPHAN; //!!!孤儿
ret = NLME_OrphanJoinRequest( zgDefaultChannelList,
zgDefaultStartingScanDuration );
}
}
else
{
#if defined( LCD_SUPPORTED )
// HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);
Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);
#endif
}
}
//#endif //!ZDO COORDINATOR || SOFT_START
if ( ret != ZSuccess )
osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
}
****************
通过参数可知路由器调用NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
执行网络发现.
而对NLME_NetworkDiscoveryRequest()的调用会产生一个回调函数ZDO_NetworkDiscoveryConfirmCB()(见主要函数说明3).
****************
ZStatus_t ZDO_NetworkDiscoveryConfirmCB( byte ResultCount,
networkDesc_t *NetworkList )
{
if ( i == ResultCount )
{
msg.hdr.status = ZDO_FAIL; // couldn't find appropriate PAN to join !
}
{
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), (byte *)&msg );
return (ZSuccess);
}
****************
由msg.hdr.status来指示网络发现是否成功,如果成功则把所发现的网络信息存在信息包msg中发往ZDAppTaskID,触发事件ZDO_NWK_DISC_CNF,看下对ZDO_NWK_DISC_CNF的处理:
****************
case ZDO_NWK_DISC_CNF:
if (devState != DEV_NWK_DISC)
{
}
#if !defined ( ZDO_COORDINATOR ) || defined ( SOFT_START ) //未编译ZDO_COORDINATOR或编译了SOFT_START
#if defined ( MANAGED_SCAN ) //管理扫描,自定义扫描参数
//如果返回的信息指示网络发现成功(hdr.status == ZDO_SUCCESS)并且网络
//发现成功次数不低于NUM_DISC_ATTEMPTS(NUM_DISC_ATTEMPTS=3)如果编译了
//管理扫描,则需3次以上成功扫描;否则需3次成功扫描.即设备至少会有3次
//初始化?
else if ( (((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->hdr.status == ZDO_SUCCESS) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
#else
else if ( (((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->hdr.status == ZDO_SUCCESS) && (zdoDiscCounter++ > NUM_DISC_ATTEMPTS) )
#endif
{
if ( devStartMode == MODE_JOIN )//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()初始化重启网络
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
}
else if ( devStartMode == MODE_REJOIN )//MODE_REJOIN
{
devState = DEV_NWK_REJOIN;
if ( NLME_ReJoinRequest() != ZSuccess )
{
//如果重加入请求不成功则执行ZDApp_NetworkInit()初始化重启网络
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
}
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
{
// The receiver is on, turn network layer polling off.
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
}
}
//如果返回的信息指示网络发现不成功或成功次数不符规定
//则执行ZDApp_NetworkInit()初始化重启网络
else
{
#if defined ( SOFT_START ) && !defined ( VIRTKEY_SOFT_START )
#if defined ( MANAGED_SCAN )
if ( (softStartAllowCoord)
&& (((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->hdr.status != ZDO_SUCCESS )
&& (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
#else
if ( (softStartAllowCoord)
&& (((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->hdr.status != ZDO_SUCCESS )
&& (zdoDiscCounter++ > NUM_DISC_ATTEMPTS) )
#endif
{
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
devStartMode = MODE_HARD;
}
else if ( continueJoining == FALSE )
{
devState = DEV_HOLD;
osal_stop_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT );
break; // Don't init
}
#endif
#if defined ( MANAGED_SCAN )
ZDApp_NetworkInit( MANAGEDSCAN_DELAY_BETWEEN_SCANS ); // ZDApp_NetworkInit()
#else
if ( continueJoining )
{
ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY
+ ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) ); // ZDApp_NetworkInit()
}
#endif
}
#endif // !ZDO_COORDINATOR
break;
****************
对事件ZDO_NWK_DISC_CNF的处理:如果网络发现成功,则执行NLME_JoinRequest()加入网络,加入不成功则执行ZDApp_NetworkInit()初始化重启网络;如果网络发现不成功,则执行ZDApp_NetworkInit()初始化重启网络.
因此路由器如果成功发现网络,则根据所获得的网络信息执行NLME_JoinRequest()加入该网络.对NLME_JoinRequest()的调用会产生一个回调函数ZDO_JoinConfirmCB(),来看下:
****************
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
{
nwkStatus = (byte)Status;
if ( Status == ZSUCCESS )
{
// LED on shows device joined
HalLedSet ( HAL_LED_3, HAL_LED_MODE_ON );
// LED off forgets HOLD_AUTO_START
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF);
if ( (devState == DEV_HOLD) )
{
// Began with HOLD_AUTO_START
devState = DEV_NWK_JOINING;
}
#if ! ( SECURE != 0 )
// Notify to save info into NV
ZDApp_NVUpdate();
#endif
}
#if defined(BLINK_LEDS)
else
HalLedSet ( HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED to show failure
#endif
// Notify ZDApp
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND, sizeof(osal_event_hdr_t), (byte*)NULL );
}
****************
函数根据返回的Status来确定设备加入网络是否成功,并作相应的灯亮来指示.最终会触发ZDAppTaskID的ZDO_NWK_JOIN_IND事件.来看下对这个事件的处理:
****************
case ZDO_NWK_JOIN_IND:
ZDApp_ProcessNetworkJoin();
break;
****************
调用了ZDApp_ProcessNetworkJoin(),来看下:
****************
#if !defined( ZDO_COORDINATOR ) || defined( SOFT_START )
//如果设备加入网络成功,则更新存储网络信息;否则初始化重启网络.
void ZDApp_ProcessNetworkJoin( void )
{
//----------------------------------
// ORPHAN//JOINING//ROUTER
//----------------------------------
if ( (devState == DEV_NWK_JOINING) ||
((devState == DEV_NWK_ORPHAN) &&
(ZDO_Config_Node_Descriptor.LogicalType == NODETYPE_ROUTER)) )
{
//-----------------------设备加入网络成功
// Result of a 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 ( SECURE != 0 )
if ( _NIB.SecurityLevel && (ZDApp_RestoreNwkKey() == false ) )
{
// wait for auth from trust center!!
devState = DEV_END_DEVICE_UNAUTH;
// Start the reset timer for MAX UNAUTH time
ZDApp_ResetTimerStart( MAX_DEVICE_UNAUTH_TIMEOUT );
}
else
#endif // SECURE
{
#if defined ( RTR_NWK )
//这种情况只有路由器
if ( devState == DEV_NWK_ORPHAN
&& ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
// Change NIB state to router for restore
_NIB.nwkState = NWK_ROUTER;
}
#endif
devState = DEV_END_DEVICE;
#if defined ( RTR_NWK )
// NOTE: first two parameters are not used, see NLMEDE.h for details
#if !defined (AUTO_SOFT_START)
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
NLME_StartRouterRequest( 0, 0, false );
}
#endif // AUTO_SOFT_START
#endif // RTR
#if defined ( ZDO_ENDDEVICE_ANNCE_GENERATE )
ZDP_EndDeviceAnnce( ZDAppNwkAddr.addr.shortAddr, saveExtAddr,
ZDO_Config_Node_Descriptor.CapabilityFlags, 0 );
#endif
}
}
//-----------------------设备加入网络不成功
else
{
//恢复网络状态
if ( (devStartMode == MODE_RESUME) && (++retryCnt >= MAX_RESUME_RETRY) )
{
if ( _NIB.nwkPanId == 0xFFFF || _NIB.nwkPanId == INVALID_PAN_ID )
devStartMode = MODE_JOIN; //原PAN_ID无效,则设置devStartMode = MODE_JOIN
else
{
devStartMode = MODE_REJOIN; //原PAN_ID有效,则设置devStartMode = MODE_REJOIN
_tmpRejoinState = true;
}
}
if ( (NLME_GetShortAddr() != INVALID_NODE_ADDR) ||
(_NIB.nwkDevAddress != INVALID_NODE_ADDR) ) //无效短地址
{
uint16 addr = INVALID_NODE_ADDR;
// Invalidate nwk addr so end device does not use in its da
ZMacSetReq( ZMacShortAddress, (byte *)&addr );
}
zdoDiscCounter = 1;
// ZDApp_NetworkInit( (uint16)
// ((NWK_START_DELAY * (osal_rand() & 0x0F)) +
// (NWK_START_DELAY * 5)) );
//初始化重启网络
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
}
//----------------------------------
// ORPHAN//REJOIN
//----------------------------------
else if ( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_REJOIN )
{
//-----------------------设备加入网络成功
// results of an orphaning attempt by this device
if (nwkStatus == ZSuccess)
{
#if ( SECURE != 0 )
ZDApp_RestoreNwkKey();
#endif
devState = DEV_END_DEVICE;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );//ZDO_STATE_CHANGE_EVT
// setup Power Manager Device
#if defined ( POWER_SAVING )
osal_pwrmgr_device( PWRMGR_BATTERY );
#endif
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
{
// The receiver is on, turn network layer polling off.
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
}
#if defined ( ZDO_ENDDEVICE_ANNCE_GENERATE )
ZDP_EndDeviceAnnce( ZDAppNwkAddr.addr.shortAddr, saveExtAddr,
ZDO_Config_Node_Descriptor.CapabilityFlags, 0 );
#endif
}
//-----------------------设备加入网络不成功
else
{
if ( (devStartMode == MODE_RESUME) && (++retryCnt >= MAX_RESUME_RETRY) )
{
if ( _NIB.nwkPanId == 0xFFFF || _NIB.nwkPanId == INVALID_PAN_ID )
devStartMode = MODE_JOIN;
else
{
devStartMode = MODE_REJOIN;
_tmpRejoinState = true;
}
}
//初始化重启网络
// setup a retry for later...
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ (osal_rand()& EXTENDED_JOINING_RANDOM_MASK)) );
}
}
else
{
// this is an error case!!
}
}
#endif
****************
ZDApp_ProcessNetworkJoin()函数功能是存储网络的关键信息.如果设备成功加入网络,则更新存储网络信息,并触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT事件;如果不成功调用ZDApp_NetworkInit()初始化重启网络.
因此如果路由器加入网络成功,则这里最终会触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT事件,看下对ZDO_STATE_CHANGE_EVT的处理:
****************
if ( events & ZDO_STATE_CHANGE_EVT )
{
ZDO_UpdateNwkStatus( devState );
// Return unprocessed events
return (events ^ ZDO_STATE_CHANGE_EVT);
}
****************
调用了ZDO_UpdateNwkStatus():、
****************
//This function will send an update message to each registered
//application endpoint/interface about a network status change.
void ZDO_UpdateNwkStatus( devStates_t state )
{
// Endpoint/Interface descriptor list.
epList_t *epDesc = epList;
byte bufLen = sizeof(osal_event_hdr_t);
osal_event_hdr_t *msgPtr;
ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.
while ( epDesc )
{
if ( epDesc->epDesc->endPoint != ZDO_EP )
{
msgPtr = (osal_event_hdr_t *)osal_msg_allocate( bufLen );
if ( msgPtr )
{
msgPtr->event = ZDO_STATE_CHANGE; // Command ID
msgPtr->status = (byte)state;
osal_msg_send( *(epDesc->epDesc->task_id), (byte *)msgPtr );
}
}
epDesc = epDesc->nextDesc;
}
}
****************
网络状态改变,这个函数会更新和发送信息通知每个注册登记过的应用终端.这里以SampleApp的路由器为例,因此会触发SampleApp_TaskID的ZDO_STATE_CHANGE事件.看下最终对ZDO_STATE_CHANGE的处理:
****************
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //获取设备当前状态
if ( (SampleApp_NwkState == DEV_ZB_COORD)
|| (SampleApp_NwkState == DEV_ROUTER)
|| (SampleApp_NwkState == DEV_END_DEVICE) )
{
// Start sending the periodic message in a regular interval.
osal_start_timerEx( SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
}
****************
最终开启了周期信息发送的定时器.
即路由器设备启动执行网络发现,发现成功则执行网络加入,加入成功则触发应用层ZDO_STATE_CHANGE事件.
3、
路由器(自启动模式)—以SampleApp的路由器为例,并假设初始化成功,网络发现成功,网络加入成功.
程序大致流程:
main()->osal_init_system()->osalInitTasks()->ZDApp_Init()-ZDOInitDevice()->ZDApp_NetworkInit->触发ZDAppTaskID的ZDO_NETWORK_INIT->ZDO_StartDevice()->NLME_NetworkDiscoveryRequest->网络发现成功ZDO_NetworkDiscoveryConfirmCB->触发ZDAppTaskID的ZDO_NWK_DISC_CNF->NLME_JoinRequest()->网络加入成功ZDO_JoinConfirmCB->触发ZDAppTaskID的ZDO_NWK_JOIN_IND->ZDApp_ProcessNetworkJoin()->触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT-> ZDO_UpdateNwkStatus->触发SampleApp_TaskID的ZDO_STATE_CHANGE->开启应用程序中发送周期信息的定时器.
4、注:
(1)自启动模式下SampleApp的终端和路由器总体流程基本一致.
(2)
以SampleApp为例,ZDO_StartDevice()函数的两个重要参数比较:
终端:
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICE
devStartMode = MODE_JOIN
路由器:
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER
devStartMode = MODE_JOIN
协调器:
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR
devStartMode = MODE_HARD
说明:
1、本文为个人学习笔记,纯属个人理解,错误不可避免,仅供参考.随时更新
2、细节基本不管,遇到问题再作分析,程序注释为个人原始注释内容,记录有些仓促.
3、欢迎交流,转载请注明出处,谢谢!
2010.7.09 XF