Zigbee网络设备启动—基本问题说明

记录几个问题:

***********************************
1、
有关设备的启动模式选项:(有待完善):

非自动启动模式 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())而是等待应用程序来开启设备并初始化建立/加入网络.

软启动模式 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.如果没有协调器则作为协调器启动,有则作为路由器启动.

自动启动模式:个人认为就是自动通过ZDApp(具体讲是ZDOInitDevice())来开启设备并初始化建立/加入网络,设备的逻辑类型由所携带的配置文件来决定.
***********************************


***********************************
2、三种逻辑类型节点的配置文件
协调器: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

-DMAC_CFG_APP_PENDING_QUEUE=TRUE

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

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

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

路由器: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中.

  

作为终端的传感器节点与作为协调器、路由器的中心收集节点:空白的文件表示没有包含在这个workspace中.

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

***********************************
3、有两种方式来设置非自动启动模式: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

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

****************************************
4、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;
****************************************

****************************************
5、存储设备逻辑类型的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;
路由器和终端类似.
****************************************

****************************************
6、启动设备都要通过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.
****************************************

****************************************
7、
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.
**************************************

****************************************
8、网络状态的类型:

//设备的网络状态为恢复的网络状态
#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

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

****************************************
9、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配置状态条目先前存储的值作为本次的值.

Zigbee网络设备启动—基本问题说明

时间: 2024-10-12 16:43:54

Zigbee网络设备启动—基本问题说明的相关文章

网络设备驱动程序数据结构

struct softnet_data{    int            throttle;    int            cng_level;    int            avg_blog;    struct sk_buff_head    input_pkt_queue;    struct list_head    poll_list;    struct net_device    *output_queue;    struct sk_buff        *co

Linux 网卡驱动学习(net_device 等数据结构)

[摘要]前文对网络驱动例子进行一个简单的梳理总结,本文贴出 net_device 的数据结构以及一些驱动中常用的数据结构. 1.网络设备驱动结构 下图摘自http://blog.chinaunix.net/uid-20672257-id-3147768.html 1).网络协议接口层向网络层协议提供提供统一的数据包收发接口,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接受数据.这一层的存在使得上层协议独立于具体的设备. 2).网

第1章 ZigBee协议栈初始化网络启动流程

作者:宋老师,华清远见嵌入式学院讲师. ZigBee的基本流程:由协调器的组网(创建PAN ID),终端设备和路由设备发现网络以及加入网络. 基本流程:main()->osal_init_system()->osalInitTasks()->ZDApp_Init(),进协议栈初始化函数ZDApp_Init(). 1.1 进入程序入口main(). ZMain.c中 C++ Code int main( void )         {                 // Turn of

开机eth0网络设备不启动

CentOS开机eth0网络设备不启动 新装一个CentOS系统,开机发现没有网络,于是ifconfig一下发现eth0设备网络没有启动 1 2 3 4 5 6 7 8 9 [[email protected] ~]# ifconfig  lo        Link encap:Local Loopback    inet addr:127.0.0.1  Mask:255.0.0.0  inet6 addr: ::1/128Scope:Host  UP LOOPBACK RUNNING  MT

linux网络设备无法启动问题处理

之前安装了一台CentOS操作系统测试Nginx负载均衡,后来很久没用.有一次同事升级了VM,最近又想在上面测试KeepAlived,于是,服务里连接不上了. 开始查找原因,一直傻傻的更改ifcfg-eth0配置文件,重启 network 的时候确总是提示 找不到设备 eth0,于是使用 ifconfig -a 命令查看了下当前所有的网络设备,发现确实不存在 eth0,但是确多出来一个 eth1,难道名称变了?不管这么多了,重新配吧. 于是乎我直接修改ifcfg-eth0的配置,将device更

解决CentOS 7 开机网络设备不启动方法

在VMware 10里新装一个CentOS 7系统,开机发现没有网络,于是ifconfig一下发现网卡没有启动 eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500 ether 00:0c:29:2b:c0:1e  txqueuelen 1000  (Ethernet) RX packets 1  bytes 251 (251.0 B) RX errors 0  dropped 0  overruns 0  fram

基于ZigBee的家居控制系统的设计与应用

基于ZigBee的家居控制系统的设计与应用 PPT简介:http://pan.baidu.com/s/1i38PC6D 摘  要 智能家居是未来家居的发展方向,其利用先进的网络技术.计算机技术和无线通信技术等将家居中的各种电子电气设备连接起来,统一管理.远程监控和资源共享,实现了高效.便利的生活环境.近些年互联网的迅猛发展,网络的稳定性.安全性和网络带宽都有了长足的发展,由互联网提供的各种服务已经深入到人们生活的方方面面,因此将智能家居系统同互联网结合起来,为用户提供远程控制服务,延伸智能家居系

ZigBee入门之基础概念3

第三讲: zigbee术语 射频收发器:如cc2420 一个节点可以对应多个设备 一个设备包含多个端点 每个端点又有很多群集(输出群集.输入群集) 每个群集有一个或多个属性 属性 Attribute 是一个反映物理数量或状态的数据值,比如开关值(On/Off) ,温度值.百 分比等. 群集(簇) Cluster 是包含一个或多个属性(attribute)的群组.简单的说,群集就是属性的集合. 每个群集都被分配一个唯一的群集 ID 且每个群集最多有 65536 个属性 设备描述 Device De

ZigBee安全相关

ZigBee安全由AES加密算法和CCM操作方式作为安全方案,广泛使用在ZigBee联盟的通信协议中.ZDO层负责安全策略和安全配置的管理. Technorati 标签: ZigBee 安全 2. 配置 在Z-Stack协议栈中,安全网络配置默认是关闭的,如需开启,将SECURE设置为非0即可. 全局变量zgSecurityMode表示设备默认的安全模式 取值有以下几种情况:     全局安全模式 ZG_SECURITY_MODE 模式含义 SECURE =0 ZG_SECURE_DYNAMIC