您的位置:首页 > 理论基础 > 计算机网络

Zigbee网络设备启动—主要函数说明

2013-10-23 16:44 323 查看
使用的协议栈版本信息: ZigBee2006\ZStack-1.4.3-1.2.1
1、ZDApp_Init()及其中几个函数的说明.
(1)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();
}
****************************************
这里说明三个函数:
ZDAppCheckForHoldKey()
ZDO_Init()
ZDOInitDevice( 0 )

(1)ZDAppCheckForHoldKey()
**************************
void ZDAppCheckForHoldKey( void )
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
  //个人认为:可以直接通过读取按键来看是否需要采用HOLD_START模式
  //如果发现SW_1按下(普通按键吧)/向上(Joystick up),则设置DEV_HOLD;
  // Get Keypad directly to see if a HOLD_START is needed.
  // Hold down the SW_BYPASS_START key (see OnBoard.h)
  // while booting to avoid starting up the device.
  if ( HalKeyRead () == SW_BYPASS_START)  //HAL_KEY_SW_1
  {
    // Change the device state to HOLD on start up
    devState = DEV_HOLD;
  }
#endif // HAL_KEY
}
参见基本问题说明3.
*************************
(2)、ZDO_Init()
*************************
void ZDO_Init( void )
{
  /*
  //REFLECTOR如果定义了这个编译选项则使用“源绑定”,
  In the Zigbee 2006 release,the binding mechanism is implemented in
  all devices and is called source binding.绑定机制可以在所有设备中实现,
  04版的只能在协调器中实现.*/
  // Initialize ZD items
  #if defined ( REFLECTOR )
  ZDO_EDBind = NULL;
  #endif

  // Setup the device - type of device to create.
  ZDODeviceSetup();
}
*************************
看下ZDODeviceSetup(),具体见各节点启动流程记录.
*************************
//Call set functions depending on the type of device compiled.
//根据编译选项来设置;比如simpleApp中的灯节点,预编译了ZDO_COORDINATOR和
//REFLECTOR和SOFT_START,因此会根据这些来选择开启一些函数功能.
static void ZDODeviceSetup( void )
{
#if defined( ZDO_COORDINATOR ) //编译了ZDO_COORDINATOR
  NLME_CoordinatorInit();
#endif

#if defined ( REFLECTOR ) //编译了REFLECTOR
  #if defined ( ZDO_COORDINATOR ) //编译了REFLECTOR且编译了ZDO_COORDINATOR
    APS_ReflectorInit( APS_REFLECTOR_PUBLIC );
  #else //编译了REFLECTOR且编译了路由器或终端
    APS_ReflectorInit( APS_REFLECTOR_PRIVATE ); //路由器/终端
  #endif
#endif

    //没有编译ZDO_COORDINATOR或者编译了SOFT_START
#if !defined( ZDO_COORDINATOR ) || defined( SOFT_START )
  NLME_DeviceJoiningInit();
#endif
}
*************************
(3)、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
  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 );
}
*************************
看下五个函数:
ZDApp_LeaveCtrlInit()
ZDApp_ReadNetworkRestoreState()
ZDApp_RestoreNetworkState()
ZDAppDetermineDeviceType()
ZDApp_NetworkInit( extendedDelay )

