Zigbee網絡設備啓動—基本問題說明

記錄幾個問題:c++

***********************************
一、
有關設備的啓動模式選項:(有待完善):
網絡

非自動啓動模式 HOLD_AUTO_START:HOLD_AUTO_START is a compile option that will surpress ZDApp from starting the device and wait for the application to start the device.不經過ZDApp(具體講是ZDOInitDevice())而是等待應用程序來開啓設備並初始化創建/加入網絡.app

軟啓動模式 SOFT_START:SOFT_START is a compile option that allows the device to start as a coordinator if one isn't found. Otherwise, the device will start as a router.若是沒有協調器則做爲協調器啓動,有則做爲路由器啓動.less

自動啓動模式:我的認爲就是自動經過ZDApp(具體講是ZDOInitDevice())來開啓設備並初始化創建/加入網絡,設備的邏輯類型由所攜帶的配置文件來決定.
***********************************
函數


***********************************
二、三種邏輯類型節點的配置文件
協調器:f8wCoord.cfg配置文件中同時編譯了路由功能RTR_NWK和協調器功能ZDO_COORDINATOR
/* Common To All Applications */
-DCPU32MHZ                         // CC2430s Run at 32MHz
-DFORCE_MAC_NEAR                   // MAC code in NEAR
-DROOT=__near_func                 // MAC/ZMAC code in NEAR
oop

-DMAC_CFG_APP_PENDING_QUEUE=TRUEui

/* Coordinator Settings */
-DZDO_COORDINATOR                  // Coordinator Functions
-DRTR_NWK                          // Router Functions
this

/* Optional Settings */
-DBLINK_LEDS                       // LED Blink Functions
spa

/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic                // Ptr declaration
.net

路由器:f8wRouter.cfg配置文件中編譯了路由功能RTR_NWK
/* Common To All Applications */
-DCPU32MHZ                         // CC2430s Run at 32MHz
-DFORCE_MAC_NEAR                   // MAC code in NEAR
-DROOT=__near_func                 // MAC/ZMAC code in NEAR

-DMAC_CFG_APP_PENDING_QUEUE=TRUE

/* Router Settings */
-DRTR_NWK                          // Router Functions

/* Optional Settings */
-DBLINK_LEDS                       // LED Blink Functions

/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic                // Ptr declaration

終端:f8wEdev.cfg配置文件中沒有編譯這兩個功能.
/* Common To All Applications */
-DCPU32MHZ                         // CC2430s Run at 32MHz
-DFORCE_MAC_NEAR                   // MAC code in NEAR
-DROOT=__near_func                 // MAC/ZMAC code in NEAR

/* Optional Settings */
-DMAC_OPT_FFD=0                    // ZigBee RFD
-DBLINK_LEDS                       // LED Blink Functions

/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic                // Ptr declaration

協調器的配置文件只比路由器配置文件多編譯了個-DZDO_COORDINATOR  // Coordinator Functions
若是同時編譯非自動啓動模式HOLD_AUTO_START和軟啓動模式SOFT_START,設備能夠經過應用程序來選擇
成爲路由器或協調器.固然這個設備所帶的配置文件應爲f8wCoord.cfg.對於設備攜帶的是何種配置文件,能夠打開project->options->c/c++compiler->extraOptions選項查看.
好比SampleApp中的DemoEB,同時編譯了SOFT_START和HOLD_AUTO_START,貌似下載進去後經過外部跳線來選擇
是當協調器仍是路由器,不過這部分程序已經被註銷了.固然的,DemoEB所帶的配置文件應該是同時編譯了路由功能和協調器功能的f8wCoord.cfg,即編譯了RTR_NWK和ZDO_COORDINATOR.再好比SimpleApp中兩個實驗中的燈與開關實驗.開關設備SimpleSwitchEB不管按K1仍是K2都是做爲終端設備的,其預編譯選項只有HOLD_AUTO_START而沒有SOFT_START,配置文件爲f8wEndev.cfg,沒有協調器和路由功能;而燈設備SimpleControllerEB按鍵K1則做爲協調器,按K2則做爲路由器,其預編譯選項同時編譯了SOFT_START和HOLD_AUTO_START,配置文件爲f8wCoord.cfg,即編譯了RTR_NWK和ZDO_COORDINATOR. SimpleApp中傳感器實驗也同樣,只能做爲終端設備的SimpleSensorEB預編譯了HOLD_AUTO_START,配置文件爲f8wEndev.cfg;而SimpleCollectorEB按K1做爲協調器按K2做爲路由器,預編譯了SOFT_START和HOLD_AUTO_START,配置文件f8wCoord.cfg. 能夠經過project->options->c/c++compiler->extraOptions選項查看,也可由workspace看出,以下:

