ZDApp_Init
函数开始的。具体的执行流程为:
Main()->osal_init_system()->osalInitTasks()->ZDApp_In
it()
。进入到
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 );
}
else
{
// Blink LED to indicate HOLD_START
HalLedBlink ( HAL_LED_4, 0, 50, 500 );
}
ZDApp_RegisterCBs();
}
ZDApp_Init
首先检测
SW1
是否被按下,如果
SW1
被按下,设备将处于
DEV_HOLD
状态,不会进入组网状态,这里我们要特别注意。如果
SW1
没有被按下,那么程序将调用
ZDOInitDevice
来开启设备。
uint8 ZDOInitDevice( uint16 startDelay )
{
uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
uint16 extendedDelay = 0;
if ( devState == DEV_HOLD )
{
// Initialize the RAM items table, in case an NV item has been updated.
zgInitItems( FALSE );
}
ZDConfig_InitDescriptors();
//devtag.071807.todo – fix this temporary solution
_NIB.CapabilityFlags = ZDO_Config_Node_Descriptor.CapabilityFlags;
#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 )
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
else
{
// Determine if NV should be restored
networkStateNV = ZDApp_ReadNetworkRestoreState();
}
if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
networkStateNV = ZDApp_RestoreNetworkState();
}
else
{
// Wipe out the network state in NV
NLME_InitNV();
NLME_SetDefaultNV();
// clear NWK key values
ZDSecMgrClearNVKeyValues();
}
#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 the security for type of device
ZDApp_SecInit( networkStateNV );
if( ZDO_INIT_HOLD_NWK_START != startDelay )
{
devState = DEV_INIT; // Remove the Hold state
// Initialize leave control logic
ZDApp_LeaveCtrlInit();
// Check leave control reset settings
ZDApp_LeaveCtrlStartup( &devState, &startDelay );
// Leave may make the hold state come back
if ( devState == DEV_HOLD )
{
// Set the NV startup option to force a “new” join.
zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
// Notify the applications
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
return ( ZDO_INITDEV_LEAVE_NOT_STARTED ); // Don’t join – (one time).
}
// Trigger the network start
ZDApp_NetworkInit( extendedDelay );
}
// set broadcast address mask to support broadcast filtering
NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags );
return ( networkStateNV );
}
在这个函数中有一段代码值得我们特别注意:
#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 )
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
。。。
#endif
我们在以前的文章里曾提到过,设备在复位之后,之前的网络信息就会丢失,那么设备将以全新的状态组建或者加入到网络中,这在实际使用过程中非常不方便。很多的应用场景中都要求设备能够在复位后仍旧按照上次入网的状态重新连接到网络中,Zstack也提供了实现该机制的方法。在工程的Options->C/C++ Complier->Preprocessor的Defined symbols中我们填入:NV_RESTORE。再回到刚才说到的代码中,程序会调用HalKeyRead(),来判断SW5的状态。如果SW5没有被按下,程序会调用ZDApp_RestoreNetworkState,取出上一次保存在flash中的网络状态信息,设备将根据这些信息重新连接到网络中;如果SW5被按下,那么即便我们使用了NV_RESTORE,程序将调用NLME_InitNV()和NLME_SetDefaultNV(),清除之前保存的网络信息,然后以全新的状态加入网络中。在完成以上操作之后,程序会调用ZDApp_NetworkInit函数,触发ZDO_NETWORK_INIT事件。
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 );
}
}