TI zstack 建網和入網過程簡介

zigbee一般可以分爲協調器,路由和終端幾個類型。首先由協調器建立網絡,然後路由和終端加入網絡。

現在根據TI的zigbee工程簡單分析的建網入網的代碼流程。

        協調器建網:

1.

int main( void )
{
...........

// Initialize the operating system 系統初始化
osal_init_system();

...........
return 0; // Shouldn't get here.
} // main()


2.

uint8 osal_init_system( void )
{
.............

// Initialize the system tasks. 任務初始化
osalInitTasks();

..........
return ( SUCCESS );
}


3.

void osalInitTasks( void )
{
uint8 taskID = 0;

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

macTaskInit( taskID++ );
nwk_init( taskID++ );
Hal_Init( taskID++ );
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_Init( taskID++ );
#endif
ZDApp_Init( taskID++ );//ZDAPP層初始化
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_Init( taskID++ );
#endif
SerialApp_Init( taskID );
}

4.
void ZDApp_Init( uint8 task_id )
{
  // Save the task ID
  ZDAppTaskID = task_id;

  // Initialize the ZDO global device short address storage
  ZDAppNwkAddr.addrMode = Addr16Bit;
  ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR;
  (void)NLME_GetExtAddr();  // Load the saveExtAddr pointer.

  // Check for manual "Hold Auto Start"
  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

  // Start the device?
  if ( devState != DEV_HOLD )//初始值爲DEV_INIT
  {
    ZDOInitDevice( 0 );
  }
  else
  {
    ZDOInitDevice( ZDO_INIT_HOLD_NWK_START );
    // Blink LED to indicate HOLD_START
    HalLedBlink ( HAL_LED_4, 0, 50, 500 );
  }

  // Initialize the ZDO callback function pointers zdoCBFunc[]
  ZDApp_InitZdoCBFunc();

  ZDApp_RegisterCBs();
} /* ZDApp_Init() */


5.
uint8 ZDOInitDevice( uint16 startDelay )
{
  ..........

  if( ZDO_INIT_HOLD_NWK_START != startDelay )
  {
    ..........

    // Trigger the network start 網路初始化
    ZDApp_NetworkInit( extendedDelay );
  }

  // set broadcast address mask to support broadcast filtering
  NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags );

  return ( networkStateNV );
}

6.
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消息到ZDAPP層
  }
}

7.
UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
{
  uint8 *msg_ptr;

  ........

  if ( events & ZDO_NETWORK_INIT )
  {
    // Initialize apps and start the network
    devState = DEV_INIT;
    osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );

    //設備啓動函數 參數:設備邏輯類型,啓動模式,信標時間,超幀長度
    ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,
                     DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );


    // Return unprocessed events
    return (events ^ ZDO_NETWORK_INIT);
  }

  .........
}

8.
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
  ......

  ret = ZUnsupportedMode;

  if ( ZG_BUILD_COORDINATOR_TYPE && logicalType == NODETYPE_COORDINATOR )//協調器部分
  {
    if ( startMode == MODE_HARD )
    {
      devState = DEV_COORD_STARTING;
      //利用NLME_NetworkFormationRequest()向網絡層發送建網請求,執行後會返回信道到ZDO_NetworkFormationConfirmCB()
      ret = NLME_NetworkFormationRequest( zgConfigPANID, zgApsUseExtendedPANID, zgDefaultChannelList,
                                          zgDefaultStartingScanDuration, beaconOrder,
                                          superframeOrder, false );

    }
    else if ( startMode == MODE_RESUME )
    {
      // Just start the coordinator
      devState = DEV_COORD_STARTING;
      ret = NLME_StartRouterRequest( beaconOrder, beaconOrder, false );
    }
    else
    {
#if defined( LCD_SUPPORTED )
      HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
#endif
    }
  }

 ......
  }

  if ( ret != ZSuccess )
  {
    osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
  }
}

9.
void ZDO_NetworkFormationConfirmCB( ZStatus_t Status )
{
  nwkStatus = (byte)Status;

  ......

  osal_set_event( ZDAppTaskID, ZDO_NETWORK_START );//發送ZDO_NETWORK_START消息到ZDAPP層
}