做爲終端的開關節點與做爲協調器/路由器的燈節點:空白的文件表示沒有包含在這個workspace中.

                      Zigbee網絡設備啓動—基本問題說明 - 小峯 - happy~   Zigbee網絡設備啓動—基本問題說明 - 小峯 - happy~

 做爲終端的傳感器節點與做爲協調器、路由器的中心收集節點:空白的文件表示沒有包含在這個workspace中.

                     Zigbee網絡設備啓動—基本問題說明 - 小峯 - happy~Zigbee網絡設備啓動—基本問題說明 - 小峯 - happy~

***********************************

***********************************
三、有兩種方式來設置非自動啓動模式:Hold Auto Start
(1)、手工方式:
在ZDApp_Init()函數中有個ZDAppCheckForHoldKey();(// Check for manual(手工的) "Hold Auto Start").

來看下這個函數:
********************
void ZDAppCheckForHoldKey( void )
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
  //直接經過讀取按鍵來判斷是否須要採用HOLD_AUTO_START模式,若是發現
  //SW_1處於按下(普通按鍵?)/向上(Joystick up)狀態,則設置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) //HAL_KEY_SW_1
  {
    // Change the device state to HOLD on start up
    devState = DEV_HOLD;
  }
#endif // HAL_KEY
}
*********************
能夠看到若是手工使HAL_KEY_SW_1置位狀態,則會設置devState = DEV_HOLD.
這裏HAL_KEY的初始化見hal_board_cfg.h:
 #ifndef HAL_KEY
 #define HAL_KEY TRUE
 #endif

而對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.
//這些鍵的定義僅適用於本應用例子,能夠在設備啓動時避開一些功能:
//避開網絡層的NV存儲和避開網絡初始化

#define SW_BYPASS_NV    HAL_KEY_SW_5     // Bypass Network layer NV restore
#define SW_BYPASS_START HAL_KEY_SW_1 
// Bypass Network initialization
所以避開網絡層NV存儲也能夠經過手工方式來完成.

(2)、預編譯方式:
project->options->c/c++compiler->preprocessor->defined symbols下編譯選項:HOLD_AUTO_START
SimpleApp例子裏四種節點都預編譯了HOLD_AUTO_START:非自動啓動模式
在ZDApp.c中:
#if defined( HOLD_AUTO_START )
  devStates_t devState = DEV_HOLD;
#else
  devStates_t devState = DEV_INIT;
#endif

把devState初始化爲DEV_HOLD.

以上兩種方式最終都會設置devState = DEV_HOLD // Initialized - not started automatically

****************************************

****************************************
四、devStartMode和devState的初始化,ZDApp.c中:

devStartMode:
#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
編譯了ZDO_COORDINATOR而且沒有編譯SOFT_START,則初始化devStartMode = MODE_HARD;其餘狀況初始化
devStartMode = MODE_RESUME;好比SampleApp三種邏輯類型節點.

devState:
#if defined( HOLD_AUTO_START )
  devStates_t devState = DEV_HOLD; // Initialized - not started automatically
#else
  devStates_t devState = DEV_INIT; // Initialized - not connected to anything
#endif

預編譯了HOLD_AUTO_START,則devState = DEV_HOLD;不然devState = DEV_INIT;
****************************************

****************************************
五、存儲設備邏輯類型的NV條目ZCD_NV_LOGICAL_TYPE:

(1)在ZGlobals.c下的NV條目表ZGlobal Item Table有這麼一個條目:
static CONST zgItem_t zgItemTable[ ] =
{
#if defined ( NV_INIT )
  {
    ZCD_NV_LOGICAL_TYPE, sizeof(zgDeviceLogicalType), &zgDeviceLogicalType
  },
  …………
}

zgItem_t結構體以下:
typedef struct zgItem
{
  uint16 id;
  uint16 len;
  void *buf;
} zgItem_t;

ZDO全局變量zgDeviceLogicalType被初始化爲uint8 zgDeviceLogicalType = DEVICE_LOGICAL_TYPE;
所以這裏全局變量zgDeviceLogicalType的值爲NV條目ZCD_NV_LOGICAL_TYPE的值,buf指向
zgDeviceLogicalType.若是在應用程序中改變了設備邏輯類型並寫入NV條目ZCD_NV_LOGICAL_TYPE中,這時即全局變量zgDeviceLogicalType的值改變了(卡在這步上近兩天,由於找不着改變的邏輯狀態與設備開啓時選擇的邏輯狀態之間的關係).

