CC2530自动启动模式的流程

2019-04-13 11:12发布

    在上一篇文章中,分析了一下定义了HOLD_AUTO_START编译选项后,程序的流程,这里分析一下在没有定义这个编译选项后,程序的启动流程,也就是自动启动模式的流程。SampleApp例程为例。 ZDApp.c文件中,可以看到下面的定义: #if defined( HOLD_AUTO_START ) devStates_t devState = DEV_HOLD;  // 初始化-不会自动启动 #else   devStates_t devState = DEV_INIT;  //初始化-没有连接到任何东西 #endif     不管什么样的启动方式,都会在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;   (void)NLME_GetExtAddr();  // Load the saveExtAddr pointer. 加载IEEE地址     // 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(); //初始化ZDO条目,并设置设备的启动方式是协调器,还是别的     // 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? 是否启动设备?如果devState不是DEV_HOLD时,则启动设备,在上面的代码分析中,也可以看到,如果定义了HOLD_AUTO_START宏,则devState等于DEV_HOLD,不会启动设备。如果按下了SW_1devState也等于DEV_HOLD,也不会启动网络。也就是说有两种方式可以设置非自动启动模式,一种是通过按键,一种通过宏定义   if ( devState != DEV_HOLD )   {     ZDOInitDevice( 0 );  //在本例程中没有定义HOLD_AUTO_START所以这个会成功执行   }   else   { //如果定义了HOLD_AUTO_START,则等待延时或外部事件启动网络,并且LED4灯,也就是蓝 {MOD}的灯闪烁     // Blink LED to indicate HOLD_START     HalLedBlink ( HAL_LED_4, 0, 50, 500 );   }     ZDApp_RegisterCBs(); } /* ZDO_Init() */    其中ZDOInitDevice()函数是最重要的,也是设备的初始化。下面是ZDOInitDevice()函数的源代码。 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 //设备的断开会造成DEV_HOLD状态,这里面设置的.   ZDApp_LeaveCtrlStartup( &devState, &startDelay );     // Leave may make the hold state come back //以上两个函数设置了对设备离开时的控制,如果有延时则延时,没有则