10.
UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
{
  uint8 *msg_ptr;

  ......

  if ( ZSTACK_ROUTER_BUILD )
  {
    if ( events & ZDO_NETWORK_START )
    {
      ZDApp_NetworkStartEvt();//網絡啓動事件


      // Return unprocessed events
      return (events ^ ZDO_NETWORK_START);
    }

    if ( events & ZDO_ROUTER_START )
    {
      if ( nwkStatus == ZSuccess )
      {
        if ( devState == DEV_END_DEVICE )
          devState = DEV_ROUTER;

        osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
      }
      else
      {
        // remain as end device!!
      }
      osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );

      // Return unprocessed events
      return (events ^ ZDO_ROUTER_START);
    }
  }

  ......
}

11.
void ZDApp_NetworkStartEvt( void )
{
  if ( nwkStatus == ZSuccess )
  {
    // Successfully started a ZigBee network
    if ( devState == DEV_COORD_STARTING )
    {
      devState = DEV_ZB_COORD;
    }

    osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
    osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );//發送ZDO_STATE_CHANGE_EVT消息到ZDAPP層
  }
  else
  {
    // Try again with a higher energy threshold !!
    if ( ( NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT ) < 0xff )
    {
      NLME_SetEnergyThreshold( (uint8)(NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT) );
      osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
    }
    else
    {
      // Failed to start network. Enter a dormant state (until user intervenes)
      devState = DEV_INIT;
      osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
    }
  }
}

至此協調器網絡建立完成





路由和終端入網:
前1-7步和協調器建網相同
8.
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
  ......

  if ( ZG_BUILD_JOINING_TYPE && (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
      //利用NLME_NetworkDiscoveryRequest()向網絡層發送發現網絡請求,執行後會返回信道到ZDO_NetworkDiscoveryConfirmCB()
      //zgDefaultChannelList在f8wConfig.cfg中定義
      ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
    #if defined ( ZIGBEE_FREQ_AGILITY )
      if ( !( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE ) &&
            ( ret == ZSuccess ) && ( ++discRetries == 4 ) )
      {
        // For devices with RxOnWhenIdle equals to FALSE, any network channel
        // change will not be recieved. On these devices or routers that have
        // lost the network, an active scan shall be conducted on the Default
        // Channel list using the extended PANID to find the network. If the
        // extended PANID isn't found using the Default Channel list, an scan
        // should be completed using all channels.
        zgDefaultChannelList = MAX_CHANNELS_24GHZ;
      }
    #endif // ZIGBEE_FREQ_AGILITY
    #if defined ( ZIGBEE_COMMISSIONING )
      if (startMode == MODE_REJOIN && scanCnt++ >= 5 )
      {
        // When ApsUseExtendedPanID is commissioned to a non zero value via
        // application specific means, the device shall conduct an active scan
        // on the Default Channel list and join the PAN with the same
        // ExtendedPanID. If the PAN is not found, an scan should be completed
        // on all channels.
        // When devices rejoin the network and the PAN is not found from
        zgDefaultChannelList = MAX_CHANNELS_24GHZ;
      }
    #endif // ZIGBEE_COMMISSIONING
  #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
    }
  }

  if ( ret != ZSuccess )
  {
    osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
  }
}

9.
ZStatus_t ZDO_NetworkDiscoveryConfirmCB(uint8 status)
{
  osal_event_hdr_t msg;

  // If Scan is initiated by ZDO_MGMT_NWK_DISC_REQ
  // Send ZDO_MGMT_NWK_DISC_RSP back
#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
  if ( zdappMgmtNwkDiscReqInProgress )
  {
    zdappMgmtNwkDiscReqInProgress = false;
    ZDO_FinishProcessingMgmtNwkDiscReq();
  }
  else
#endif
  {
    // Pass the confirm to another task if it registers the callback
    // Otherwise, pass the confirm to ZDApp.
    if (zdoCBFunc[ZDO_NWK_DISCOVERY_CNF_CBID] != NULL )
    {
      zdoCBFunc[ZDO_NWK_DISCOVERY_CNF_CBID]( (void*)&status );
    }
    else
    {
      // Otherwise, send scan confirm to ZDApp task to proceed
      msg.status = ZDO_SUCCESS;
      //將ZDO_NWK_DISC_CNF消息發送到ZDAPP層,由ZDApp_ProcessOSALMsg()處理
      ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(osal_event_hdr_t), (uint8 *)&msg );
    }
  }
  return (ZSuccess);
}  // ZDO_NetworkDiscoveryConfirmCB

