如果使用HOLD_AUTO_START選項(xiàng),那么本工程就會(huì)禁止自動(dòng)啟動(dòng)ZDApp事件處理循環(huán)中的ZDO_NETWORK_INIT事件,也就是上電后不自動(dòng)調(diào)用ZDOInitDevice(),需要通過外部事件,或者用戶自己調(diào)用這個(gè)函數(shù),下面我們看看定義了這個(gè)函數(shù)后,程序的流程是怎么樣的。
在ZDApp.c文件中,可以看到下面的定義:
#if defined( HOLD_AUTO_START )
devStates_t devState = DEV_HOLD; // 初始化-不會(huì)自動(dòng)啟動(dòng)
#else
devStates_t devState = DEV_INIT; //初始化-沒有連接到任何東西
#endif
#if defined( ZDO_COORDINATOR ) && !defined( SOFT_START )
// Set the default to coodinator
devStartModes_t devStartMode = MODE_HARD;
#else
devStartModes_t devStartMode = MODE_JOIN; // Assume joining
//devStartModes_t devStartMode = MODE_RESUME; // if already "directly joined"
// to parent. Set to make the device do an Orphan scan.
#endif
#if !defined( ZDO_COORDINATOR ) || defined( SOFT_START )
static uint8 retryCnt;
#endif
在調(diào)用用戶自己定義的任務(wù)初始化函數(shù)之前,調(diào)用下面的初始函數(shù),看看這里怎么處理,devState狀態(tài)的。
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;
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer. 加載IEEE地址
// Check for manual "Hold Auto Start"
//打開電源時(shí),檢測到有手工設(shè)置SW_1則會(huì)設(shè)置devState = DEV_HOLD,從而不進(jìn)行網(wǎng)絡(luò)初始化
ZDAppCheckForHoldKey();
// Initialize ZDO items and setup the device - type of device to create.
ZDO_Init(); //初始化ZDO條目,并設(shè)置設(shè)備的啟動(dòng)方式是協(xié)調(diào)器,還是別的
// 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? 是否啟動(dòng)設(shè)備?如果devState不是DEV_HOLD時(shí),則啟動(dòng)設(shè)備,在上面的代碼分析中,也可以看到,如果定義了HOLD_AUTO_START宏,則devState等于DEV_HOLD,不會(huì)啟動(dòng)設(shè)備。如果按下了SW_1鍵devState也等于DEV_HOLD,也不會(huì)啟動(dòng)網(wǎng)絡(luò)。也就是說有兩種方式可以設(shè)置非自動(dòng)啟動(dòng)模式,一種是通過按鍵,一種通過宏定義
if ( devState != DEV_HOLD )
{
ZDOInitDevice( 0 );
}
else
{
//如果定義了HOLD_AUTO_START,則等待延時(shí)或外部事件啟動(dòng)網(wǎng)絡(luò),并且LED4燈,也就是藍(lán)色的燈閃爍
// Blink LED to indicate HOLD_START
HalLedBlink ( HAL_LED_4, 0, 50, 500 );
}
ZDApp_RegisterCBs();
} /* ZDO_Init() */
void ZDAppCheckForHoldKey( void )
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
//通過判斷按鍵來決定是否采用HOLD_AUTO_START方式。當(dāng)按下SW_BYPASS_START按鍵,也就是SW1鍵,將避開自動(dòng)啟動(dòng)設(shè)備,也就是設(shè)置 devState = 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)
{
// Change the device state to HOLD on start up
devState = DEV_HOLD;
}
#endif // HAL_KEY
}
說明:(1)這里HAL_KEY的初始化在hal_board_cfg.h文件中:
#ifndef HAL_KEY #define HAL_KEY TRUE #endif 而對(duì)SW_BYPASS_START的初始化在OnBoard.h文件中: // These Key definitions are unique to this development system. // They are used to bypass functions when starting up the device. //這些鍵的定義僅適用于本應(yīng)用例子,可以在設(shè)備啟動(dòng)時(shí)避開一些功能: //避開網(wǎng)絡(luò)層的NV存儲(chǔ)和避開網(wǎng)絡(luò)初始化 #define SW_BYPASS_NV HAL_KEY_SW_5 // Bypass Network layer NV restore #define SW_BYPASS_START HAL_KEY_SW_1 // Bypass Network initialization 因此避開網(wǎng)絡(luò)層NV存儲(chǔ)也可以通過手工方式來完成. //根據(jù)編譯選項(xiàng)來設(shè)置;比如SimpleApp中的燈節(jié)點(diǎn),預(yù)編譯了ZDO_COORDINATOR和REFLECTOR和SOFT_START,因此會(huì)根據(jù)這些來選擇開啟一些函數(shù)功能.
void ZDO_Init( void )
{
// Initialize ZD items REFLECTOR如果定義了這個(gè)編譯選項(xiàng)則使用“源綁定”,
#if defined ( REFLECTOR )
ZDO_EDBind = NULL;
#endif
// Setup the device - type of device to create.
ZDODeviceSetup();
}
static void ZDODeviceSetup( void )
{
#if defined( ZDO_COORDINATOR ) //如果定義了協(xié)調(diào)器,協(xié)調(diào)器初始化
NLME_CoordinatorInit();
#endif
#if defined ( REFLECTOR ) //如果定義了COORDINATOR_BINDING 綁定時(shí)使用
#if defined ( ZDO_COORDINATOR )//定義了REFLECTOR,且定義了協(xié)調(diào)器
APS_ReflectorInit( APS_REFLECTOR_PUBLIC );
#else //編譯了REFLECTOR且編譯了路由器或終端
APS_ReflectorInit( APS_REFLECTOR_PRIVATE );
#endif
#endif
#if !defined( ZDO_COORDINATOR ) || defined( SOFT_START )//如果沒有定義協(xié)調(diào)器ZDO_COORDINATOR ),則還定義了SOFT_START則進(jìn)行連接初始化
NLME_DeviceJoiningInit();
#endif
}
uint8 ZDOInitDevice( uint16 startDelay )
{
//初始化設(shè)備網(wǎng)絡(luò)狀態(tài)為ZDO_INITDEV_NEW_NETWORK_STATE:新的網(wǎng)絡(luò)狀態(tài).可能意味著ZCD_NV_STARTUP_OPTION不能恢復(fù),或沒有任何網(wǎng)絡(luò)狀態(tài)恢復(fù)
uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
uint16 extendedDelay = 0;
devState = DEV_INIT; // Remove the Hold state
// Initialize leave control logic
//函數(shù)讀取NV項(xiàng)目ZCD_NV_LEAVE_CTRL的值,ZDApp_LeaveCtrl指向這個(gè)值
ZDApp_LeaveCtrlInit();
// Check leave control reset settings
//設(shè)備的斷開會(huì)造成DEV_HOLD狀態(tài),這里面設(shè)置的.
ZDApp_LeaveCtrlStartup( &devState, &startDelay );
// Leave may make the hold state come back
//以上兩個(gè)函數(shù)設(shè)置了對(duì)設(shè)備離開時(shí)的控制,如果有延時(shí)則延時(shí),沒有則
//把設(shè)備狀態(tài)設(shè)為DEV_HOLD //ZDO_INITDEV_LEAVE_NOT_STARTED:該設(shè)備沒有在網(wǎng)絡(luò)中,下次調(diào)用才啟用.
if ( devState == DEV_HOLD )
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按鍵處于按下狀態(tài)時(shí),則避開網(wǎng)絡(luò)層的NV存儲(chǔ)
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //設(shè)備網(wǎng)絡(luò)狀態(tài)為新的網(wǎng)絡(luò)狀態(tài)
else
{
// Determine if NV should be restored
//函數(shù)返回的設(shè)備網(wǎng)絡(luò)狀態(tài)要么是新的網(wǎng)絡(luò)狀態(tài);要么是恢復(fù)的網(wǎng)絡(luò)狀態(tài);以此
//來確定要不要讀取NV里相應(yīng)條目來恢復(fù)網(wǎng)絡(luò)先前狀態(tài) networkStateNV = ZDApp_ReadNetworkRestoreState();
}
//如果設(shè)備的網(wǎng)絡(luò)狀態(tài)為恢復(fù)的網(wǎng)絡(luò)狀態(tài)
if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
networkStateNV = ZDApp_RestoreNetworkState();
}
else
{
// Wipe out the network state in NV
//恢復(fù)設(shè)備先前的網(wǎng)絡(luò)狀態(tài)參數(shù)
//設(shè)置devStartMode = MODE_RESUME NLME_InitNV();
NLME_SetDefaultNV();
}
#endif
//如果設(shè)備的網(wǎng)絡(luò)狀態(tài)為新的網(wǎng)絡(luò)狀態(tài),
if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE )
{
//根據(jù)預(yù)編譯來設(shè)置設(shè)備新的網(wǎng)絡(luò)狀態(tài)參數(shù)
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 );
}
ZigBee設(shè)備的啟動(dòng),最終是要調(diào)用ZDO_StartDevice()函數(shù)來實(shí)現(xiàn)的。下面看一下是怎么啟動(dòng)這個(gè)函數(shù)的。在ZDOInitDevice()函數(shù)的最后,調(diào)用了下面的ZDApp_NetworkInit()函數(shù),在這個(gè)函數(shù)中,啟動(dòng)了ZDO_NETWORK_INIT事件,這個(gè)事件是在ZDApp_event_loop()事件處理函數(shù)中進(jìn)行處理的。在這個(gè)事件中調(diào)用了啟動(dòng)設(shè)備的函數(shù)ZDO_StartDevice(),這函數(shù)在前面的文章中也已經(jīng)分析過了。
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 );
}
}
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);
}
.....................
}
下面以SimpleSwitchEB為例子看看當(dāng)定義了HOLD_AUTO_START選項(xiàng)后,程序的流程是怎么樣的。在void SAPI_Init( byte task_id )函數(shù)的最后,有下面一句話,
osal_set_event(task_id, ZB_ENTRY_EVENT);下圖是編譯選項(xiàng)的設(shè)置:
這將觸發(fā)ZB_ENTRY_EVENT事件,這個(gè)事件的處理在,
UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )
{
.................................
if ( events & ZB_ENTRY_EVENT )
{
uint8 startOptions;
// Give indication to application of device startup
//這個(gè)函數(shù)不處理ZB_ENTRY_EVENT事件
zb_HandleOsalEvent( ZB_ENTRY_EVENT );
// LED off cancels HOLD_AUTO_START blink set in the stack
//關(guān)閉協(xié)議棧中LED4的閃爍,LED4燈閃爍表明沒有正常啟動(dòng)設(shè)備或者沒有加入網(wǎng)絡(luò) 關(guān)閉棧中的HOLD指示
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
{
//首次使用時(shí),閃爍LED2,指示外部輸入,等待啟動(dòng)設(shè)備
// blink leds and wait for external input to config and restart
HalLedBlink(HAL_LED_2, 0, 50, 500);
}
return (events ^ ZB_ENTRY_EVENT);
}
..............................
}
在按鍵處理函數(shù)中,可以看到
void zb_HandleKeys( uint8 shift, uint8 keys )
{
uint8 startOptions;
uint8 logicalType;
// Shift is used to make each button/switch dual purpose.
if ( shift )
{
if ( keys & HAL_KEY_SW_1 )
{
}
if ( keys & HAL_KEY_SW_2 )
{
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
}
}
else
{
if ( keys & HAL_KEY_SW_1 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// The Switch device is always an end-device
logicalType = ZG_DEVICETYPE_ENDDEVICE;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
// Do more configuration if necessary and then restart device with auto-start bit set
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;//下次啟動(dòng)時(shí),自動(dòng)啟動(dòng)
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();//這里導(dǎo)致設(shè)備重啟,重啟后,產(chǎn)生ZB_ENTRY_EVENT事件,啟動(dòng)網(wǎng)絡(luò)設(shè)備
}
else
{
// Initiate a binding with null destination
zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID, NULL);
}
}
if ( keys & HAL_KEY_SW_2 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// The Switch device is always an end-device
logicalType = ZG_DEVICETYPE_ENDDEVICE;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
else
{
// Send the command to toggle light
zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,
(uint8 *)NULL, myAppSeqNumber, 0, 0 );
}
}
if ( keys & HAL_KEY_SW_3 )
{
// Remove all existing bindings
zb_BindDevice(FALSE, TOGGLE_LIGHT_CMD_ID, NULL);
}
if ( keys & HAL_KEY_SW_4 )
{
}
}
}
這樣SimpleSwitchEB()就作為了非自動(dòng)啟動(dòng)設(shè)備進(jìn)行了啟動(dòng)了,也就是說必須在定義了HOLD_AUTO_START宏以后,當(dāng)按鍵按下后,就會(huì)重新啟動(dòng)網(wǎng)絡(luò)設(shè)備。
|
|