z-stack組網分:協調器建立網絡、路由器和終端加入網絡
暫時只記錄第一次上電建立網絡的過程,至於開啟NV_RESTORE后,恢復原有的網絡則暫時不分析。
一、協調器建立網絡:
1、ZDO層的ZDApp_Init中有如下函數:
if ( devState != DEV_HOLD ) // 如果不希望自動啟動,則可以在這個函數調用前,把devState設置為DEV_HOLD,然后在需要啟動的時候設置為DEV_INIT
{ ZDOInitDevice( 0 ); // 啟動設備,里面就包含了組網 } else { // Blink LED to indicate HOLD_START HalLedBlink ( HAL_LED_4, 0, 50, 500 ); }
2、ZDOInitDevice()中如果定義了NV_RESTORD,則可以通過按鍵選擇是新建一個網絡,或者是讀取NV中的網絡進行恢復,我們這里假設NV_RESTORE沒有定義,直接新建一個網絡。
if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE ) // 判斷是新建一個網絡 { ZDAppDetermineDeviceType(); // 確定當前設備類型為NODETYPE_COORDINATOR協調器,設備啟動模式為MODE_HARD // 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 ); // Trigger the network start ZDApp_NetworkInit( extendedDelay ); // 開始網絡初始化,我們這里協調器開始建立網絡 // set broadcast address mask to support broadcast filtering NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags );
3、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 ); } }
4、ZDApp_event_loop則檢測ZDO層的任務,當發現ZDO_NETWORK_INIT事件后,會執行如下:
if ( events & ZDO_NETWORK_INIT ) { // Initialize apps and start the network devState = DEV_INIT;
// 以前面確定的節點類型NODETYPE_COORDINATOR(協調器),啟動方式MODE_HARD啟動設備 ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode, DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER ); // Return unprocessed events return (events ^ ZDO_NETWORK_INIT); }
5、ZDO_StartDevice()函數調用如下函數開始形成網絡:
if ( ZG_BUILD_COORDINATOR_TYPE && logicalType == NODETYPE_COORDINATOR ) { if ( startMode == MODE_HARD ) { devState = DEV_COORD_STARTING; // 把設備狀態更改為協調器啟動中,並且開始建立網絡
// 調用網絡形成函數開始建立網絡,需要的信息需要我們設置的主要包括PANID,信道 ret = NLME_NetworkFormationRequest( zgConfigPANID, zgApsUseExtendedPANID, zgDefaultChannelList, zgDefaultStartingScanDuration, beaconOrder, superframeOrder, false ); }
6、NLME_NetworkFormationRequest()函數是通過網絡層像空間發送建立網絡請求,其中通過抓包軟件發現,他會想空間發送一個BEACON信號,來獲取空間中的網絡情況,然后建立自己的網絡,如果自己的網絡和空間中的網絡的PANID相同,則會在此PANID上+1,
7、NLME_NetworkFormationRequest()函數發出request請求后會得到一個confirm,這個confirm函數為ZDO_NetworkFormationConfirmCB(),如果status的值為ZSUCCESS,則此網絡成功建立,網絡建立成功或者失敗,都需要告知ZDO層,ZDO層好根據情況作出相應的合適的處理。
/********************************************************************* * @fn ZDO_NetworkFormationConfirmCB * * @brief This function reports the results of the request to * initialize a coordinator in a network. * * @param Status - Result of NLME_NetworkFormationRequest() * * @return none */ void ZDO_NetworkFormationConfirmCB( ZStatus_t Status ) { nwkStatus = (byte)Status; if ( Status == ZSUCCESS ) { // LED on shows Coordinator started HalLedSet ( HAL_LED_3, HAL_LED_MODE_ON ); // LED off forgets HOLD_AUTO_START HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF); #if defined ( ZBIT ) SIM_SetColor(0xd0ffd0); #endif if ( devState == DEV_HOLD ) { // Began with HOLD_AUTO_START devState = DEV_COORD_STARTING; } } #if defined(BLINK_LEDS) else { HalLedSet ( HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED to show failure } #endif osal_set_event( ZDAppTaskID, ZDO_NETWORK_START ); // 通知ZDO層,設置一個ZDO_NETWORK_START事件 }
8、ZDApp_event_loop處理上面觸發的ZDO_NETWORK_START事件
if ( events & ZDO_NETWORK_START ) { ZDApp_NetworkStartEvt(); // Return unprocessed events return (events ^ ZDO_NETWORK_START); }
9、ZDO_NETWORK_START事件調用了ZDApp_NetworkStartEvt()函數,如果之前網絡已經建立成功則設置ZDO_STATE_CHANGE_EVT事件,否則增大發射功率再次設置ZDO_NETWORK_INIT事件,重新開始建立網絡,具體函數如下:
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 ); } 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 ); } } }
10、ZDO_STATE_CHANGE_EVT事件調用函數ZDO_UpdateNwkStatue()函數,此函數會把該網絡變化情況通知給所有的應用層端點,以便用戶根據此通知做相應處理,具體函數如下:
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); #endif ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr(); (void)NLME_GetExtAddr(); // Load the saveExtAddr pointer. }
11、至此協調器成功建立網絡並且告知應用層。路由器和終端加入網絡的過程在下一節繼續分析。