【深度分析Zigbee】Zstack协议栈初窥(六):协调器的组网过程详解

  • Post author:
  • Post category:其他


这一讲我要详细说一下协调器的组网过程。在Zstack中,网络组网是从

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 );

}

}