//把设备状态设为DEV_HOLD
 //ZDO_INITDEV_LEAVE_NOT_STARTED:该设备没有在网络中,下次调用才启用.   if ( devState == DEV_HOLD )     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 )   {     networkStateNV = ZDApp_RestoreNetworkState();   }   else   { // Wipe out the network state in NV  //恢复设备先前的网络状态参数
    //设置devStartMode = MODE_RESUME
    NLME_InitNV();     NLME_SetDefaultNV();   } #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 ); }    在这里又分了两种情况,一种是定义了编译选项NV_RESTORE,另一种就是没有定义该编译选项。 下面首先看一下没有定义该选项的情况: (1)       NV_RESTORE编译选项定义     首先,判断按键HAL_KEY_SW_5是否按下,如果HAL_KEY_SW_5按键按下,则设置networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; 如果没有按下,通过调用ZDApp_ReadNetworkRestoreState()函数设置networkStateNV的值,通过读取ZCD_NV_STARTUP_OPTION项的值,来决定networkStateNV选项的值。如果这个函数的返回值为ZDO_INITDEV_RESTORED_NETWORK_STATE。则调用ZDApp_RestoreNetworkState();函数,该函数的源代码如下: uint8 ZDApp_RestoreNetworkState( void ) {   byte nvStat; #if ( SECURE != 0 )   nwkActiveKeyItems keyItems; #endif     // Initialize NWK NV items   nvStat = NLME_InitNV(); //如果设备的状态为恢复的网络状态,即ZDO_INITDEV_RESTORED_NETWORK_STATE状态,则进行这个函数进行恢复。如果短地址为0x0000则为协调器结点,然后设备逻辑设备的类型为NODETYPE_COORDINATOR,并设置devStartMode = MODE_RESUME;说明设备为恢复状态。   if ( nvStat != NV_OPER_FAILED )   {     if ( NLME_RestoreFromNV() )     {       // Are we a coordinator       ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();       if ( ZDAppNwkAddr.addr.shortAddr == 0 )       {         ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;       }       devStartMode = MODE_RESUME;     }     else       nvStat = NV_ITEM_UNINIT;   #if   ( SECURE != 0  )     nwkFrameCounterChanges = 0;     osal_memset( &keyItems, 0, sizeof( nwkActiveKeyItems ) );     osal_nv_item_init( ZCD_NV_NWKKEY, sizeof(nwkActiveKeyItems), (void *)&keyItems );     #if defined ( ZDO_COORDINATOR )     ZDApp_RestoreNwkKey();   #endif // ZDO_COORDINATOR #endif // SECURE       // The default for RxOnWhenIdle is true for RTR_NWK and false for end devices     // [setup in the NLME_RestoreFromNV()].  Change it here if you want something     // other than default.   }     if ( nvStat == ZSUCCESS )     return ( ZDO_INITDEV_RESTORED_NETWORK_STATE );   else     return ( ZDO_INITDEV_NEW_NETWORK_STATE ); } //如果networkStateNV=ZDO_INITDEV_NEW_NETWORK_STATE,则会调用下面的函数 void ZDAppDetermineDeviceType( void ) {   if ( zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE )     return;   #if defined ( SOFT_START )   if ( zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR )   {     devStartMode = MODE_HARD;     // Start as a coordinator     ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;   }   else   {     if ( zgDeviceLogicalType == ZG_DEVICETYPE_ROUTER )     {       softStartAllowCoord = FALSE;  // Don't allow coord to start 如果是路由器则不充许作为协调器启动       continueJoining = TRUE;     }     devStartMode = MODE_JOIN;     // Assume joining   } #endif // SOFT_START }     可以看到,如果编译等式SOFT_START也有定义的话,设备的类型为协调器,则会设置devStartMode = MODE_HARD;也就是说设备为开始状态。如果是不是协调器而是路由器的话,devStartMode = MODE_JOIN; 设备为重新加入的状态。 ZDOInitDevice()函数的最后,通过调用ZDApp_NetworkInit( extendedDelay );进行网络的初始化操作。 2void 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 );   } } 3)在这里设置了ZDO_NETWORK_INIT事件,在下次循环中,也就是在ZDApp_event_loop()函数中,进行处理。 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);   } ..................... } 4. ZDO_StartDevice()函数根据传递过来的值,也就是 ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR
devStartMode = MODE_HARD
且协调器编译了ZDO_COORDINATOR
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder ) {   ZStatus_t ret;     ret = ZUnsupportedMode;   #if defined(ZDO_COORDINATOR) //如果定义了编译选项ZDO_COORDINATOR   if ( logicalType == NODETYPE_COORDINATOR ) //如果逻辑设备是协调器   {     if ( startMode == MODE_HARD ) //开始启动设备     {       devState = DEV_COORD_STARTING; //建立网络       ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,                                           zgDefaultStartingScanDuration, beaconOrder,                                           superframeOrder, false );     }     else if ( startMode == 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" ); #endif     }   } #endif  // !ZDO_COORDINATOR   #if !defined ( ZDO_COORDINATOR ) || defined( SOFT_START )//如果没有定义ZDO_COORDINATOR编译选项,而是定义了SOFT_START选项的话   if ( logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE )   { //如果不是协调器,而是终端或者路由器,并且开始状态为加入或者重新加入,     if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) )     {       devState = DEV_NWK_DISC; //发现网络加入     #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 ) //如果开始的状态为恢复的话,     {       if ( logicalType == NODETYPE_ROUTER )//如果是路由器结点       {         ZMacScanCnf_t scanCnf;         devState = DEV_NWK_ORPHAN; //以孤儿结点方式加入,在ZigBee中有两种加入网络的方式还有一种是联合的方式           /* 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 );       }     }