(2)NV條目ZCD_NV_LOGICAL_TYPE的值有哪些?
// Device Logical Type
//NV條目ZCD_NV_LOGICAL_TYPE的值包括:(即zgDeviceLogicalType的值)
// Values for ZCD_NV_LOGICAL_TYPE (zgDeviceLogicalType)

#define ZG_DEVICETYPE_COORDINATOR       0x00
#define ZG_DEVICETYPE_ROUTER                   0x01
#define ZG_DEVICETYPE_ENDDEVICE             0x02
#define ZG_DEVICETYPE_SOFT                        0x03

(3)對於DEVICE_LOGICAL_TYPE的值各邏輯類型設備初始化以下:
// Device Logical Type
//zgDeviceLogicalType = DEVICE_LOGICAL_TYPE

#if defined ( SOFT_START )
  #define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_SOFT        //可選擇類型
#elif defined( ZDO_COORDINATOR )
  #define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_COORDINATOR //協調器
#elif defined (RTR_NWK)
  #define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_ROUTER      //路由器
#else
  #define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_ENDDEVICE   //終端
#endif

若是編譯了SOFT_START,則初始化DEVICE_LOGICAL_TYPE=ZG_DEVICETYPE_SOFT,即zgDeviceLogicalType = ZG_DEVICETYPE_SOFT;若是沒有編譯SOFT_START但編譯了ZDO_COORDINATOR,則初始DEVICE_LOGICAL_TYPE = ZG_DEVICETYPE_COORDINATOR,即zgDeviceLogicalType=ZG_DEVICETYPE_COORDINATOR;
路由器和終端相似.
****************************************

****************************************
六、啓動設備都要經過ZDApp_event_loop()函數調用ZDO_StartDevice()對ZDO_NETWORK_INIT事件的處理:
ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,
                     DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );
這裏對於設備邏輯類型的傳遞參數ZDO_Config_Node_Descriptor.LogicalType,ZDConfig.c中初始化是這樣的

NodeDescriptorFormat_t ZDO_Config_Node_Descriptor =
{
#if defined( ZDO_COORDINATOR ) && !defined( SOFT_START )
  NODETYPE_COORDINATOR, //協調器
#elif defined (RTR_NWK)
 NODETYPE_ROUTER,             //路由器
#else
  NODETYPE_DEVICE,             //終端設備    // Logical Type
#endif
…………
}

若是編譯了ZDO_COORDINATOR且沒有編譯SOFT_START,則ZDO_Config_Node_Descriptor.LogicalType的值爲NODETYPE_COORDINATOR; 若是沒有編譯ZDO_COORDINATOR或者編譯了SOFT_START,且編譯了了RTR_NWK,則ZDO_Config_Node_Descriptor.LogicalType的值爲NODETYPE_ROUTER(好比simpleApp中燈節點和中心收集節點就是這種狀況,所以它倆的ZDO_Config_Node_Descriptor.LogicalType被初始化爲NODETYPE_ROUTER,固然當通過外部按鍵選擇設備邏輯類型爲協調器時,會經過內部程序把這個值改成NODETYPE_COORDINATOR,這點後面再做記錄);剩下狀況爲NODETYPE_DEVICE.
****************************************

****************************************
七、
simpleApp中的按鍵完成兩個功能:
設置設備的邏輯類型(ZC/ZR/ED) 和 設置設備的啓動方式(ZCD_STARTOPT_AUTO_START),而後寫入相應的NV條
目ZCD_NV_LOGICAL_TYPE和ZCD_NV_STARTUP_OPTION.
ZDApp_Init()是先於應用任務如SampleApp_Init()初始化的.

ZCD_NV_STARTUP_OPTION值包括:
//   These are bit weighted - you can OR these together.
//   Setting one of these bits will set their associated NV items
//   to code initialized values.

#define ZCD_STARTOPT_DEFAULT_CONFIG_STATE  0x01    //默認配置
#define ZCD_STARTOPT_DEFAULT_NETWORK_STATE 0x02 //默認網絡狀態
#define ZCD_STARTOPT_AUTO_START            0x04               //自動啓動
#define ZCD_STARTOPT_CLEAR_CONFIG   ZCD_STARTOPT_DEFAULT_CONFIG_STATE //清除配置=默認配置
#define ZCD_STARTOPT_CLEAR_STATE  ZCD_STARTOPT_DEFAULT_NETWORK_STATE
//清除狀態=默認網絡狀態