10.
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
  // Data Confirmation message fields
  uint8 sentEP;       // This should always be 0
  uint8 sentStatus;
  afDataConfirm_t *afDataConfirm;
  uint8 tmp;

  switch ( msgPtr->event )
  {
   ......

    case ZDO_NWK_DISC_CNF:
      if (devState != DEV_NWK_DISC)
        break;

      if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
      {
        // Process the network discovery scan results and choose a parent
        // device to join/rejoin itself
        networkDesc_t *pChosenNwk;
        if ( ( (pChosenNwk = ZDApp_NwkDescListProcessing()) != NULL ) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
        {
          if ( devStartMode == MODE_JOIN )
          {
            devState = DEV_NWK_JOINING;

            ZDApp_NodeProfileSync( pChosenNwk->stackProfile);
            //請求加入網絡NLME_JoinRequest(),執行結果返回到ZDO_JoinConfirmCB()
            if ( NLME_JoinRequest( pChosenNwk->extendedPANID, pChosenNwk->panId,
                                  pChosenNwk->logicalChannel,
                                  ZDO_Config_Node_Descriptor.CapabilityFlags,
                                  pChosenNwk->chosenRouter, pChosenNwk->chosenRouterDepth ) != ZSuccess )

            {
              ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
                                          + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
            }
          } // if ( devStartMode == MODE_JOIN )
          else if ( devStartMode == MODE_REJOIN )
          {
            devState = DEV_NWK_REJOIN;

            // Before trying to do rejoin, check if the device has a valid short address
            // If not, generate a random short address for itself
            if ( _NIB.nwkDevAddress == INVALID_NODE_ADDR )
            {
              _NIB.nwkDevAddress = osal_rand();
              ZMacSetReq( ZMacShortAddress, (byte*)&_NIB.nwkDevAddress );
            }

            if ( ZG_SECURE_ENABLED )
            {
              ZDApp_RestoreNwkKey();
            }

            // Check if the device has a valid PanID, if not, set it to the discovered Pan
            if ( _NIB.nwkPanId == INVALID_PAN_ID )
            {
              _NIB.nwkPanId = pChosenNwk->panId;
              ZMacSetReq( ZMacPanId, (byte*)&(_NIB.nwkPanId) );
            }

            tmp = true;
            ZMacSetReq( ZMacRxOnIdle, &tmp ); // Set receiver always on during rejoin
            if ( NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel) != ZSuccess )
            {
              ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
                                          + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
            }
          } // else if ( devStartMode == MODE_REJOIN )

          if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
          {
            // The receiver is on, turn network layer polling off.
            NLME_SetPollRate( 0 );
            NLME_SetQueuedPollRate( 0 );
            NLME_SetResponseRate( 0 );
          }
          else
          {
            if ( (ZG_SECURE_ENABLED) && (devStartMode == MODE_JOIN) )
            {
              ZDApp_SavedPollRate = zgPollRate;
              NLME_SetPollRate( zgRejoinPollRate );
            }
          }
        }
        else
        {
          if ( continueJoining )
          {
    #if defined ( MANAGED_SCAN )
            ZDApp_NetworkInit( MANAGEDSCAN_DELAY_BETWEEN_SCANS );
    #else
            zdoDiscCounter++;
            ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY
                  + ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) );
    #endif
          }
        }
      }
      break;

    ......

}

11.
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
{
  (void)PanId;  // remove if this parameter is used.

  ......

  // Notify ZDApp 發送消息給ZDAPP層,在ZDApp_ProcessOSALMsg()中處理
  ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND, sizeof(osal_event_hdr_t), (byte*)NULL );

}

12.
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
  // Data Confirmation message fields
  uint8 sentEP;       // This should always be 0
  uint8 sentStatus;
  afDataConfirm_t *afDataConfirm;
  uint8 tmp;

  switch ( msgPtr->event )
  {
   ......

    case ZDO_NWK_JOIN_IND:
      if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
      {
        //調用ZDApp_ProcessNetworkJoin
        ZDApp_ProcessNetworkJoin();
      }
      break;

    ......
  }

}

13.
此處分爲路由和終端兩種情況
終端:
void ZDApp_ProcessNetworkJoin( void )
{
  if ( (devState == DEV_NWK_JOINING) ||
      ((devState == DEV_NWK_ORPHAN)  &&
       (ZDO_Config_Node_Descriptor.LogicalType == NODETYPE_ROUTER)) )
  {
    // Result of a Join attempt by this device.
    if ( nwkStatus == ZSuccess )
    {
      //發送ZDO_STATE_CHANGE_EVT消息給ZDAPP層
      osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );

    ......
    }
  }
  ......
}

