使用的协议栈版本信息: 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 - (one time).
#if defined ( NV_RESTORE ) // Get Keypad directly to see if a reset nv is needed. // Hold down the SW_BYPASS_NV key (defined in OnBoard.h) // while booting(引导) to skip past NV Restore. if ( HalKeyRead() == SW_BYPASS_NV ) //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();/*!!!!*/
// Only delay if joining network - not restoring network state 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 data reqs. _NIB.nwkDevAddress = INVALID_NODE_ADDR; //更新 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
|