(3.1)ZDApp_LeaveCtrlInit()
*************************
void ZDApp_LeaveCtrlInit( void )
{
  uint8 status;


  // Initialize control state
  ZDApp_LeaveCtrl = ZDAPP_LEAVE_CTRL_INIT;  //0

  //初始化一个NV条目.这个函数检查一个NV条目的存在与否.
  //如果不存在,它将被建立和初始化随着数据一起传给函数,
  //这个函数必须在调用osal_nv_read() or osal_nv_write()之前被调用
  status = osal_nv_item_init( ZCD_NV_LEAVE_CTRL,   //用户定义的条目ID
                              sizeof(ZDApp_LeaveCtrl),                 //条目的大小
                              &ZDApp_LeaveCtrl );                         //指向条目初始化的数据

  if ( status == ZSUCCESS ) //这个NV条目存在,则把这个条目值读出来,ZDApp_LeaveCtrl指向它
  {
    // Read saved control
    osal_nv_read( ZCD_NV_LEAVE_CTRL,  //用户定义的项目ID
                  0,                                                  //Memory offset into item in bytes.
                  sizeof( uint8 ),                             //条目长度
                  &ZDApp_LeaveCtrl);                  //数据保存缓冲区指针
  }
}
*************************
(3.2)ZDApp_ReadNetworkRestoreState()
如果预编译了NV_RESTORE并且没有手工设置避开NV存储机制,则通过这个函数来判断是否需要恢复设备原先的网络状态.
*************************
//返回要么是新的网络状态;要么是恢复的网络状态
//返回默认为恢复的状态,但如果从读取ZCD_NV_STARTUP_OPTION这个NV条目中
//读取出来的设备网络状态是ZCD_STARTOPT_DEFAULT_NETWORK_STATE,则返回
//新的网络状态ZDO_INITDEV_NEW_NETWORK_STATE
uint8 ZDApp_ReadNetworkRestoreState( void )
{                        //设备的网络状态为恢复的网络状态
  uint8 networkStateNV = ZDO_INITDEV_RESTORED_NETWORK_STATE;

  // Look for the New Network State option.  默认的网络状态
  if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_NETWORK_STATE )
  {
    //网络状态初始化,即新的网络状态,可能意味着没有任何网络状态恢复
    networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
  }

  return ( networkStateNV );
}
*************************
(3.3)ZDApp_RestoreNetworkState()
如果3.2的函数得到的networkStateNV为恢复的网络状态,则通过这个函数来读取存储在NV里的先前的网络状态.
*************************
uint8 ZDApp_RestoreNetworkState( void )
{
  …………

  // Initialize NWK NV items
  nvStat = NLME_InitNV();

  if ( nvStat != NV_OPER_FAILED )
  {
    if ( NLME_RestoreFromNV() )
    {
      // 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!!!!!!!!
    }
    else
      nvStat = NV_ITEM_UNINIT;

   …………
  if ( nvStat == ZSUCCESS )
    return ( ZDO_INITDEV_RESTORED_NETWORK_STATE );//说明设备的网络状态已经恢复
  else
    return ( ZDO_INITDEV_NEW_NETWORK_STATE );
}
*************************
(3.4)ZDAppDetermineDeviceType()
如果设备的网络状态为新的网络状态(第一种情况:未编译NV_RESTORE则在ZDOInitDevice()开头初始化为ZDO_INITDEV_NEW_NETWORK_STATE;第二种情况:编译了NV_RESTORE但ZDApp_ReadNetworkRestoreState()得到的设备网络状态为ZDO_INITDEV_NEW_NETWORK_STATE,即不能恢复或无状态恢复.).这个函数仅适用于编译了SOFT_START的设备,不支持终端设备.比如对于自动启动模式的SampleApp,没有编译SOFT_START.因此本函数对其没作用.具体见各类型设备启动流程.
*************************

 * @fn      ZDAppDetermineDeviceType()
 *
 * @brief   Determines the type of device to start.  Right now
 *          this only works with the SOFT_START feature.  So it doesn't
 *          support the end device type.
 *          //终端逻辑类型只能作为终端
 */
//像simpleApp这个例子中,灯节点和中心收集节点都同时预编译了
//SOFT_START和HOLD_AUTO_START;而开关节点和传感器节点都只预编译了
//HOLD_AUTO_START;
//开关节点和传感器节点无论按哪个键都是作为终端设备启动的
//而灯节点和中心收集节点可以选择作为协调器或路由器.
void ZDAppDetermineDeviceType( void )
{
  /*
  像simpleApp中灯节点和中心收集节点都编译了SOFT_START,
  zgDeviceLogicalType在ZGlobals.h中被初始化为ZG_DEVICETYPE_SOFT.而像
  开关节点和传感器节点没有编译SOFT_START,则zgDeviceLogicalType被初始化为
  ZG_DEVICETYPE_ENDDEVICE.之前卡在这里很长时间,因为像灯节点和中心收集节点
  编译过SOFT_START,那zgDeviceLogicalType不就等于ZG_DEVICETYPE_SOFT,最终在
  这个函数里也只能执行devStartMode = MODE_JOIN这一句,这与灯节点和中心收集
  节点可以通过按键来选择作为协调器或路由器不符,纠结了很久,最后才发现,在按键
  选择设备的逻辑类型后,会把这个逻辑类型值写入NV条目ZCD_NV_LOGICAL_TYPE,而
  ZDO全局变量zgDeviceLogicalType等于NV条目ZCD_NV_LOGICAL_TYPE的值,通过按键
  选择逻辑类型会改变zgDeviceLogicalType的值.比如灯节点按K1选择设备的逻辑类型
  为协调器ZG_DEVICETYPE_COORDINATOR,写入NV条目ZCD_NV_LOGICAL_TYPE存储,则此时zgDeviceLogicalType的值即为  ZG_DEVICETYPE_COORDINATOR!!!见基本问题说明5.
  */

  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
}
*************************
(3.5)ZDApp_NetworkInit( extendedDelay )
函数设置触发事件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 );  //不需延时
  }
}
*************************