ZCD_NV_LOGICAL_TYPE值參見4.
**************************************

****************************************
八、網絡狀態的類型:

//設備的網絡狀態爲恢復的網絡狀態
#define ZDO_INITDEV_RESTORED_NETWORK_STATE      0x00
//網絡狀態初始化,即設備的網絡狀態爲新的網絡狀態.可能意味着ZCD_NV_STARTUP_OPTION不能恢復,或沒有任何網絡狀態恢復
#define ZDO_INITDEV_NEW_NETWORK_STATE           0x01
//復位前,網絡重返選項爲TRUE,所以該設備在網絡中沒有啓動(僅一次),下次調用該函數將啓動.
#define ZDO_INITDEV_LEAVE_NOT_STARTED           0x02

****************************************

****************************************
九、NV條目ZCD_NV_STARTUP_OPTION初始化

********************************************************************************
********************************************************************************
********************************************************************************

分析一:(錯誤,見分析二;暫不刪除)
NV條目的初始化在zgInit()中.main()函數中:
***************
  // Initialize basic NV items
  /*初始化NV條目*/
  zgInit();
****************************************
 * @fn          zgInit
 *
 * @brief
 *
 *   Initialize the Z-Stack Globals. If an item doesn't exist in
 *   NV memory, write the system default into NV memory. But if
 *   it exists, set the item to the value stored in NV memory.
 *
 * NOTE: The Startup Options (ZCD_NV_STARTUP_OPTION) indicate
 *       that the Config state items (zgItemTable) need to be
 *       set to defaults (ZCD_STARTOPT_DEFAULT_CONFIG_STATE). The
 *
 *
 * @param       none
 *
 * @return      ZSUCCESS if successful, NV_ITEM_UNINIT if item did not
 *              exist in NV, NV_OPER_FAILED if failure.
 */

uint8 zgInit( void )
{
  uint8  i = 0;
  uint8  setDefault = FALSE;

  // Do we want to default the Config state values
  if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )// 0x01
  {
    setDefault = TRUE;
  }

#if 0 //正常狀況下被禁止來節省NV空間
  // Enable this section if you need to track the number of resets
  // This section is normally disabled to minimize "wear" on NV memory

  …………
#endif

  // Initialize the Extended PAN ID as my own extended address
  //擴展地址

  ZMacGetReq( ZMacExtAddr, zgExtendedPANID );

#ifndef NONWK
  // Initialize the Pre-Configured Key to the default key
  osal_memcpy( zgPreConfigKey, defaultKey, SEC_KEY_LEN );  // Do NOT Change!!!
#endif
// NONWK

//----------------------------------初始化各NV配置狀態條目值
//初始化NV條目表zgItemTable[ ].若是setDefault=TRUE,則設置爲默認
//值;不然讀取原先存儲在裏面的值.

  while ( zgItemTable[i].id != 0x00 )
  {
    // Initialize the item
    zgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault  );

    // Move on to the next item
    i++;
  }
//----------------------------------
 
  // Clear the Config State default
  //若是NV條目ZCD_NV_STARTUP_OPTION的ZCD_STARTOPT_DEFAULT_CONFIG_STATE標緻位爲1
  if ( setDefault )
  { //把ZCD_STARTOPT_DEFAULT_CONFIG_STATE標緻位清0
    zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE );
  }

  return ( ZSUCCESS );
}
****************************************
NOTE: The Startup Options (ZCD_NV_STARTUP_OPTION) indicate
that the Config state items (zgItemTable) need to be
set to defaults (ZCD_STARTOPT_DEFAULT_CONFIG_STATE).
開啓選項代表了各NV配置狀態條目(zgItemTable表中的即爲NV配置狀態條目)須要被設置爲默認值.
setDefault的值取決於zgReadStartupOptions(),而這個函數記取的正是ZCD_NV_STARTUP_OPTION的值.
****************************************
// Reads the ZCD_NV_STARTUP_OPTION NV Item.
uint8 zgReadStartupOptions( void )
{
  // Default to Use Config State and Use Network State
  uint8 startupOption = 0;

  // This should have been done in ZMain.c, but just in case.
  if ( osal_nv_item_init( ZCD_NV_STARTUP_OPTION,
                              sizeof(startupOption),
                              &startupOption ) == ZSUCCESS )
  {
    // Read saved startup control
    //NV條目ZCD_NV_STARTUP_OPTION值讀到startupOption

    osal_nv_read( ZCD_NV_STARTUP_OPTION,
                  0,
                  sizeof( startupOption ),
                  &startupOption);
  }
  return ( startupOption );
}
****************************************

