zoukankan      html  css  js  c++  java
  • SimpleApp例子中网络的形成过程(转)

      每个设备都有一组被配置的参数,整个配置参数在代码中已经定义了默认值(在f8wConfig.cfg)中,在同个网络中,所有设备的“网络细节”配置参数(如PANIDChannel等)应该被设置成一样的值。每个设备的“设备细节”配置参数(CoordinatorRouter EndDevice等)可能配置为不同的值。
        但是,ZCD_NV_LOGICAL_TYPE必须被设置,确保①有正确的一个设备作为协调器被配置②所有电池供电的设备作为终端设备被配置。一旦这些工作都完成,这个设备就可以以任意方式启动,协调器设备将建立网络,其他设备将发现和加入这个网络。
        协调器将扫描所有被ZCD_NV_CHANLIST参数制定的通道和选择1个最小能量的通道,如果有2个以上的最小能量通道,则协调器选择在ZigBee网络中存在的序号最小的通道,协调器将选择用ZCD_NV_PANID参数指定的网络ID,路由器和终端设备将扫描用ZCD_NV_CHANLIST配置参数指定的通道和试图发现IDZCD_NV_PANID参数指定的网络。
    (1)  协调器格式化网络
        协调器将扫描DEFAULT_CHANLIST指定的通道,最后在其中之一上形成网络,f8wConfig.cfg文件中,可以看到其定义如下:
    -DDEFAULT_CHANLIST=0x00000800  // 11 - 0x0B
    还可以查看到PANID的定义:
    -DZDAPP_CONFIG_PAN_ID=0xFFFF
        如果 ZDAPP_CONFIG_PAN_ID被定义为0xFFFF,那么协调器将根据自身的IEEE地址建立一个随机的PAN ID,如果ZDAPP_CONFIG_PAN_ID没有被定义为0xFFFF,那么协调器建立网络的PAN ID将由ZDAPP_CONFIG_PAN_ID指定。
    可以在下面的函数发现PID的判断
    ZStatus_t ZDO_NetworkDiscoveryConfirmCB( byte ResultCount,
                                             networkDesc_t *NetworkList )
    {
    ...................
    for ( i = 0; i < ResultCount; i++, pNwkDesc = pNwkDesc->nextDesc )
        {
          if ( zgConfigPANID != 0xFFFF )
          {
            // PAN Id is preconfigured. check if it matches
            // only 14 bits of pan id is used
            if ( pNwkDesc->panId != ( zgConfigPANID & 0x3FFF ) )
              continue;
          }
    .......................
    }
    当所有的参数配置好后,可以调用下面的函数来格式化网络。
    ZStatus_t NLME_NetworkFormationRequest( uint16 PanId, uint32 ScanChannels,
                                          byte ScanDuration, byte BeaconOrder,
                                          byte SuperframeOrder,
    byte BatteryLifeExtension );
    (2) 路由器和终端设备加入网络
        路由器和终端设备启动后,将扫描DEFAULT_CHANLIST指定的频道,如果ZDAPP_CONFIG_PAN_ID没有被定义为0xFFFF,则路由器将强制加入ZDAPP_CONFIG_PAN_ID定义的网络。
    发现一个网络可以调用下面的函数
    ZStatus_t NLME_NetworkDiscoveryRequest( uint32 ScanChannels, byte scanDuration);
         该函数要求网络层去发现邻居路由器节点,并且应该在进行网络扫描之前调用,扫描的结果由ZDO_NetworkDiscoveryConfirmCB()函数返回。其中:
    ScanChannels-----准备扫描的信道号(信道号的范围为11~26,也就是2.4GHz频段有效)
    scanDuration--------规定了在新的网开始建立之前,其他网络可能扫描每个信道的时间其长度。
    发现网络存在后,就调用下面的函数加入网络
    ZStatus_t NLME_OrphanJoinRequest( uint32 ScanChannels, byte ScanDuration );
    该函数要求网络层以孤节点的形式加入网络,函数调用的结果由ZDO_JoinConfirmCB()返回。其中:
    ScanChannels------准备扫描的信道号
    scanDuration--------规定了在新的网开始建立之前,其他网络可能扫描每个信道的时间其长度。
    (3) 实际上,ZigBee设备启动时不直接调用上面的三个函数,而是通过调用ZDO_StartDevice()函数来启动设备。当sapi_Init()函数的最后,调用osal_set_event(task_id,ZB_ENTRY_EVENT);函数,触发ZB_ENTRY_EVENT事件后,ZCD_NV_STARTUP_OPTION被设置为ZCD_STARTOPT_AUTO_START后,在zb_HandleKeys()函数中,也就是按下SW1键后。会在SAPI_ProcessEvent( byte task_id, UINT16 events )函数中执行下面的语句。
    if ( events & ZB_ENTRY_EVENT )
      {
        uint8 startOptions;
        // Give indication to application of device startup
        zb_HandleOsalEvent( ZB_ENTRY_EVENT );
     
        // LED off cancels HOLD_AUTO_START blink set in the stack
        HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);
     
        zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
        if ( startOptions & ZCD_STARTOPT_AUTO_START )
        {
          zb_StartRequest();
        }
        else
        {
          // blink leds and wait for external input to config and restart
          HalLedBlink(HAL_LED_2, 0, 50, 500);
        }
        return (events ^ ZB_ENTRY_EVENT );
      }
    下面是zb_StartRequest();函数的源代码
    void zb_StartRequest()
    {
      uint8 logicalType;
      // Start the device
      // start delay = min(NWK_START_DELAY, zgStartDelay) + rand() - only for fresh start, not restore
      if ( zgStartDelay < NWK_START_DELAY )
        zgStartDelay = 0;
      else
        zgStartDelay -= NWK_START_DELAY;
     
      // check that bad combinations of compile flag definitions and device type
      //读取设备的逻辑设备
      zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
       if (  ( logicalType > ZG_DEVICETYPE_ENDDEVICE ) || ...... )//判断设备配置是否正确
       {
         SAPI_SendCback( SAPICB_START_CNF, ZInvalidParameter, 0 );//配置错误
       }
       else
       {
         ZDOInitDevice(zgStartDelay);
       }
      return;
    }
        设备打开电源之后,由于还没有形成网络,所以经过设备逻辑类型的判断后,程序会跳转到ZDOInitDevice(zgStartDelay);下面是ZDOInitDevice(zgStartDelay);的程序定义。
     
    uint8 ZDOInitDevice( uint16 startDelay )
    {
      ................................... 
    #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 决定NV是否应该被重新载入
        networkStateNV = ZDApp_ReadNetworkRestoreState();
      }
     
      if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE )
      {
        networkStateNV = ZDApp_RestoreNetworkState();
      }
      else
      {
        // Wipe out the network state in NV
        NLME_InitNV();//清除NV中的网络状态
        NLME_SetDefaultNV();
      }
    #endif
      if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE )
      {
        ZDAppDetermineDeviceType();
        // 加入网络的时延
        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_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 );
      }
    }
        而ZDO_NETWORK_INIT事件的处理函数位于Z-Stack应用层的任务事件处理函数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);
      }
     
    .........................................
      return 0;
    }
        其实在ZDO_StartDevice()函数中,分别调用了NLME_NetworkFormationRequest(),NLME_NetworkDiscoveryRequestNLME_OrphanJoinRequest函数。所以它会自动启动设备,并根据类型的不同做相应的工作,用户可以完全不用关心这些工作,而全部交给Z-Stack来完成。
    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 )
        {
          devState = DEV_COORD_STARTING;
          ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,
                                              zgDefaultStartingScanDuration, beaconOrder,
                                              superframeOrder, false );
        }
       ...................................
     
    #if !defined ( ZDO_COORDINATOR ) || defined( 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;
     
            /* 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 );
          }
        }
        else
        {
    #if defined( LCD_SUPPORTED )
          HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
    #endif
        }
      }
    #endif  //!ZDO COORDINATOR || SOFT_START
     
      if ( ret != ZSuccess )
        osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
    }
  • 相关阅读:
    hdu 4614 线段树 二分
    cf 1066d 思维 二分
    lca 最大生成树 逆向思维 2018 徐州赛区网络预赛j
    rmq学习
    hdu 5692 dfs序 线段树
    dfs序介绍
    poj 3321 dfs序 树状数组 前向星
    cf 1060d 思维贪心
    【PAT甲级】1126 Eulerian Path (25分)
    【PAT甲级】1125 Chain the Ropes (25分)
  • 原文地址:https://www.cnblogs.com/zhangleiccst/p/2431951.html
Copyright © 2011-2022 走看看