Silicon Lab Ember zigbee学习杂谈----Tokens

本文将介绍ember zigbee中token的概念及用法,token是用来存储非易失性数据的即掉电后也能保存,由于在EM3xx芯片中没有eeprom,所以实际上它们是直接存储在flash上,用flash作为虚拟eeprom(simulated eeprom)的用法。

token分为两部分:名字(token key)和数据(token data)。在使用过程中只需要用他的名字(token key)就可以访问到他的数据(token data)而无需知道他实际的储存位置。token有standard、indexed、counter类型。

EmberZNet PRO提供了API,可直接调用。如token的读写:

读token:void halCommonGetToken( data, token )
写token:void halCommonSetToken( token, data )

上面的token就是token名(token),而data就是他的实际内容了。为了更方便的使用token,ember还特别定义了两种特殊的token:indexed tokens与counter tokens。

index token是以数组的形式来存储的,可以单独读数组成员进行读写;counter token用于需要经常自增1的特殊用法。对于这两种token,有专门的API可以对其进行调用,如以下:

读index token的第index个元素:void halCommonGetIndexedToken( data, token, index )
写index token的地index个元素:void halCommonSetIndexedToken( token, index, data )
使counter token'自增1:void halCommonIncrementCounterToken( token )

当然对于counter token同样可以使用halCommonGetToken和halCommonSetToken来读写,这样会比使用halCommonIncrementCounterToken效率低,而且对sim-eeprom的使用寿命也不利。

那么如果自己要保存一些数据,使之掉电不消失,那就要用到token,那么如何使用token,要怎么做呢?

第一步:使用自定义token需要创建一个自定义的token头文件(xxx.h)名字可以随意取,头文件需要包含下面的内容,这样系统才能知道你是在定义自己的token,这个头文件将包含到工程中,而且对所有工程文件都是可见的。

/**
* Custom Application Tokens
*/


// (第一部分)定义token的名字
#ifdef DEFINETYPES
//(第二部分)这里定义所有token用到的类型
#endif //DEFINETYPES
#ifdef DEFINETOKENS
//(第三部分)这里用来定义token的储存信息
#endif //DEFINETOKENS

第二步:先定义token的名字,也就是在上一步建的头文件中的第一部分定义token的名字,如下:

//定义token的名字

#define CREATOR_DEVICE_INSTALL_DATA (0x000A)
#define CREATOR_HOURLY_TEMPERATURES (0x000B)
#define CREATOR_LIFETIME_HEAT_CYCLES (0x000C)

定义名字时都必须以CREATOR_开头后面接自定义token的名字,如上面INSTALL_DATA就是token的名字。后面的16位字节就是这个token的唯一表示码(token key),最高位(第16bit)为系统token(stack token与manufacturing token)保留,所以我们定义的的token key一定要小于0x8000,也就是说这个token key我们可以自己定,只要不大于0x8000并且没有重复就可以了,上面的例子使用了0x000A-0x000C来作为token key。

第三步:定义token使用的类型,如果token是一个特殊的类型如结构体,那么你就要在这里定义它(在第二部分#ifdef DEFINETYPES与#endif //DEFINETYPES之间)如下:

#ifdef DEFINETYPES
// Include or define any typedef for tokens here
typedef struct {
int8u install_date[11] /** YYYY-mm-dd + NULL */
int8u room_number; /** The room where this device is installed */
} InstallationData_t;
#endif //DEFINETYPES

定义了一个InstallationData_t的结构体,这个将作为token DEVICE_INSTALL_DATA的类型。

第四步:定义token的存储信息,上面已经定义3个token,这里就要定义这三个token要存储的内容(第三部分#ifdef DEFINETOKENS与#endif //DEFINETOKENS之间),如下:

#ifdef DEFINETOKENS

// Define the actual token storage information here
DEFINE_BASIC_TOKEN(DEVICE_INSTALL_DATA,
InstallationData_t,
{0, {0,...}})
DEFINE_INDEXED_TOKEN(HOURLY_TEMPERATURES, int16u, 24, {0,...})
DEFINE_COUNTER_TOKEN(LIFETIME_HEAT_CYCLES, int32u, 0}

#endif //DEFINETOKENS

定义了DEVICE_INSTALL_DATA为普通类型的token,它的数据类型为InstallationData_t,初始值全为0;定义了HOURLY_TEMPERATURES为indexed token,它是一个16位无符号数数组,长度为24,初始值全为0;定义了LIFETIME_HEAT_CYCLES为一个counter token为32位无符号数据类型,初始值为0。

第五步:将头文件包含的工程里

在ember desktop Version: 3.3.1915 (Beta)版本中,有直接包含用户token头文件的选框,在include的选项里如下图:


如果是之前的版本可能没有custom token header的选项卡,也可以直接从上面的code,header file,include paths and libraries选项卡包含进来:


经过以上步骤,就可以使用自定义的token了,如下:

普通token DEVICE_INSTALL_DATA的读写:

InstallationData_t data;
// Read the stored token data
halCommonGetToken(&data, TOKEN_DEVICE_INSTALL_DATA);
// Set the local copy of the data to new values
data.room_number = < user input data >
MEMCOPY(data.install_date, < user input data>, 0, sizeof(data.install_date));
// Update the stored token data with the new values
halCommonSetToken(TOKEN_DEVICE_INSTALL_DATA, &data);


indexed token HOURLY_TEMPERATURES的读写:

int16s getCurrentTargetTemperature(int8u hour) {
int16s temperatureThisHour = 0; /** Stores the temperature for return */
if (hour < HOURS_IN_DAY) {
halCommonGetIndexedToken(&temperatureThisHour,
TOKEN_HOURLY_TEMPERATURES, hour);
}
return temperatureThisHour;
}
void setTargetTemperature(int8u hour, int16s targetTemperature) {
if (hour < HOURS_IN_DAY) {
halCommonSetIndexedToken(TOKEN_HOURLY_TEMPERATURE, hour,&temperatureThisHour);
}
}


counter token LIFETIME_HEAT_CYCLES的用法:

void requestHeatCycle(void) {
/// < application logic to initiate heat cycle >
halCommonIncrementCounterToken(TOKEN_LIFETIME_HEAT_CYCLES);
}
int32u totalHeatCycles(void) {
int32u heatCycles;
halCommonGetToken(&heatCycles, TOKEN_LIFETIME_HEAT_CYCLES);
return heatCycles;
}

上面对各类型的token用法都举了例,注意的是在使用token时,token名都使用了TOKEN_加token名,而不是直接用token名。

最后需要注意的是token是基于flash的sim-eeprom来保存数据的,因为flash的擦写次数有限(相比于真正的eeprom),因此尽量避免频繁地去写token!下一篇博文我想跟大家一起学习一下sim-eeprom的原理。

猜你喜欢

转载自blog.csdn.net/wangchongttg/article/details/50950269