****************************************
 * @fn       zgItemInit()
 *
 *   Initialize a global item. If the item doesn't exist in NV memory,
 *   write the system default (value passed in) into NV memory. But if
 *   it exists, set the item to the value stored in NV memory.
 *
 *   Also, if setDefault is TRUE and the item exists, we will write
 *   the default value to NV space.
 *
 * @param   id - item id
 * @param   len - item len
 * @param   buf - pointer to the item
 * @param   setDefault - TRUE to set default, not read
 *                       TRUE則設置爲默認值而不讀取原先的值
 * @return  ZSUCCESS if successful, NV_ITEM_UNINIT if item did not
 *          exist in NV, NV_OPER_FAILED if failure.
 */

static uint8 zgItemInit( uint16 id, uint16 len, void *buf, uint8 setDefault )
{

  uint8 status;

  // If the item doesn't exist in NV memory, create and initialize
  // it with the value passed in.

  status = osal_nv_item_init( id, len, buf );  //NV條目讀寫前要進行條目的初始化
  if ( status == ZSUCCESS )
  {
    if ( setDefault )  //條目存在,setDefault=TRUE,設置爲默認值
    {
      // Write the default value back to NV
      status =  osal_nv_write( id, 0, len, buf );
    }
    else //條目存在,setDefault=FALSE,讀取原先存儲的值
    {
      // The item exists in NV memory, read it from NV memory
      status = osal_nv_read( id, 0, len, buf );
    }
  }

  return (status);
}
****************************************
zgReadStartupOptions()中:Default to Use Config State and Use Network State說明採用默認的配置和網絡狀態,那設備初始啓動時ZCD_NV_STARTUP_OPTION值應該是默認配置標誌位和默認網絡標誌位都置1,二者相或0x03(見7),但還沒能找到究竟哪裏進行過初始化.
回到zgInit():(1)setDefault = FALSE;(2)讀取ZCD_NV_STARTUP_OPTION值若是ZCD_STARTOPT_DEFAULT_CONFIG_STATE標誌位爲1,設置setDefault = TRUE;(3)初始化NV配置狀態條目表zgItemTable[ ]中各條目爲默認值(4)清除ZCD_STARTOPT_DEFAULT_CONFIG_STATE標誌位.
至於清除ZCD_STARTOPT_DEFAULT_CONFIG_STATE標誌位,我想若是用戶不改變ZCD_NV_STARTUP_OPTION條目的值,設備每次重啓都會將NV條目表中各項初始化爲默認值:好比SampleApp例子,每次設備重啓配置狀態都爲默認值.而若是用戶改變了ZCD_NV_STARTUP_OPTION的值,好比SimpleApp中:
        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();

每次按鍵後都會先把設備邏輯狀態寫入NV中(準備下次啓動設備時以保存在這個NV條目裏的邏輯類型來啓動),而後把ZCD_NV_STARTUP_OPTION設爲ZCD_STARTOPT_AUTO_START 0x04,則下面兩個標誌位都爲0.
ZCD_STARTOPT_DEFAULT_CONFIG_STATE  0x01 //默認配置狀態:存儲配置信息
ZCD_STARTOPT_DEFAULT_NETWORK_STATE 0x02 //默認網絡狀態:存儲網絡信息

這樣系統重啓進入zgInit()後:
if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )// 0x01
  {
    setDefault = TRUE;
  }
ZCD_STARTOPT_DEFAULT_CONFIG_STATE標誌位不爲1,setDefault保持FALSE,於是進入NV配置狀態條目初始化zgItemInit()時,執行的是:
    else //條目存在,setDefault=FALSE,讀取原先存儲的值
    {
      // The item exists in NV memory, read it from NV memory
      status = osal_nv_read( id, 0, len, buf );
    }
這樣把上次存儲在NV條目ZCD_NV_LOGICAL_TYPE中的設備邏輯類型值讀出做爲這次NV條目ZCD_NV_LOGICAL_TYPE的值.
問題是,還未肯定開啓選項ZCD_NV_STARTUP_OPTION的值初始化的地方.糾結中,待解決……

 ********************************************************************************
********************************************************************************
********************************************************************************


分析二:
@@@ ZCD_NV_STARTUP_OPTION最開始在osal_nv_item_init()中初始化,初始化爲0