****************************************
2、ZDO_StartDevice()
ZDApp_event_loop()对事件ZDO_NETWORK_INIT处理如下:
*************************
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_Config_Node_Descriptor.LogicalType和devStartMode,
ZDO_Config_Node_Descriptor.LogicalType的初始化见基本问题说明6.devStartMode的初始化见4.但两个参数的值可以通过函数(3.3)ZDApp_RestoreNetworkState()[如果编译了NV_RESTORE]和函数(3.4)ZDAppDetermineDeviceType()来改变.
*************************
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  //错误,启动模式未知
    {
      …………
    }
  }
#endif  // !ZDO_COORDINATOR


  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 )
      {
        …………
        nwk_ScanJoiningOrphan(&scanCnf);

        ret = ZSuccess;
      }
      else
      {
        devState = DEV_NWK_ORPHAN;  //孤儿
        ret = NLME_OrphanJoinRequest( zgDefaultChannelList,
                                      zgDefaultStartingScanDuration );
      }
    }
    else
    {
      …………
    }
  }
  …………
}
*************************

3、协调器建网,路由器/终端入网的回调函数
(1)ZDO_NetworkFormationConfirmCB():协调器建立网络请求的回调函数
 * @brief       This function reports the results of the request to
 *              initialize a coordinator in a network.
 *
 * @param       Status - Result of NLME_NetworkFormationRequest()

(2)ZDO_StartRouterConfirmCB():作为路由器启动请求的回调函数
 * @brief       This function reports the results of the request to
 *              start functioning as a router in a network.
 *
 * @param       Status - Result of NLME_StartRouterRequest()

(3)ZDO_JoinConfirmCB():路由器/终端加入网络请求的回调函数
 * @brief       This function allows the next hight layer to be notified
 *              of the results of its request to join itself or another
 *              device to a network.
 *
 * @param       Status - Result of NLME_JoinRequest()

(4) ZDO_NetworkDiscoveryConfirmCB():路由器/终端发现网络请求的回调函数
 * @fn          ZDO_NetworkDiscoveryConfirmCB
 *
 * @brief       This function returns a choice of PAN to join.
 *
 * @param       ResultCount - Number of routers discovered
 * @param       NetworkList - Pointer to list of network descriptors


四种回调函数会分别触发ZDAppTaskID相应事件:
ZDO_NetworkFormationConfirmCB(): osal_set_event( ZDAppTaskID, ZDO_NETWORK_START );
ZDO_StartRouterConfirmCB():osal_set_event( ZDAppTaskID, ZDO_ROUTER_START );
ZDO_JoinConfirmCB():ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND, sizeof                                   (osal_event_hdr_t), (byte*)NULL );
ZDO_NetworkDiscoveryConfirmCB(): ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof                                 (ZDO_NetworkDiscoveryCfm_t), (byte *)&msg );

参照上面ZDO_StartDevice()函数,可以看到相应功能的请求函数.
回调函数具体调用流程参见种类型设备的启动流程.

 
说明:
1、本文为个人学习笔记,纯属个人理解,错误不可避免,仅供参考.随时更新!
2、细节基本不管,遇到问题再作分析,程序注释为个人原始注释内容,记录有些仓促!
3、欢迎交流,转载请注明出处,谢谢!                                                       

                                                                                                       2010.7.09  ~XF
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: