本章解读Z-STACK中关于Nv操作的源码,以及z-stack中Nv的使用!
在Z-STACK中Nv存储器主要用于保存网络的配置参数,如网络地址,使 系统在掉电重启仍然能读取一些参数,自动加入到原来的网络中,这样其网络地址没有变化!
在z-stack中,每一个参数的配置对应的是一个Nv条目(item),每一个item都有自己的ID,z-stack中使用的条目ID范围如下:
0x0000 保留
0x0001~0x0020 操作系统抽象层(OSAL)
0x0021~0x0040 网络层(NWK)
0x0041~0x0060 应用程序支持子层(APS)
0x0061~0x0080 安全(Security)
0x0081~0x00A0 Zigbee设备对象(ZDO)
0x00A1~0x0200 保留
0x0201~0x0FFF 应用程序
0x1000~0xFFFF 保留
如果是我们自己的应用程序中需要使用Nv,则定义其ID在0x0201~0x0FFF 范围内!
Z-STACK真正提供给用户使用的是五个函数:(在OSAL_Nv.h中声明)
1 void osal_nv_init( void *p );
2 uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf );
3 uint8 osal_nv_read( uint16 id, uint16 offset, uint16 len, void *buf );
4 uint8 osal_nv_write( uint16 id, uint16 offset, uint16 len, void *buf );
5 uint16 osal_nv_item_len( uint16 id );
第1个函数在系统初始化的时候被调用,我们在应用程序中不用管!
第2个函数是我们在使用Nv时,初始化某个条目,如osal_nv_item_init(TEST_NV,1,NULL);
第3个函数是Nv读取某一个条目的数据,将其存储在buf中
第4个函数创建一个Nv条目(如果条目的ID不存在,如果存在,就将原来的item数据部分覆盖),并向其中写入数据
第5个函数是查询某一个item的数据长度。
真正我们使用的是第2~4个函数。使用如下:
unsigned char value_read;
unsigned char value = 0x18;
osal_nv_item_init(TEST_NV,1,NULL);//NULL表示初始化的时候,item数据部分为空
osal_nv_item_write(TEST_NV,0,1,&value);
osal_nv_item_read(TEST_NV,0,1,&value_read);
value_read的值便是0x18,记住在write之前必须要初始化item,即调用osal_nv_item_init函数
下面我们打开OSAL_Nv.c源文件,通过分析源代码,就知道Z-STACK是如何抽象的封装出以上几个API,这对我们以后写程序还是很有帮助的!
在解读源码之前,必须要知道存储Nv条目的6个page如何存储Nv的,即其item在page中的结构和布局!
首先每一个page都有一个osalNvPgHdr_t结构体的头
typedef struct
{
uint16 active;
uint16 inUse;
uint16 xfer;
uint16 spare;
} osalNvPgHdr_t; 其中的几个成员稍后在做解释!
在这8个字节的page头部之后才是item的存储位置。而每一个item都有一个8字节的头部
typedef struct
{
uint16 id;
uint16 len; // Enforce Flash-WORD size on len.
uint16 chk; // Byte-wise checksum of the 'len' data bytes of the item.
uint16 stat; // Item status.
} osalNvHdr_t; 从后面注释就知道了每一个成员变量的含义
然后我们还必须得知道几个全局变量和数组的含义:OSAL_NV_PAGES_USED值为6,即6个page
uint16 pgOff[OSAL_NV_PAGES_USED];