****************************************
 * @fn          zgInit
 *
 * @brief
 *
 *   Initialize the Z-Stack Globals. If an item doesn't exist in
 *   NV memory, write the system default into NV memory. But if
 *   it exists, set the item to the value stored in NV memory.
 *
 * NOTE: The Startup Options (ZCD_NV_STARTUP_OPTION) indicate
 *       that the Config state items (zgItemTable) need to be
 *       set to defaults (ZCD_STARTOPT_DEFAULT_CONFIG_STATE). The
 *
 *
 * @param       none
 *
 * @return      ZSUCCESS if successful, NV_ITEM_UNINIT if item did not
 *              exist in NV, NV_OPER_FAILED if failure.
 */
uint8 zgInit( void )
{
  uint8  i = 0;
  uint8  setDefault = FALSE;

  // Do we want to default the Config state values
  if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )  // 0x01
  {
    setDefault = TRUE;
  }

#if 0 //正常狀況下被禁止來節省NV空間
  // Enable this section if you need to track the number of resets
  // This section is normally disabled to minimize "wear" on NV memory
  …………
#endif

  // Initialize the Extended PAN ID as my own extended address
  //擴展地址

  ZMacGetReq( ZMacExtAddr, zgExtendedPANID );

#ifndef NONWK
  // Initialize the Pre-Configured Key to the default key
  osal_memcpy( zgPreConfigKey, defaultKey, SEC_KEY_LEN );  // Do NOT Change!!!
#endif
// NONWK

//----------------------------------初始化各NV配置狀態條目值
//初始化NV條目表zgItemTable[ ].若是setDefault=TRUE,則設置爲系統默認
//值;不然設置爲原先存儲在裏面的值.

  while ( zgItemTable[i].id != 0x00 )
  {
    // Initialize the item
    zgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault  );

    // Move on to the next item
    i++;
  }
//----------------------------------
 
  // Clear the Config State default
  //若是NV條目ZCD_NV_STARTUP_OPTION的ZCD_STARTOPT_DEFAULT_CONFIG_STATE標緻位爲1
  if ( setDefault )
  { //把ZCD_STARTOPT_DEFAULT_CONFIG_STATE標緻位清0
    zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE );
  }

  return ( ZSUCCESS );
}
****************************************

首先來看下zgReadStartupOptions():
****************************************
// Reads the ZCD_NV_STARTUP_OPTION NV Item.
uint8 zgReadStartupOptions( void )
{
  // Default to Use Config State and Use Network State
  uint8 startupOption = 0;

  // This should have been done in ZMain.c, but just in case.
  //能返回ZSUCCESS,說明條目已經存在;固然,若是不存在,仍是在osal_nv_item_init
  //中建立條目並設置爲startupOption的值.
  if ( osal_nv_item_init( ZCD_NV_STARTUP_OPTION,
                              sizeof(startupOption),
                              &startupOption ) == ZSUCCESS )
  {
    // Read saved startup control
    //NV條目ZCD_NV_STARTUP_OPTION值讀到startupOption

    osal_nv_read( ZCD_NV_STARTUP_OPTION,
                  0,
                  sizeof( startupOption ),
                  &startupOption);
  }
  return ( startupOption );
}
****************************************
這裏讀取ZCD_NV_STARTUP_OPTION NV值,再來看下osal_nv_item_init():
****************************************
 * @fn      osal_nv_item_init
 *
 * @brief   If the NV item does not already exist, it is created and
 *          initialized with the data passed to the function, if any.
 *          This function must be called before calling osal_nv_read() or
 *          osal_nv_write().
            若是條目不存在,則建立並初始化爲傳遞過來的值.若是存在,
            直接返回ZSUCCESS.這個必須在read和write以前調用.

 *
 * @param   id  - Valid NV item Id.
 * @param   len - Item length.
 * @param  *buf - Pointer to item initalization data. Set to NULL if none.
 *                條目初始化時的值.
 * @return  NV_ITEM_UNINIT - Id did not exist and was created successfully.
 *          ZSUCCESS       - Id already existed, no action taken.
 *          NV_OPER_FAILED - Failure to find or create Id.
 */
uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf )
{
  /* Global fail flag for fail due to low bus voltage has less impact on code
   * size than passing back a return value all the way from the lowest level.
   */
  failF = FALSE;

  // ZCD_NV_EXTADDR is maintained without an osalNvHdr_t, so it is always already

initialized.
  //條目已經存在,則直接返回ZSUCCESS

  if ( (id == ZCD_NV_EXTADDR) || (findItem( id ) != OSAL_NV_ITEM_NULL) )
  {
    return ZSUCCESS;  //只有條目已經存在了,纔會返回ZSUCCESS
  }
  //條目不存在,則經過initItem建立條目並初始化爲buf傳遞過來的值
  else if ( initItem( TRUE, id, len, buf ) )
  {
    if ( failF )
    {
      (void)initNV();  // See comment at the declaration of failF.
      return NV_OPER_FAILED;
    }
    else
    {
      return NV_ITEM_UNINIT;
    }
  }
  else
  {
    return NV_OPER_FAILED;
  }
}
****************************************
在zgReadStartupOptions()中調用了osal_nv_item_init( ZCD_NV_STARTUP_OPTION,sizeof(startupOption),&startupOption );其中startupOption = 0;一開始並不存在ZCD_NV_STARTUP_OPTION這個NV條目,於是這裏會建立NV條目ZCD_NV_STARTUP_OPTION並初始化爲startupOption傳遞過來的值0.成功則返回NV_ITEM_UNINIT,於是不會調用zgReadStartupOptions()的osal_nv_read( ZCD_NV_STARTUP_OPTION,0,sizeof( startupOption ),&startupOption),最後返回startupOption=0.回到zgInit(),setDefault = FALSE保持不變,而後進入NV配置狀態條目初始化 zgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault  ),注意此時傳遞進去的值zgItemTable[i].buf已經定義爲系統默認值(能夠查看ZGlobals.c的NWK GLOBAL VARIABLES欄).看下zgItemInit():
****************************************
 * @fn       zgItemInit()
 *
 * @brief
 *
 *   Initialize a global item. If the item doesn't exist in NV memory,
 *   write the system default (value passed in) into NV memory. But if
 *   it exists, set the item to the value stored in NV memory.
 *   條目不存在,建立並設置爲傳遞過來的值;存在則設置爲原存儲的值.
 *   Also, if setDefault is TRUE and the item exists, we will write
 *   the default value to NV space.
 *
 * @param   id - item id
 * @param   len - item len
 * @param   buf - pointer to the item
 * @param   setDefault - TRUE to set default, not read
 *                     
 * @return  ZSUCCESS if successful, NV_ITEM_UNINIT if item did not
 *          exist in NV, NV_OPER_FAILED if failure.
 */
static uint8 zgItemInit( uint16 id, uint16 len, void *buf, uint8 setDefault )
{

  uint8 status;

  // If the item doesn't exist in NV memory, create and initialize
  // it with the value passed in.
  status = osal_nv_item_init( id, len, buf );//NV條目讀寫前都要進行條目的初始化
  //這裏是要status == ZSUCCESS纔會執行裏面的內容,說明
  //此NV條目是已經存在的,這樣纔會返回ZSUCCESS
  if ( status == ZSUCCESS )
  {
    if ( setDefault )  //條目存在,設置爲默認值
    {
      // Write the default value back to NV
      status =  osal_nv_write( id, 0, len, buf );
    }
    else //條目存在,讀取原先存儲的值
    {
      // The item exists in NV memory, read it from NV memory
      status = osal_nv_read( id, 0, len, buf );
    }
  }

  return (status);
}
****************************************
能夠看到一樣調用了osal_nv_item_init( id, len, buf ),若是條目不存在則建立並設置爲buf傳遞過來的值,若是存在則直接返回ZSUCCESS.一開始各NV配置狀態條目不存在,於是這裏建立各條目並設置爲buf傳遞過來的值(系統定義的默認值).回到zgInit(),各NV配置狀態條目初始化完成後,返回ZSUCCESS.由於此時setDefault保持FALSE不變,於是不會執行zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE );

以上爲NV條目的初始化流程.初始化時ZCD_NV_STARTUP_OPTION=0,即把各NV條目初始化爲系統默認的值.
想到zgReadStartupOptions()開頭那句話:
  // Default to Use Config State and Use Network State
  uint8 startupOption = 0;
startupOption即爲ZCD_NV_STARTUP_OPTION的初始化值.

(###)若是,這樣初始化完成後,又在應用程序中改變ZCD_NV_STARTUP_OPTION的值,改成ZCD_STARTOPT_DEFAULT_CONFIG_STATE.而後zb_SystemReset()重啓系統.進入zgInit(),首先設置setDefault = FALSE,而後一樣進入判斷:
  if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )// 0x01
  {
    setDefault = TRUE;
  }