路由:
void ZDApp_ProcessNetworkJoin( void )
{
  ......
  else if ( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_REJOIN )
  {
    ......

      if ( ZSTACK_ROUTER_BUILD )
      {
        // NOTE: first two parameters are not used, see NLMEDE.h for details
        if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
        {
         //路由啓動請求,執行結果返回到ZDO_StartRouterConfirmCB()
          NLME_StartRouterRequest( 0, 0, false );
        }
      }

      ZDApp_AnnounceNewAddress();
    }
    ......
}

void ZDO_StartRouterConfirmCB( ZStatus_t Status )
{
  ......

  //發送ZDO_ROUTER_START消息給ZDAPP層
  osal_set_event( ZDAppTaskID, ZDO_ROUTER_START );
}

UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
{
  uint8 *msg_ptr;

  ......

    if ( events & ZDO_ROUTER_START )
    {
      if ( nwkStatus == ZSuccess )
      {
        if ( devState == DEV_END_DEVICE )
          devState = DEV_ROUTER; //設備狀態改變

        osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
      }
      else
      {
        // remain as end device!!
      }
      //發送ZDO_STATE_CHANGE_EVT消息給ZDAPP層
      osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );

      // Return unprocessed events
      return (events ^ ZDO_ROUTER_START);
    }
  

  ......
}

14.
UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
{
  uint8 *msg_ptr;

  ......

  if ( events & ZDO_STATE_CHANGE_EVT )//設備加入網絡後,身份確定產生一個網絡狀態改變事件
  {
    ZDO_UpdateNwkStatus( devState );//更新網絡狀態

    // At start up, do one MTO route discovery if the device is a concentrator
    if ( zgConcentratorEnable == TRUE )
    {
      // Start next event
      osal_start_timerEx( NWK_TaskID, NWK_MTO_RTG_REQ_EVT, 100 );
    }

    // Return unprocessed events
    return (events ^ ZDO_STATE_CHANGE_EVT);
  }

  ......
}

15.
void ZDO_UpdateNwkStatus(devStates_t state)
{
  epList_t *pItem = epList;

  while (pItem != NULL)
  {
    if (pItem->epDesc->endPoint != ZDO_EP)
    {
      zdoSendStateChangeMsg(state, *(pItem->epDesc->task_id));
    }

    pItem = pItem->nextDesc;
  }
#if defined MT_ZDO_CB_FUNC
  zdoSendStateChangeMsg(state, MT_TaskID);//發送狀態改變信息到ZDO層
#endif

  ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();//獲取16位短地址
  (void)NLME_GetExtAddr();  // Load the saveExtAddr pointer.
}

16.
static void zdoSendStateChangeMsg(uint8 state, uint8 taskId)
{
  osal_event_hdr_t *pMsg = (osal_event_hdr_t *)osal_msg_find(taskId, ZDO_STATE_CHANGE);

  if (NULL == pMsg)
  {
    if (NULL == (pMsg = (osal_event_hdr_t *)osal_msg_allocate(sizeof(osal_event_hdr_t))))
    {
      // Upon failure to notify any EndPoint of the state change, re-set the ZDO event to
      // try again later when more Heap may be available.
      osal_set_event(ZDAppTaskID, ZDO_STATE_CHANGE_EVT);//狀態未改變則重新執行一次
    }
    else
    {
      pMsg->event = ZDO_STATE_CHANGE;
      pMsg->status = state;

      (void)osal_msg_send(taskId, (uint8 *)pMsg);//狀態改變後到MT_TASK.C中執行MT_ProcessIncomingCommand
    }
  }
  else
  {
    // Modify in place the status of an existing ZDO_STATE_CHANGE message to the EndPoint.
    pMsg->status = state;
  }
}

17.
static void MT_ProcessIncomingCommand( mtOSALSerialData_t *msg )
{
  uint8 len, *msg_ptr = msg->msg;

 ......
#ifdef MT_ZDO_CB_FUNC
    case ZDO_STATE_CHANGE:
      MT_ZdoStateChangeCB((osal_event_hdr_t *)msg);
      break;
#endif
         ......
}

至此入網完成



注:此協議版本爲ZStack-CC2530-2.5.1a,若有不正確的地方歡迎大俠指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章