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

来源:互联网 发布:linux 用户段错误 编辑:程序博客网 时间:2024/06/01 07:14
这一讲我要详细说一下协调器的组网过程。在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 );

  }

}
0 0