調用:zgReadStartupOptions()->osal_nv_item_init(),由於此時NV條目ZCD_NV_STARTUP_OPTION已經存在,因此osal_nv_item_init()不會再建立條目並設置爲傳遞過來的值startupOption = 0,而是直接返回ZSUCCESS,於是這時在zgReadStartupOptions()裏會調用    osal_nv_read( ZCD_NV_STARTUP_OPTION,0,sizeof( startupOption ),&startupOption)讀取先前已經存儲在條目ZCD_NV_STARTUP_OPTION裏的值:ZCD_STARTOPT_DEFAULT_CONFIG_STATE!因此這裏設置setDefault = TRUE.而後進入各NV配置狀態條目初始化:zgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault  );進入zgItemInit(),一樣先調用了osal_nv_item_init( id, len, buf ),由於各NV配置狀態條目已經存在,因此再也不建立而是直接返回ZSUCCESS,因此此次會調用:
  if ( status == ZSUCCESS )
  {
    if ( setDefault )  //條目存在,設置爲默認值
    {
      // Write the default value back to NV
      status =  osal_nv_write( id, 0, len, buf );
    }
    else //條目存在,設置爲原先存儲的值
    {
      // The item exists in NV memory, read it from NV memory
      status = osal_nv_read( id, 0, len, buf );
    }
  }
由於setDefault = TRUE,因此從新設置各NV配置狀態條目爲系統默認值.而後回到zgInit(),最終調用
  if ( setDefault )
  {  //把ZCD_STARTOPT_DEFAULT_CONFIG_STATE這位清0
    zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE );
  }
這裏把ZCD_NV_STARTUP_OPTION條目值從新清0(我上面只假設ZCD_NV_STARTUP_OPTION的值爲ZCD_STARTOPT_DEFAULT_CONFIG_STATE 0x01).

  (###)固然,若是像SampleApp例子沒有在應用程序中修改過ZCD_NV_STARTUP_OPTION,最開始啓動設備時會建立條目並初始化爲0(startupOption = 0),而後建立各NV配置狀態條目並初始化爲系統默認值.之後的每次設備啓動,ZCD_NV_STARTUP_OPTION值爲0,setDefault = FALSE,各NV配置狀態條目初始化執行的是:
    else //條目存在,設置爲原先存儲的值
    {
      // The item exists in NV memory, read it from NV memory
      status = osal_nv_read( id, 0, len, buf );
    }
讀取此前的配置狀態.

  (###)再好比SimpleApp例子,應用程序經過按鍵改變NV條目ZCD_NV_STARTUP_OPTION以及NV配置狀態條目ZCD_NV_LOGICAL_TYPE的值,經過zb_WriteConfiguration()寫入NV中,而後zb_SystemReset()重啓系統.進入zgInit(),經過zgReadStartupOptions()讀出的ZCD_NV_STARTUP_OPTION值不爲ZCD_STARTOPT_DEFAULT_CONFIG_STATE,於是setDefault = FALSE.再進入zgItemInit(),由於條目存在且setDefault = FALSE,因此執行     
// The item exists in NV memory, read it from NV memory
      status = osal_nv_read( id, 0, len, buf );

把條目的值設置爲先前存儲的值.即在SampleApp例子中,把上次存儲在NV條目ZCD_NV_LOGICAL_TYPE中
的設備邏輯類型值讀出做爲這次NV條目ZCD_NV_LOGICAL_TYPE的值.

(1)初始ZCD_NV_STARTUP_OPTION=0.若是設備是首次啓動,則調用status = osal_nv_item_init( id, len, buf )建立各NV配置狀態條目並初始化爲系統默認值;若是設備不是首次啓動,則調用osal_nv_read( id, 0, len, buf )讀取各NV配置狀態條目先前存儲的值做爲本次的值.
(2)設置ZCD_NV_STARTUP_OPTION=ZCD_STARTOPT_DEFAULT_CONFIG_STATE.NV條目ZCD_NV_STARTUP_OPTION已經存在,調用osal_nv_write( id, 0, len, buf )設置各NV配置狀態條目爲系統默認值.最後把這位清0.
(3)設置ZCD_NV_STARTUP_OPTION=ZCD_STARTOPT_AUTO_START.NV條目ZCD_NV_STARTUP_OPTION已經存在,調用osal_nv_read( id, 0, len, buf )讀取各NV配置狀態條目先前存儲的值做爲本次的值.

相關文章
相關標籤/搜索