[size=large] 由NVRAM文件管理器管理的数据单元都是逻辑数据项,一个数据项可以被看作为一个固定大小的记录,所以我们根据他们的记录的大小将所有的逻辑数据项分为两种类型;
1,透明数据元(Transparent EF):这个类型的数据项的记录的大小为一个byte;因此,这种数据项可以认为是一系列的bytes;
2,线性固定数据元(linear fixed EF):这个类型的数据项的记录的大小远大于一个byte;所有的数据按线性存储;
如下图所示:
一,先来看“线性固定数据元”
首先我们来新建一项NV;分析每个步骤的原理;
总的步骤必须遵循如下几步:
1,在文件:“nvram_user_defs.h”的枚举结构体“nvram_LID_cust_enum”中定义一个新的LID:“NVRAM_EF_[new logical data item name]_LID”;
注意:请将新LID项加在NVRAM_EF_LAST_LID_CORE.之前;
ex: NVRAM_EF_PORT_SETTING_LID;
lzq:这个LID项的主要作用是什么呢?为什么一定要添加一个LID?因为NVRAM中的数据是在fs文件系统的管理中操作的,而文
件操作需要识别数据项和管理数据项,都是通过这个LID来操作的;
2,在文件:“nvram_user_defs.h”中定义两个常量:SIZE和TOTAL;
ex: #define NVRAM_EF_PORT_SETTING_SIZE 16
#define NVRAM_EF_PORT_SETTING_TOTAL 1
lzq:既然是一块内存,很明显就必须要设置这块内存的大小;这样将结构体的数据保存和读取时都很容易的操作到了特定的内存中;
并且有效的控制的内存不足和溢出的问题;就像是初始话一个数组的大小;
(lzq_091216_补充:如果size是个结构体,则注意这个结构体的定义就和上面的定义写在一起;)
如:
#ifdef __HL_WEB_PHONE__
typedef struct
{
kal_uint8 status; //open or close;
kal_uint32 phone_number[11]; //本机号码;
kal_uint8 number_exten[10];//号码前缀;
kal_uint8 number_zone[8]; //本地区号;
}MY_WEB_PHONE;
#define NVRAM_EF_MY_WEB_PHONE_DATA_SIZE sizeof(MY_WEB_PHONE) //MY_WEB_PHONE
#define NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL 1 //1
#endif
3,在文件:“custom_nvram_editor_data_item.h”中定义版本号:“NVRAM_[new data item name]_LID_VERNO”。
ex: #define NVRAM_EF_PORT_SETTING_LID_VERNO "000"
lzq:由于文件系统管理了这些NV数据;这些数据难免要进行各式的操作,比如修改,添加,删除的操作,那么文件系统是怎么知道
它所管理的这些NV数据已经改变了呢?就是通过这个版本号来识别的,比如你修改了某个NV数据但没有更该它的版本号,文件
系统是不会对原始数据更改的;只有在更改了NV值并且修改了版本号,这时文件系统才识别到已经更改,并进行相应的数据更新
例如 short类型NV的版本号是:NVRAM_EF_CACHE_SHORT_LID_VERNO ;
4,在文件:“nvram_user_config.c”中设置这个新nv项的默认值;
ex:
static kal_uint8 const NVRAM_EF_PORT_SETTING_DEFAULT[] = {
0x01, 0x00,
0x00, 0x00,
0x00, 0xC2, 0x01, 0x00,
0x00, 0xC2, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00
};
lzq:在申请了一块内存后,需要进行初始化默认值;这样在手机的异常时,比如恢复出厂设置时,NV将只载入默认值;
5,在文件:“nvram_user_config.c”中的结构体数组logical_data_item_table_cust[]中新添加一个条目(Add a new entry);
注意:这个新的条目是设置这个LID项的属性的;以提供文件系统来对它操作;
ex:
{
NVRAM_EF_PORT_SETTING_LID,
NVRAM_EF_PORT_SETTING_SIZE,
NVRAM_EF_PORT_SETTING_TOTAL,
NVRAM_EF_PORT_SETTING_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER,
"MP1y", //注意:在这里如果上个是MP1y,那么这里应该为加一为:MP2y,表明有新的条目添加了;
VER(NVRAM_EF_PORT_SETTING_LID),
"Port Settings\0",
NVRAM_RESERVED_VALUE
},
6,在文件custom_nvram_editor_data_item.h 中添加结构体定义;这个结构体定义只为了在使用mata工具时,能看到的新添加的NV项的结构体数组中的各个值;如果不添加将在
mata工具中看不到这个新添加的nv项 ;
ex:这个是透明数据元byte在META工具中将要显示的byte的NV项中所有记录的字符串描述数组的结构体;
typedef struct
{
kal_uint8 CacheByte[NVRAM_CACHE_SIZE];
} nvram_cache_byte_struct ;
7,在文件:custom_nvram_editor_data_item.h中.添加 bit-level 说明;这个也是只为了在mata工具中的操作而实现的;在程序中并用不到 ;
ex:这个是byte项的NV 的META工具中的字符串初始化默认值;
LID_BIT VER_LID(NVRAM_EF_CACHE_BYTE_LID) nvram_cache_byte_struct *NVRAM_CACHE_TOTAL
{
CacheByte:"One-byte parameter setting ";
CacheByte[14]
{
default_lang:8 "Default Language "
{
};
};
CacheByte[24]
{
time_zone:8 "Time Zone (Current City )"
{
};
};
CacheByte[25]
{
date_format:8 "Time Format "
{
};
};
CacheByte[26]
{
date_format:8 "Date Format "
{
};
};
};
整个过程如下图:
lzq总结:NV数据实现了数据的读写保护,保证了数据在手机上正常而安全的使用;我们知道对于手机上的一些属性值,比如开机声音,待机画面等是由一些数据来控制的
,这些数据是全局的,可以在随时随地的对它调用;如果是在一个游戏应用中,我们只要将它设置为一个全局的变量,在游戏开始时进行初始化就可以了;但在手机上我们必须保
证这些数据不能丢失,并且在整个系统运行中当系统出现数据损坏并崩溃时,这些数据也是不会被丢失和更改;保证了手机系统的安全运行;也许我们可以说为什么不用一个文件
来保存这些数据呢?我们知道如果用文件的话,虽然实现了数据的异地保存,但一旦这个文件丢失,将导致系统致命错误;另外,这些数据接受用户的个性修改,如果用文件保存
的话,数据修改并不方便;而且在读写速度上明显不及直接NVRAM存储器的操作;因此,我们可以这样认为,NV让我们将一些数据从全局中取了出来,并放入了一个不能擦除的存
储器中保护起来;
接下来让我们看看NVRAM的结构:
从上图中我们发现,在文件系统中Data Item Management System 管理着NVRAM;而这个管理系统(Data Item Management System)通过内部的一个查询表(lookup table)来获
得每个数据项的具体细节;
而这个查询表(lookup table )包含以下4个部分:
1. MT reign, for project independent data items;
2. MP reign, for MTK /PMT common applications;
3. CT reign, for the customer usage.
4. CV reign, for the vendor of customer usage.
下图显示了NVRAM定制文件布局。我们经常操作的文件一般在CT部分;
NVRAM LID 的定义部分都在以下几个文件中进行:
- nvram_data_items.h : for MT use
- nvram_data_items.c : for MT use
- nvram_common_defs.h : for MP use
- nvram_common_config.c : for MP use
- nvram_user_defs.h : for CT use
- nvram_user_config.c : for CT use
- nvram_cust_pack.c: for CustPack use
- nvram_vendor_config.c: for CV use
- nvram_vendor_defs.h: for CV use
META tool 的说明介绍内容都在以下几个文件中实现;:
- nvram_editor_data_item.h: for MT use
- common_nvram_editor_data_item.h : for MP use
- custom_ nvram_editor_data_item.h : for CT use
- vendor_nvram_editor_data_item.h: for CV use
现在我们回头去看步骤5,添加新的条目的操作中,我们会问,为什么要添加新的条目,而且在这些变量中,各个项的涵义是什么呢? 如下:
ex:
{
NVRAM_EF_PORT_SETTING_LID,
NVRAM_EF_PORT_SETTING_SIZE,
NVRAM_EF_PORT_SETTING_TOTAL,
NVRAM_EF_PORT_SETTING_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER,
"MP1y",
VER(NVRAM_EF_PORT_SETTING_LID),
"Port Settings\0",
NVRAM_RESERVED_VALUE
},
我们刚才知道了,管理系统(Data Item Management System)通过内部的一个查询表(lookup table)来获得每个数据项的具体细节的,我们在这里实现的这个新的条目就是为
了让管理系统通过查询表来找到它并对它进行操作;所以每个新的LID都要来这里添加新的条目;
那么每个新的条目的具体的数据结构是什么样的呢?如下是它的定义:
typedef struct
{
nvram_lid_enum LID;
kal_uint16 size;
kal_uint16 total_records;
kal_uint8 const *default_value;
nvram_attr_enum attr;
nvram_category_enum category;
kal_char fileprefix[FILE_PREFIX_LEN + 1];
kal_char fileverno[FILE_VERNO_LEN + 1];
kal_char *description;
kal_uint8 record_ID;
} ltable_entry_struct;
具体涵义如下:
接下来分别分析一些具体数据项的涵义:
1,属性attr ;
属性选项是个可选的,它由枚举:nvram_attr_enum定义:
NVRAM_ATTR_AVERAGE: 0x0000 //这是个默认的属性选项;
NVRAM_ATTR_IMPORTANT: 0x0001 //当一个IMPORTANT的数据项被更改时,会先将相关程序停止,并被要求进行备份和保存,
//只有在成功备份和保存后,才会将程序重新安全开启;
NVRAM_ATTR_WRITEPROTECT: 0x0002 //写保护,只读;
NVRAM_ATTR_MULTIPLE: 0x0004 //如果一个数据项的属性是multiple,那么NVRAM会自动将它做一个备份,并当在其中有一个数据
//被损坏时,NVRAM会从另个数据中将它还原;
NVRAM_ATTR_CONFIDENTIAL: 0x0008 //对数据采用对称算法进行加密或解密;所以:mulitiple+confidential能实现最好的数据保护;
NVRAM_ATTR_MULTIREC_READ: 0x0010 //适用于那些需要一次性对一数据进行多次读取操作的数据项;
NVRAM_ATTR_OTP: 0x0020 //This attribute is supported only if One Time Programming (OTP) function exists on the flash storage. NVRAM will
//maintain a small table to OTP region; the table consists of all OTP data items, by order in
the lookup table.
NVRAM_ATTR_DIFFERENCE: 0x0080 //NVRAM保留。
2,模板category;
这个选项和attr非常相似,可以说是attr的分支;一个数据项可以属于很多category的或者是很多数据项属于一个category;所以NVRAM需要找到那些需要被category重
新设置的数据项;它的枚举包含如下:
NVRAM_CATEGORY_USER: 0x0000 //默认属性;
NVRAM_CATEGORY_SYSTEM: 0x0001 //一旦版本号更改,这个数据项将被初始化为默认值;
NVRAM_CATEGORY_COMPOSED: 0x0002 //NVRAM 保留;
NVRAM_CATEGORY_FACTORY: 0x0004 //当MSG_ID_NVRAM_RESET_REQ随着 reset_category = NVRAM_RESET_FACTORY,NVRAM
将重新设置NVRAM_CATEGORY_FACTORY的值,并且清除预定义的文件和设置;
NVRAM_CATEGORY_MULTI_DEFAULT: 0x0008 //这样的数据项的每个记录可能有不能的值,但是所有的默认值必须在一个连续的数组里。
NVRAM_CATEGORY_CUSTPACK: 0x0010 //NVRAM will auto assign default values in CustPack BIN to this category. Once the version of
CustPack BIN changes, NVRAM_CATEGORY_CUSTPACK will be reset
to default.
NVRAM_CATEGORY_BRANCH: 0x0020 //This category of data item will be kept even the branch number of software version changes. Every
time the branch number is different from previous one, NVRAM will clear all data items except NVRAM_CATEGORY_BRANCH.
NVRAM_CATEGORY_SHADOW: 0x0040 //This category is only used for single bank NOR-flash. With single bank NOR-flash,
only this category could be modified in normal mode. NVRAM
uses Shadow mechanism to
make device type transparent to applications. Please see
chapter 7. to get more details.
IMPORTANT: Shadow needs additional memory.
NVRAM_CATEGORY_SHADOW_MS: 0x0080 //When USB boot mode, all data item can’t be accessed because of storage exporting.
Thus NVRAM uses Shadow mechanism to make a few applications still
can access their data.
IMPORTANT: Shadow needs additional memory.
我们再来看看LID文件的命名和LID的版本号规则:
File Name Format:
(0~3) File Name
( 4) M.
(5~7) Version
1. File Name: The first 4 bytes of the File Name Format are used for the file name, which needs to be
distinguishable from all other file names. The File naming rule:
- Data items in the core: MT[x][y], where x and y in the range (0~9, a~z)
- Data items in custom/common folder: MP[x][y] , where x and y in the range (0~9, a~z)
- Data items in custom/app folder: CT[x][y] , where x and y in the range (0~9, a~z)
- Data items in vendor folder: CV[x][y] , where x and y in the range (0~9, a~z)
-
?? 4-byte filenames. The file naming MT[x][y], MP[x][y] ,CT[x][y] and CV[]x[y] allow maximum sequence
number up to 36*36 = 1296 each.
IMPORTANT: Any file name MUST be unique.
2. M byte: The byte is used to indicate the ‘multiple’ attribute of the data item.
- If a data item is defined to be ‘multiple’, M can be ‘a’ or ‘b’ to represent two copies of the file.
- If a data item is defined w/o the ‘multiple’ attribute, M will be ‘_’.
3. Version: Three human-readable digits, for example, ‘000’
?? the version number is incremented when a data item is added / deleted or its data structure is changed, or
its attribute is changed.
?? For ease of reading, the 3-byte version number can be used from 000 ~ 999. That means a single LID can
be versioned 1000 times. If the limit is hit, a work-around is to delete the LID and make it a new one with
version 000.
MTK之NVRAM研究[二]
二,再来看“透明逻辑数据元”
这样的数据项已经实现了的三个数据项:
1,byte 数据项;
2,short数据项;
3,double数据项;
这些数据项都已经实现了数据项LID的定义,数据项的定义和值的定义;如:
LID: 在文件Nvram_user_defs.h中:
NVRAM_EF_CACHE_BYTE _LID = NVRAM_LID_CUST_BEGIN,
NVRAM_EF_CACHE_SHORT _LID,
NVRAM_EF_CACHE_DOUBLE _LID,
size:custom_mmi_default_value.h中:
#define NVRAM_CACHE_SIZE 512 //很明显byte,short ,double的数据项都有512个记录,一个记录只有一个byte值 ;
#define NVRAM_CACHE_TOTAL 1
新增数据项在文件:Nvram_user_config.h中
ltable_entry_struct logical_data_item_table_cust[] =
{
{
NVRAM_EF_CACHE_BYTE_LID,
NVRAM_CACHE_SIZE, // 512
NVRAM_CACHE_TOTAL, //1
NVRAM_EF_ZERO_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER | NVRAM_CATEGORY_CUSTPACK | NVRAM_CATEGORY_SHADOW_MS,
"CT00",
VER(NVRAM_EF_CACHE_BYTE_LID),
"1-byte Setting\0",
NVRAM_RESERVED_VALUE
}
,{
NVRAM_EF_CACHE_SHORT_LID,
NVRAM_CACHE_SIZE, // 512
NVRAM_CACHE_TOTAL, // 1
NVRAM_EF_ZERO_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER | NVRAM_CATEGORY_CUSTPACK | NVRAM_CATEGORY_SHADOW_MS,
"CT01",
VER(NVRAM_EF_CACHE_SHORT_LID),
"2-byte Setting\0",
NVRAM_RESERVED_VALUE
}
,{
NVRAM_EF_CACHE_DOUBLE_LID,
NVRAM_CACHE_SIZE, //512
NVRAM_CACHE_TOTAL, //1
NVRAM_EF_ZERO_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER | NVRAM_CATEGORY_CUSTPACK | NVRAM_CATEGORY_SHADOW_MS,
"CT02",
VER(NVRAM_EF_CACHE_DOUBLE_LID),
"8-byte Setting\0",
NVRAM_RESERVED_VALUE
}
...
默认值:
kal_uint8 const NVRAM_EF_ZERO_DEFAULT[] = { 0x00 };
我们先来看一个条目的数据结构:
上图中显示,当total_records == 1时,说明这个LID为透明数据元,size就表示这个逻辑数据项的大小;比如byte,那么就是size=1*512;
如果 total_records != 1 时,说明这个LID为线性固定数据元,total_records 就是记录的个数,size就是每个记录的大小;
( lzq注 :我们从这两种数据元的特征中可以得出这样的结论:
透明数据元相当于一维数组;已经实现了的数据项LID就相当于一个数组byte record[ Record_ID ]; 其中数组个数512; Recodr_ID为枚举ID;
short record2[
Record_ID ]; //Record_ID由用户自己定义并初始化;
double record3[
Recodr_ID ];
线性固定数据元相当于二维数组 :已经实现了的数据项LID就相当于My_type_struct records[ total_records ][ size ];
)
由此分析,我们可以直接当做一个byte数据项的一个记录来直接添加到里面;即在数组record[]中的某个位置从新添加一个值;而不需要另外去实现一个新的byte的LID;大大的
简化了操作;而且在byte,short,double的数据项里新添加一个数据很方便,具体只有两步骤:
1,定义menu_ID
typedef enum
{
......
#ifdef __HQ_CLAMSHELL_TONE__CONTROL__ //参考yj的一个滑盖声音模块的LID;
NVRAM_CLAMSHELL_TONE_CONTROL_SETTING, //定义一个Record_ID;
#endif
......
NVRAM_LAST_BYTE_ELEMENT
} BYTEDATA;
2,将这个数组值设置一个默认值;
#ifdef __HQ_CLAMSHELL_TONE__CONTROL__
BYTE_ENTRY( NVRAM_CLAMSHELL_TONE_CONTROL_SETTING , 0x01 ), //默认值为0x01;
#endif
Appendix:
一,当数据都已经定义完后剩下的就是怎么使用这个数据了;
对透明数据(一维数组)的读写操作有:
WriteValue (NVRAM_CLAMSHELL_TONE_CONTROL_SETTING, &data, DS_BYTE, &error);
ReadValue (NVRAM_CLAMSHELL_TONE_CONTROL_SETTING, &data, DS_BYTE, &error);
对线性固定数据元(二维数组)的读写操作有:
ReadRecord (
NVRAM_EF_TIMING_SMS_LIST_LID, //参考宏:__HQ_TIMING_SMS__
(U16) (i + 1),
(void*)&(g_timingsms_cntx.TaskList[i]),
NVRAM_TIMING_SMS_LIST_RECORD_SIZE,
&error);
WriteRecord (
NVRAM_EF_TIMING_SMS_LIST_LID,
(U16) (index + 1),
(void*)&(g_timingsms_cntx.TaskList[index]),
NVRAM_TIMING_SMS_LIST_RECORD_SIZE,
&error);
二,现在来看下NVRAM的META工具中用到的‘位级别的注释’(bit_level description);
也就是在上面的步骤6和步骤7中的操作;
先让我们来看个资料:NVRAM LID脚本
这个特殊的脚本能够用来描述NVRAM LID;在编译的过程中,这个脚本会解析并且将信息保存到有cgen.exe生成的数据库中;PC工具(如META工具)可以利用这个数据库去
解析这个LID的原始数据;这个脚本可以被保存在一个头文件中并将在由cgen.exe解析之前进行预处理;程序员可以利用标准c语言(,//注释)去编程,并且可以用宏 “#define
” 去控制;
例如:
typedef struct {
kal_uint8 context_id;
kal_uint8 nsapi;
kal_uint8 pdp_addr_type;
kal_uint8 pdp_addr_len;
kal_uint8 addr_val[4];
qos_struct req_qos;
qos_struct min_qos;
kal_uint8 apn_len;
kal_uint8 apn[100];
kal_uint8 pcomp_algo;
kal_uint8 dcomp_algo;
kal_uint8 context_type;
kal_uint8 primary_context_id;
kal_uint8 is_sib_defined;
} nvram_ef_tcm_PDP_profile_record_struct; //lzq:第六步:定义META工具使用的数据结构 ;
typedef struct {
kal_uint8 qos_length;
kal_uint8 unused1;
kal_uint8 delay_class;
kal_uint8 reliability_class;
kal_uint8 peak_throughput;
kal_uint8 unused2;
kal_uint8 precedence_class;
kal_uint8 unused3;
kal_uint8 mean_throughput;
kal_uint8 traffic_class;
kal_uint8 delivery_order;
kal_uint8 delivery_of_err_sdu;
kal_uint8 max_sdu_size;
kal_uint8 max_bitrate_up_lnk;
kal_uint8 max_bitrate_down_lnk;
kal_uint8 residual_bit_err_rate;
kal_uint8 sdu_err_ratio;
kal_uint8 transfer_delay;
kal_uint8 traffic_hndl_priority;
kal_uint8 guarntd_bit_rate_up_lnk;
kal_uint8 guarntd_bit_rate_down_lnk;
} qos_struct; //lzq:在这个例子中,有嵌入式结构体定义;实现原理一样,不过要用到'" 、"来获得子成员变量
;
BEGIN_NVRAM_DATA
LID_BIT VER_LID(NVRAM_EF_TCM_PDP_PROFILE_LID) nvram_ef_tcm_PDP_profile_record_struct*1
{
context_id: "" {}; //lzq:这个是上面定义的数据结构(第6步中实现的)nvram_ef_tcm_PDP_profile_record_struct中的成员变量 ;
addr_val: "Statistic PDP address value, in MSB" {};//lzq:语法: 结构体成员变量名 :"描述语" {更多子项,可以为空 };
addr_val[0]
{
addr_v1:4 " Address Value 1" {};
addr_v2:4 " Address Value 2" {};
};
req_qos: "Requested QoS" {};
req_qos.qos_length: "Length of QoS" {};
req_qos.unused1: "Delay Class"
{
req_qos_identifier:3 " Request QoS Identifier"
{
0x0:"Req QoS Invaild";
0x2:"Req QoS Vaild";
0x4:"Req QoS Under Verifing";
};
req_qos_list:2
{
0x0:"Req QoS List 1";
0x1:"Req QoS List 2";
0x2:"Req QoS List 3";
};
};
req_qos.delay_class: "Delay Class" {};
req_qos.reliability_class: "Reliability Class"
{
reliablity_class:8
{
0x00: "Realiablity Class Zero";
0x01: "Realiablity Class Low";
0x02: "Realiablity Class Medium";
}
}
req_qos.peak_throughput: "Peak Throughput" {};
apn: "APN string" {} ;
};
END_NVRAM_DATA
再来看第二个例子,透明数据员bity的描述实现:
typedef struct
{
kal_uint8 CacheByte[NVRAM_CACHE_SIZE];
} nvram_cache_byte_struct;
LID_BIT VER_LID(NVRAM_EF_CACHE_BYTE_LID)
nvram_cache_byte_struct *NVRAM_CACHE_TOTAL
{
CacheByte :"One-byte parameter setting";
CacheByte [14] //lzq:这里表示在结构体成员变量CacheByte[]数组的第14个数据项的描叙 ;
{
default_lang:8 "Default Language" //default_lang: 8 ---表示直接显示这个串; "Default Language"---表示对这个数据项的补充说明;
{
};
};
CacheByte[24] //lzq:这里表示在结构体成员变量CacheByte[]数组的第24个数据项的描叙 ;
{
time_zone:8 "Time Zone (Current City)"
{
};
};
CacheByte[25] //lzq:这里表示在结构体成员变量CacheByte[]数组的第25个数据项的描叙 ;
{
date_format:8 "Time Format"
{
};
};
CacheByte[26] //lzq:这里表示在结构体成员变量CacheByte[]数组的第26个数据项的描叙 ;
{
date_format:8 "Date Format"
{
};
};
更多的实现功能可以参考原程序中的定义实现,再结合META工具去查看该数据项的显示效果;
lzq自己添加的LID项,如下图;
在实现的过程中,遇到一个问题:
当我们完成所有的步骤(7步)后,当用META工具察看时却发现不了自己新添加的那个LID:NVRAM_EF_MY_NEW_DATA_LID;
分析原因:
没有看到LID说明两个问题:1,在实现的过程中有的地方出错;
2,在用META工具查看时,选择了不对的datebase(数据库),导致手机database和META工具的database
版本不对;
操作:
在检查了所有的原代码后,确认没有出错,再从新new了一遍后,重新用META工具查看时,出现如下图的错误:
说明在选择database时选择了错误的版本,因此用META工具看到的还是原来的老的版本的数据,因此看不到我们新添加的LID;
end 2009-7-17 下午 05:36:39
MTK之NVRAM研究[三]
一,下面来具体看看两个不同的NV项的实现过程,具体的步骤还是和上面的一样的;
这里面实现两中NV项:
NV项一:_LZQ_TEST_ :他的数据结构比较简单,只是一个数组;
NV项二:__HL_WEB_PHONE__ :他的数据结构是个结构体,和NV项一相比有些地方实现不一样;
具体实现如下:
//--------------------在文件中定义NV项的LID:nvram_user_defs.h----------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
NVRAM_EF_MY_NEW_DATA_LID,
#endif
#ifdef __HL_WEB_PHONE__
NVRAM_EF_MY_WEB_PHONE_DATA_LID,
#endif
//--------------------在文件中定义NV项的大小和个数:nvram_user_defs.h----------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
#define NVRAM_EF_MY_NEW_DATA_SIZE 10 // 10 byte each record
#define NVRAM_EF_MY_NEW_DATA_TOTAL 9 //9 records
#endif
#ifdef __HL_WEB_PHONE__
typedef struct
{
kal_uint8 status; //open or close;
kal_uint32 phone_number[11]; //本机号码;
kal_uint8 number_exten[10];//号码前缀;
kal_uint8 number_zone[8]; //本地区号;
}MY_WEB_PHONE;
#define NVRAM_EF_MY_WEB_PHONE_DATA_SIZE sizeof(MY_WEB_PHONE) //MY_WEB_PHONE
#define NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL 1 //1
#endif
//lzq说明:注意这里,新添加的NV项如果用到了数据结构,则一定要和它声明结构体大小的地方一起声明,不然编译时找不到结构体;
//---------------------------在文件中设置NV的默认值:nvram_user_config.c---------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
static kal_uint8 const NVRAM_EF_MY_NEW_DATA_DEFAULT[90] ={
0x12,0x34,0x56,0x78,0x90,
0x12,0x34,0x56,0x78,0x90
};
#endif
//在这里由于NV项二不用默认值,他只要使用平台的默认0值就可以了,所以在这里他不用声明和定义默认值;
//---------------------------在文件中设置NV的属性:nvram_user_config.c---------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
,{
NVRAM_EF_MY_NEW_DATA_LID,
NVRAM_EF_MY_NEW_DATA_SIZE,
NVRAM_EF_MY_NEW_DATA_TOTAL,
NVRAM_EF_MY_NEW_DATA_DEFAULT,//lzq:当不好设置默认值时就用默认的0代替;
NVRAM_ATTR_MULTIPLE,
NVRAM_CATEGORY_USER,
"CT52", //lzq:这是做什么的?
VER(NVRAM_EF_MY_NEW_DATA_LID), //lzq:这是做什么的?
"My new data\0", //lzq:这是做什么的?
NVRAM_INVALID_VALUE
}
#endif
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
,{
NVRAM_EF_MY_WEB_PHONE_DATA_LID,
NVRAM_EF_MY_WEB_PHONE_DATA_SIZE,
NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL,
NVRAM_EF_ZERO_DEFAULT,//NVRAM_EF_MY_NEW_DATA_DEFAULT,//lzq:当不好设置默认值时就用默认的0代替;
NVRAM_ATTR_MULTIPLE,
NVRAM_CATEGORY_USER,
"CT53", //lzq:这是做什么的?
VER(NVRAM_EF_MY_WEB_PHONE_DATA_LID), //lzq:这是做什么的?
"My new data2\0", //lzq:这是做什么的?
NVRAM_INVALID_VALUE
}
#endif
//-----------在文件中设置NV的版本号:custom_nvram_editor_data_item.h---------------
//lzq: 为新添加的NV项添加版本号;
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
#define NVRAM_EF_MY_NEW_DATA_LID_VERNO "002"
#endif
//lzq: 为新添加的NV项添加版本号;
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
#define NVRAM_EF_MY_WEB_PHONE_DATA_LID_VERNO "000"
#endif
//-----------在文件中设置meta属性值:custom_nvram_editor_data_item.h---------------
--------------先添加meta说明的结构体-------------------------------
//lzq: 为新添加的NV项添加NV META工具中的说明结构体;
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
typedef struct
{
kal_uint8 nvram_ef_my_new_data_field[NVRAM_EF_MY_NEW_DATA_SIZE];
}nvram_ef_my_new_data_struct;
#endif
//lzq: 为新添加的NV项添加NV META工具中的说明结构体;
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
typedef struct
{
MY_WEB_PHONE nvram_ef_my_new_data2_field;
}nvram_ef_my_new_data2_struct;
#endif
//lzq说明:在这里声明nvram_ef_my_new_data2_field时一定要用自己的数据结构来声明,不然在meta工具中看不到自己的数据;
----------------然后设置meta说明结构体:---------------------------
//lzq: 为新添加的NV项添加NV META工具中的说明字符串;
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
LID_BIT VER_LID(NVRAM_EF_MY_NEW_DATA_LID) nvram_ef_my_new_data_struct* NVRAM_EF_MY_NEW_DATA_TOTAL
{
nvram_ef_my_new_data_field:"my_new_data setting";
nvram_ef_my_new_data_field[2]
{
MynewData:6 "lzq"
{
};
};
};
#endif
//lzq: 为新添加的NV项添加NV META工具中的说明字符串;
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
LID_BIT VER_LID(NVRAM_EF_MY_WEB_PHONE_DATA_LID) nvram_ef_my_new_data2_struct* NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL
{
};
#endif
具体的结果看下图:
注意:在步骤六中出现了这样的问题:
Reading custom_data succeeded.
Start to parse the custom NVRAM DATA!
make: *** [.\tst\database_classb\BPLGUInfoCustomAppSrc] Error 1
因为在结构体中使用了说明字符串:
LID_BIT VER_LID(NVRAM_EF_MY_WEB_PHONE_DATA_LID) nvram_ef_my_new_data2_struct* NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL
{
//-------------------web phone-----------
nvram_ef_my_new_data2_field:"my_web_phone setting"{};
status:"open or close switch"{};
phone_number:"the phone number"{};
number_exten:"the phone number pre extern"{};
number_zone:"the zone number"{};
};
此时只要将上面的这段红色的代码注释掉就可以了,本来按照文档的解释这样写是没问题的,但不知道为什么会出现问题;高手路过多指教;
另外附上平台的一个NV的流程,仅作参考:
//------1---------在文件中定义LID: nvram_common_defs.h ---------------------------------
NVRAM_EF_WAP_PROFILE_CONTENT_LID,
//-------2----------在文件中 定义结构体common_nvram_editor_data_item.h---------------------------------------
typedef struct
{
kal_uint8 editable;
kal_uint8 empty;
kal_uint16 proxy_port;
kal_uint8 homepage_url[NVRAM_WAP_PROFILE_HOMEPAGE_URL_LEN];
kal_uint8 data_account;
kal_uint8 conn_type;
kal_uint8 proxy_ip[4];
kal_uint8 username[NVRAM_WAP_PROFILE_USERNAME_LEN];
kal_uint8 password[NVRAM_WAP_PROFILE_PASSWORD_LEN];
} nvram_wap_profile_content_struct;
//-------3--------------在文件中定义内存大小:Nvram_common_defs.h------------------------------------------
#define NVRAM_EF_WAP_PROFILE_CONTENT_SIZE sizeof(nvram_wap_profile_content_struct)
#define NVRAM_EF_WAP_PROFILE_CONTENT_TOTAL 10
//--------4-------------在文件中定义默认值:Nvram_common_config.c--------------------------------------------
nvram_wap_profile_content_struct const NVRAM_EF_WAP_PROFILE_CONTENT_DEFAULT[NVRAM_WAP_PROFILE_MAX]=
{
#ifdef CUSTOM_WAP_PROFILE_CONTENT_DEFAULT
CUSTOM_WAP_PROFILE_CONTENT_DEFAULT
#else
{
1,0,80,"http://mobile.fetnet.net",10,1,210,241,199,199,"",""
},
{
1,0,8080,"http://wap.emome.net",11,1,10,1,1,1,"",""
},
}
//-----------5----------------在文件中设置属性nvram_common_config.c--------------------------------------------
,{
NVRAM_EF_WAP_PROFILE_CONTENT_LID,
NVRAM_EF_WAP_PROFILE_CONTENT_SIZE,
NVRAM_EF_WAP_PROFILE_CONTENT_TOTAL,
(kal_uint8*)NVRAM_EF_WAP_PROFILE_CONTENT_DEFAULT,
NVRAM_ATTR_AVERAGE | NVRAM_ATTR_MULTIREC_READ,
NVRAM_CATEGORY_MULTI_DEFAULT,
"MP2U",
VER(NVRAM_EF_WAP_PROFILE_CONTENT_LID),
"wap profile\0",
NVRAM_RESERVED_VALUE
}
//该nv项的lid为:NVRAM_EF_WAP_PROFILE_CONTENT_LID,
//------------6-----------在文件中:common_nvram_editor_data_item.h中设置mata属性-----------------------;
typedef struct
{
nvram_wap_profile_content_struct wapProfile1;
nvram_wap_profile_content_struct wapProfile2;
nvram_wap_profile_content_struct wapProfile3;
nvram_wap_profile_content_struct wapProfile4;
nvram_wap_profile_content_struct wapProfile5;
nvram_wap_profile_content_struct wapProfile6;
nvram_wap_profile_content_struct wapProfile7;
nvram_wap_profile_content_struct wapProfile8;
nvram_wap_profile_content_struct wapProfile9;
nvram_wap_profile_content_struct wapProfile10;
} nvram_meta_wap_profile_content_struct;
LID_BIT VER_LID(NVRAM_EF_WAP_PROFILE_CONTENT_LID)
nvram_meta_wap_profile_content_struct *NVRAM_EF_WAP_PROFILE_CONTENT_TOTAL
{
};
【lzq2010-4-7 下午 04:28:22 补充】
1,在手机中隐藏了一个盘符:C盘;在modis上我们能看到这个盘符里的文件,都是临时文件和NV文件;这个盘符很重要因为在down软件时半擦不会将这个盘里的文件删除;而如
果是全擦的话就会删除这里的全部文件;所以半擦时没有升级版本号的NV不会生效;
另外,升级了版本号的NV是如何生效的需要另外深入研究;[/size]
1,透明数据元(Transparent EF):这个类型的数据项的记录的大小为一个byte;因此,这种数据项可以认为是一系列的bytes;
2,线性固定数据元(linear fixed EF):这个类型的数据项的记录的大小远大于一个byte;所有的数据按线性存储;
如下图所示:
一,先来看“线性固定数据元”
首先我们来新建一项NV;分析每个步骤的原理;
总的步骤必须遵循如下几步:
1,在文件:“nvram_user_defs.h”的枚举结构体“nvram_LID_cust_enum”中定义一个新的LID:“NVRAM_EF_[new logical data item name]_LID”;
注意:请将新LID项加在NVRAM_EF_LAST_LID_CORE.之前;
ex: NVRAM_EF_PORT_SETTING_LID;
lzq:这个LID项的主要作用是什么呢?为什么一定要添加一个LID?因为NVRAM中的数据是在fs文件系统的管理中操作的,而文
件操作需要识别数据项和管理数据项,都是通过这个LID来操作的;
2,在文件:“nvram_user_defs.h”中定义两个常量:SIZE和TOTAL;
ex: #define NVRAM_EF_PORT_SETTING_SIZE 16
#define NVRAM_EF_PORT_SETTING_TOTAL 1
lzq:既然是一块内存,很明显就必须要设置这块内存的大小;这样将结构体的数据保存和读取时都很容易的操作到了特定的内存中;
并且有效的控制的内存不足和溢出的问题;就像是初始话一个数组的大小;
(lzq_091216_补充:如果size是个结构体,则注意这个结构体的定义就和上面的定义写在一起;)
如:
#ifdef __HL_WEB_PHONE__
typedef struct
{
kal_uint8 status; //open or close;
kal_uint32 phone_number[11]; //本机号码;
kal_uint8 number_exten[10];//号码前缀;
kal_uint8 number_zone[8]; //本地区号;
}MY_WEB_PHONE;
#define NVRAM_EF_MY_WEB_PHONE_DATA_SIZE sizeof(MY_WEB_PHONE) //MY_WEB_PHONE
#define NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL 1 //1
#endif
3,在文件:“custom_nvram_editor_data_item.h”中定义版本号:“NVRAM_[new data item name]_LID_VERNO”。
ex: #define NVRAM_EF_PORT_SETTING_LID_VERNO "000"
lzq:由于文件系统管理了这些NV数据;这些数据难免要进行各式的操作,比如修改,添加,删除的操作,那么文件系统是怎么知道
它所管理的这些NV数据已经改变了呢?就是通过这个版本号来识别的,比如你修改了某个NV数据但没有更该它的版本号,文件
系统是不会对原始数据更改的;只有在更改了NV值并且修改了版本号,这时文件系统才识别到已经更改,并进行相应的数据更新
例如 short类型NV的版本号是:NVRAM_EF_CACHE_SHORT_LID_VERNO ;
4,在文件:“nvram_user_config.c”中设置这个新nv项的默认值;
ex:
static kal_uint8 const NVRAM_EF_PORT_SETTING_DEFAULT[] = {
0x01, 0x00,
0x00, 0x00,
0x00, 0xC2, 0x01, 0x00,
0x00, 0xC2, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00
};
lzq:在申请了一块内存后,需要进行初始化默认值;这样在手机的异常时,比如恢复出厂设置时,NV将只载入默认值;
5,在文件:“nvram_user_config.c”中的结构体数组logical_data_item_table_cust[]中新添加一个条目(Add a new entry);
注意:这个新的条目是设置这个LID项的属性的;以提供文件系统来对它操作;
ex:
{
NVRAM_EF_PORT_SETTING_LID,
NVRAM_EF_PORT_SETTING_SIZE,
NVRAM_EF_PORT_SETTING_TOTAL,
NVRAM_EF_PORT_SETTING_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER,
"MP1y", //注意:在这里如果上个是MP1y,那么这里应该为加一为:MP2y,表明有新的条目添加了;
VER(NVRAM_EF_PORT_SETTING_LID),
"Port Settings\0",
NVRAM_RESERVED_VALUE
},
6,在文件custom_nvram_editor_data_item.h 中添加结构体定义;这个结构体定义只为了在使用mata工具时,能看到的新添加的NV项的结构体数组中的各个值;如果不添加将在
mata工具中看不到这个新添加的nv项 ;
ex:这个是透明数据元byte在META工具中将要显示的byte的NV项中所有记录的字符串描述数组的结构体;
typedef struct
{
kal_uint8 CacheByte[NVRAM_CACHE_SIZE];
} nvram_cache_byte_struct ;
7,在文件:custom_nvram_editor_data_item.h中.添加 bit-level 说明;这个也是只为了在mata工具中的操作而实现的;在程序中并用不到 ;
ex:这个是byte项的NV 的META工具中的字符串初始化默认值;
LID_BIT VER_LID(NVRAM_EF_CACHE_BYTE_LID) nvram_cache_byte_struct *NVRAM_CACHE_TOTAL
{
CacheByte:"One-byte parameter setting ";
CacheByte[14]
{
default_lang:8 "Default Language "
{
};
};
CacheByte[24]
{
time_zone:8 "Time Zone (Current City )"
{
};
};
CacheByte[25]
{
date_format:8 "Time Format "
{
};
};
CacheByte[26]
{
date_format:8 "Date Format "
{
};
};
};
整个过程如下图:
lzq总结:NV数据实现了数据的读写保护,保证了数据在手机上正常而安全的使用;我们知道对于手机上的一些属性值,比如开机声音,待机画面等是由一些数据来控制的
,这些数据是全局的,可以在随时随地的对它调用;如果是在一个游戏应用中,我们只要将它设置为一个全局的变量,在游戏开始时进行初始化就可以了;但在手机上我们必须保
证这些数据不能丢失,并且在整个系统运行中当系统出现数据损坏并崩溃时,这些数据也是不会被丢失和更改;保证了手机系统的安全运行;也许我们可以说为什么不用一个文件
来保存这些数据呢?我们知道如果用文件的话,虽然实现了数据的异地保存,但一旦这个文件丢失,将导致系统致命错误;另外,这些数据接受用户的个性修改,如果用文件保存
的话,数据修改并不方便;而且在读写速度上明显不及直接NVRAM存储器的操作;因此,我们可以这样认为,NV让我们将一些数据从全局中取了出来,并放入了一个不能擦除的存
储器中保护起来;
接下来让我们看看NVRAM的结构:
从上图中我们发现,在文件系统中Data Item Management System 管理着NVRAM;而这个管理系统(Data Item Management System)通过内部的一个查询表(lookup table)来获
得每个数据项的具体细节;
而这个查询表(lookup table )包含以下4个部分:
1. MT reign, for project independent data items;
2. MP reign, for MTK /PMT common applications;
3. CT reign, for the customer usage.
4. CV reign, for the vendor of customer usage.
下图显示了NVRAM定制文件布局。我们经常操作的文件一般在CT部分;
NVRAM LID 的定义部分都在以下几个文件中进行:
- nvram_data_items.h : for MT use
- nvram_data_items.c : for MT use
- nvram_common_defs.h : for MP use
- nvram_common_config.c : for MP use
- nvram_user_defs.h : for CT use
- nvram_user_config.c : for CT use
- nvram_cust_pack.c: for CustPack use
- nvram_vendor_config.c: for CV use
- nvram_vendor_defs.h: for CV use
META tool 的说明介绍内容都在以下几个文件中实现;:
- nvram_editor_data_item.h: for MT use
- common_nvram_editor_data_item.h : for MP use
- custom_ nvram_editor_data_item.h : for CT use
- vendor_nvram_editor_data_item.h: for CV use
现在我们回头去看步骤5,添加新的条目的操作中,我们会问,为什么要添加新的条目,而且在这些变量中,各个项的涵义是什么呢? 如下:
ex:
{
NVRAM_EF_PORT_SETTING_LID,
NVRAM_EF_PORT_SETTING_SIZE,
NVRAM_EF_PORT_SETTING_TOTAL,
NVRAM_EF_PORT_SETTING_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER,
"MP1y",
VER(NVRAM_EF_PORT_SETTING_LID),
"Port Settings\0",
NVRAM_RESERVED_VALUE
},
我们刚才知道了,管理系统(Data Item Management System)通过内部的一个查询表(lookup table)来获得每个数据项的具体细节的,我们在这里实现的这个新的条目就是为
了让管理系统通过查询表来找到它并对它进行操作;所以每个新的LID都要来这里添加新的条目;
那么每个新的条目的具体的数据结构是什么样的呢?如下是它的定义:
typedef struct
{
nvram_lid_enum LID;
kal_uint16 size;
kal_uint16 total_records;
kal_uint8 const *default_value;
nvram_attr_enum attr;
nvram_category_enum category;
kal_char fileprefix[FILE_PREFIX_LEN + 1];
kal_char fileverno[FILE_VERNO_LEN + 1];
kal_char *description;
kal_uint8 record_ID;
} ltable_entry_struct;
具体涵义如下:
接下来分别分析一些具体数据项的涵义:
1,属性attr ;
属性选项是个可选的,它由枚举:nvram_attr_enum定义:
NVRAM_ATTR_AVERAGE: 0x0000 //这是个默认的属性选项;
NVRAM_ATTR_IMPORTANT: 0x0001 //当一个IMPORTANT的数据项被更改时,会先将相关程序停止,并被要求进行备份和保存,
//只有在成功备份和保存后,才会将程序重新安全开启;
NVRAM_ATTR_WRITEPROTECT: 0x0002 //写保护,只读;
NVRAM_ATTR_MULTIPLE: 0x0004 //如果一个数据项的属性是multiple,那么NVRAM会自动将它做一个备份,并当在其中有一个数据
//被损坏时,NVRAM会从另个数据中将它还原;
NVRAM_ATTR_CONFIDENTIAL: 0x0008 //对数据采用对称算法进行加密或解密;所以:mulitiple+confidential能实现最好的数据保护;
NVRAM_ATTR_MULTIREC_READ: 0x0010 //适用于那些需要一次性对一数据进行多次读取操作的数据项;
NVRAM_ATTR_OTP: 0x0020 //This attribute is supported only if One Time Programming (OTP) function exists on the flash storage. NVRAM will
//maintain a small table to OTP region; the table consists of all OTP data items, by order in
the lookup table.
NVRAM_ATTR_DIFFERENCE: 0x0080 //NVRAM保留。
2,模板category;
这个选项和attr非常相似,可以说是attr的分支;一个数据项可以属于很多category的或者是很多数据项属于一个category;所以NVRAM需要找到那些需要被category重
新设置的数据项;它的枚举包含如下:
NVRAM_CATEGORY_USER: 0x0000 //默认属性;
NVRAM_CATEGORY_SYSTEM: 0x0001 //一旦版本号更改,这个数据项将被初始化为默认值;
NVRAM_CATEGORY_COMPOSED: 0x0002 //NVRAM 保留;
NVRAM_CATEGORY_FACTORY: 0x0004 //当MSG_ID_NVRAM_RESET_REQ随着 reset_category = NVRAM_RESET_FACTORY,NVRAM
将重新设置NVRAM_CATEGORY_FACTORY的值,并且清除预定义的文件和设置;
NVRAM_CATEGORY_MULTI_DEFAULT: 0x0008 //这样的数据项的每个记录可能有不能的值,但是所有的默认值必须在一个连续的数组里。
NVRAM_CATEGORY_CUSTPACK: 0x0010 //NVRAM will auto assign default values in CustPack BIN to this category. Once the version of
CustPack BIN changes, NVRAM_CATEGORY_CUSTPACK will be reset
to default.
NVRAM_CATEGORY_BRANCH: 0x0020 //This category of data item will be kept even the branch number of software version changes. Every
time the branch number is different from previous one, NVRAM will clear all data items except NVRAM_CATEGORY_BRANCH.
NVRAM_CATEGORY_SHADOW: 0x0040 //This category is only used for single bank NOR-flash. With single bank NOR-flash,
only this category could be modified in normal mode. NVRAM
uses Shadow mechanism to
make device type transparent to applications. Please see
chapter 7. to get more details.
IMPORTANT: Shadow needs additional memory.
NVRAM_CATEGORY_SHADOW_MS: 0x0080 //When USB boot mode, all data item can’t be accessed because of storage exporting.
Thus NVRAM uses Shadow mechanism to make a few applications still
can access their data.
IMPORTANT: Shadow needs additional memory.
我们再来看看LID文件的命名和LID的版本号规则:
File Name Format:
(0~3) File Name
( 4) M.
(5~7) Version
1. File Name: The first 4 bytes of the File Name Format are used for the file name, which needs to be
distinguishable from all other file names. The File naming rule:
- Data items in the core: MT[x][y], where x and y in the range (0~9, a~z)
- Data items in custom/common folder: MP[x][y] , where x and y in the range (0~9, a~z)
- Data items in custom/app folder: CT[x][y] , where x and y in the range (0~9, a~z)
- Data items in vendor folder: CV[x][y] , where x and y in the range (0~9, a~z)
-
?? 4-byte filenames. The file naming MT[x][y], MP[x][y] ,CT[x][y] and CV[]x[y] allow maximum sequence
number up to 36*36 = 1296 each.
IMPORTANT: Any file name MUST be unique.
2. M byte: The byte is used to indicate the ‘multiple’ attribute of the data item.
- If a data item is defined to be ‘multiple’, M can be ‘a’ or ‘b’ to represent two copies of the file.
- If a data item is defined w/o the ‘multiple’ attribute, M will be ‘_’.
3. Version: Three human-readable digits, for example, ‘000’
?? the version number is incremented when a data item is added / deleted or its data structure is changed, or
its attribute is changed.
?? For ease of reading, the 3-byte version number can be used from 000 ~ 999. That means a single LID can
be versioned 1000 times. If the limit is hit, a work-around is to delete the LID and make it a new one with
version 000.
MTK之NVRAM研究[二]
二,再来看“透明逻辑数据元”
这样的数据项已经实现了的三个数据项:
1,byte 数据项;
2,short数据项;
3,double数据项;
这些数据项都已经实现了数据项LID的定义,数据项的定义和值的定义;如:
LID: 在文件Nvram_user_defs.h中:
NVRAM_EF_CACHE_BYTE _LID = NVRAM_LID_CUST_BEGIN,
NVRAM_EF_CACHE_SHORT _LID,
NVRAM_EF_CACHE_DOUBLE _LID,
size:custom_mmi_default_value.h中:
#define NVRAM_CACHE_SIZE 512 //很明显byte,short ,double的数据项都有512个记录,一个记录只有一个byte值 ;
#define NVRAM_CACHE_TOTAL 1
新增数据项在文件:Nvram_user_config.h中
ltable_entry_struct logical_data_item_table_cust[] =
{
{
NVRAM_EF_CACHE_BYTE_LID,
NVRAM_CACHE_SIZE, // 512
NVRAM_CACHE_TOTAL, //1
NVRAM_EF_ZERO_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER | NVRAM_CATEGORY_CUSTPACK | NVRAM_CATEGORY_SHADOW_MS,
"CT00",
VER(NVRAM_EF_CACHE_BYTE_LID),
"1-byte Setting\0",
NVRAM_RESERVED_VALUE
}
,{
NVRAM_EF_CACHE_SHORT_LID,
NVRAM_CACHE_SIZE, // 512
NVRAM_CACHE_TOTAL, // 1
NVRAM_EF_ZERO_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER | NVRAM_CATEGORY_CUSTPACK | NVRAM_CATEGORY_SHADOW_MS,
"CT01",
VER(NVRAM_EF_CACHE_SHORT_LID),
"2-byte Setting\0",
NVRAM_RESERVED_VALUE
}
,{
NVRAM_EF_CACHE_DOUBLE_LID,
NVRAM_CACHE_SIZE, //512
NVRAM_CACHE_TOTAL, //1
NVRAM_EF_ZERO_DEFAULT,
NVRAM_ATTR_AVERAGE,
NVRAM_CATEGORY_USER | NVRAM_CATEGORY_CUSTPACK | NVRAM_CATEGORY_SHADOW_MS,
"CT02",
VER(NVRAM_EF_CACHE_DOUBLE_LID),
"8-byte Setting\0",
NVRAM_RESERVED_VALUE
}
...
默认值:
kal_uint8 const NVRAM_EF_ZERO_DEFAULT[] = { 0x00 };
我们先来看一个条目的数据结构:
上图中显示,当total_records == 1时,说明这个LID为透明数据元,size就表示这个逻辑数据项的大小;比如byte,那么就是size=1*512;
如果 total_records != 1 时,说明这个LID为线性固定数据元,total_records 就是记录的个数,size就是每个记录的大小;
( lzq注 :我们从这两种数据元的特征中可以得出这样的结论:
透明数据元相当于一维数组;已经实现了的数据项LID就相当于一个数组byte record[ Record_ID ]; 其中数组个数512; Recodr_ID为枚举ID;
short record2[
Record_ID ]; //Record_ID由用户自己定义并初始化;
double record3[
Recodr_ID ];
线性固定数据元相当于二维数组 :已经实现了的数据项LID就相当于My_type_struct records[ total_records ][ size ];
)
由此分析,我们可以直接当做一个byte数据项的一个记录来直接添加到里面;即在数组record[]中的某个位置从新添加一个值;而不需要另外去实现一个新的byte的LID;大大的
简化了操作;而且在byte,short,double的数据项里新添加一个数据很方便,具体只有两步骤:
1,定义menu_ID
typedef enum
{
......
#ifdef __HQ_CLAMSHELL_TONE__CONTROL__ //参考yj的一个滑盖声音模块的LID;
NVRAM_CLAMSHELL_TONE_CONTROL_SETTING, //定义一个Record_ID;
#endif
......
NVRAM_LAST_BYTE_ELEMENT
} BYTEDATA;
2,将这个数组值设置一个默认值;
#ifdef __HQ_CLAMSHELL_TONE__CONTROL__
BYTE_ENTRY( NVRAM_CLAMSHELL_TONE_CONTROL_SETTING , 0x01 ), //默认值为0x01;
#endif
Appendix:
一,当数据都已经定义完后剩下的就是怎么使用这个数据了;
对透明数据(一维数组)的读写操作有:
WriteValue (NVRAM_CLAMSHELL_TONE_CONTROL_SETTING, &data, DS_BYTE, &error);
ReadValue (NVRAM_CLAMSHELL_TONE_CONTROL_SETTING, &data, DS_BYTE, &error);
对线性固定数据元(二维数组)的读写操作有:
ReadRecord (
NVRAM_EF_TIMING_SMS_LIST_LID, //参考宏:__HQ_TIMING_SMS__
(U16) (i + 1),
(void*)&(g_timingsms_cntx.TaskList[i]),
NVRAM_TIMING_SMS_LIST_RECORD_SIZE,
&error);
WriteRecord (
NVRAM_EF_TIMING_SMS_LIST_LID,
(U16) (index + 1),
(void*)&(g_timingsms_cntx.TaskList[index]),
NVRAM_TIMING_SMS_LIST_RECORD_SIZE,
&error);
二,现在来看下NVRAM的META工具中用到的‘位级别的注释’(bit_level description);
也就是在上面的步骤6和步骤7中的操作;
先让我们来看个资料:NVRAM LID脚本
这个特殊的脚本能够用来描述NVRAM LID;在编译的过程中,这个脚本会解析并且将信息保存到有cgen.exe生成的数据库中;PC工具(如META工具)可以利用这个数据库去
解析这个LID的原始数据;这个脚本可以被保存在一个头文件中并将在由cgen.exe解析之前进行预处理;程序员可以利用标准c语言(,//注释)去编程,并且可以用宏 “#define
” 去控制;
例如:
typedef struct {
kal_uint8 context_id;
kal_uint8 nsapi;
kal_uint8 pdp_addr_type;
kal_uint8 pdp_addr_len;
kal_uint8 addr_val[4];
qos_struct req_qos;
qos_struct min_qos;
kal_uint8 apn_len;
kal_uint8 apn[100];
kal_uint8 pcomp_algo;
kal_uint8 dcomp_algo;
kal_uint8 context_type;
kal_uint8 primary_context_id;
kal_uint8 is_sib_defined;
} nvram_ef_tcm_PDP_profile_record_struct; //lzq:第六步:定义META工具使用的数据结构 ;
typedef struct {
kal_uint8 qos_length;
kal_uint8 unused1;
kal_uint8 delay_class;
kal_uint8 reliability_class;
kal_uint8 peak_throughput;
kal_uint8 unused2;
kal_uint8 precedence_class;
kal_uint8 unused3;
kal_uint8 mean_throughput;
kal_uint8 traffic_class;
kal_uint8 delivery_order;
kal_uint8 delivery_of_err_sdu;
kal_uint8 max_sdu_size;
kal_uint8 max_bitrate_up_lnk;
kal_uint8 max_bitrate_down_lnk;
kal_uint8 residual_bit_err_rate;
kal_uint8 sdu_err_ratio;
kal_uint8 transfer_delay;
kal_uint8 traffic_hndl_priority;
kal_uint8 guarntd_bit_rate_up_lnk;
kal_uint8 guarntd_bit_rate_down_lnk;
} qos_struct; //lzq:在这个例子中,有嵌入式结构体定义;实现原理一样,不过要用到'" 、"来获得子成员变量
;
BEGIN_NVRAM_DATA
LID_BIT VER_LID(NVRAM_EF_TCM_PDP_PROFILE_LID) nvram_ef_tcm_PDP_profile_record_struct*1
{
context_id: "" {}; //lzq:这个是上面定义的数据结构(第6步中实现的)nvram_ef_tcm_PDP_profile_record_struct中的成员变量 ;
addr_val: "Statistic PDP address value, in MSB" {};//lzq:语法: 结构体成员变量名 :"描述语" {更多子项,可以为空 };
addr_val[0]
{
addr_v1:4 " Address Value 1" {};
addr_v2:4 " Address Value 2" {};
};
req_qos: "Requested QoS" {};
req_qos.qos_length: "Length of QoS" {};
req_qos.unused1: "Delay Class"
{
req_qos_identifier:3 " Request QoS Identifier"
{
0x0:"Req QoS Invaild";
0x2:"Req QoS Vaild";
0x4:"Req QoS Under Verifing";
};
req_qos_list:2
{
0x0:"Req QoS List 1";
0x1:"Req QoS List 2";
0x2:"Req QoS List 3";
};
};
req_qos.delay_class: "Delay Class" {};
req_qos.reliability_class: "Reliability Class"
{
reliablity_class:8
{
0x00: "Realiablity Class Zero";
0x01: "Realiablity Class Low";
0x02: "Realiablity Class Medium";
}
}
req_qos.peak_throughput: "Peak Throughput" {};
apn: "APN string" {} ;
};
END_NVRAM_DATA
再来看第二个例子,透明数据员bity的描述实现:
typedef struct
{
kal_uint8 CacheByte[NVRAM_CACHE_SIZE];
} nvram_cache_byte_struct;
LID_BIT VER_LID(NVRAM_EF_CACHE_BYTE_LID)
nvram_cache_byte_struct *NVRAM_CACHE_TOTAL
{
CacheByte :"One-byte parameter setting";
CacheByte [14] //lzq:这里表示在结构体成员变量CacheByte[]数组的第14个数据项的描叙 ;
{
default_lang:8 "Default Language" //default_lang: 8 ---表示直接显示这个串; "Default Language"---表示对这个数据项的补充说明;
{
};
};
CacheByte[24] //lzq:这里表示在结构体成员变量CacheByte[]数组的第24个数据项的描叙 ;
{
time_zone:8 "Time Zone (Current City)"
{
};
};
CacheByte[25] //lzq:这里表示在结构体成员变量CacheByte[]数组的第25个数据项的描叙 ;
{
date_format:8 "Time Format"
{
};
};
CacheByte[26] //lzq:这里表示在结构体成员变量CacheByte[]数组的第26个数据项的描叙 ;
{
date_format:8 "Date Format"
{
};
};
更多的实现功能可以参考原程序中的定义实现,再结合META工具去查看该数据项的显示效果;
lzq自己添加的LID项,如下图;
在实现的过程中,遇到一个问题:
当我们完成所有的步骤(7步)后,当用META工具察看时却发现不了自己新添加的那个LID:NVRAM_EF_MY_NEW_DATA_LID;
分析原因:
没有看到LID说明两个问题:1,在实现的过程中有的地方出错;
2,在用META工具查看时,选择了不对的datebase(数据库),导致手机database和META工具的database
版本不对;
操作:
在检查了所有的原代码后,确认没有出错,再从新new了一遍后,重新用META工具查看时,出现如下图的错误:
说明在选择database时选择了错误的版本,因此用META工具看到的还是原来的老的版本的数据,因此看不到我们新添加的LID;
end 2009-7-17 下午 05:36:39
MTK之NVRAM研究[三]
一,下面来具体看看两个不同的NV项的实现过程,具体的步骤还是和上面的一样的;
这里面实现两中NV项:
NV项一:_LZQ_TEST_ :他的数据结构比较简单,只是一个数组;
NV项二:__HL_WEB_PHONE__ :他的数据结构是个结构体,和NV项一相比有些地方实现不一样;
具体实现如下:
//--------------------在文件中定义NV项的LID:nvram_user_defs.h----------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
NVRAM_EF_MY_NEW_DATA_LID,
#endif
#ifdef __HL_WEB_PHONE__
NVRAM_EF_MY_WEB_PHONE_DATA_LID,
#endif
//--------------------在文件中定义NV项的大小和个数:nvram_user_defs.h----------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
#define NVRAM_EF_MY_NEW_DATA_SIZE 10 // 10 byte each record
#define NVRAM_EF_MY_NEW_DATA_TOTAL 9 //9 records
#endif
#ifdef __HL_WEB_PHONE__
typedef struct
{
kal_uint8 status; //open or close;
kal_uint32 phone_number[11]; //本机号码;
kal_uint8 number_exten[10];//号码前缀;
kal_uint8 number_zone[8]; //本地区号;
}MY_WEB_PHONE;
#define NVRAM_EF_MY_WEB_PHONE_DATA_SIZE sizeof(MY_WEB_PHONE) //MY_WEB_PHONE
#define NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL 1 //1
#endif
//lzq说明:注意这里,新添加的NV项如果用到了数据结构,则一定要和它声明结构体大小的地方一起声明,不然编译时找不到结构体;
//---------------------------在文件中设置NV的默认值:nvram_user_config.c---------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
static kal_uint8 const NVRAM_EF_MY_NEW_DATA_DEFAULT[90] ={
0x12,0x34,0x56,0x78,0x90,
0x12,0x34,0x56,0x78,0x90
};
#endif
//在这里由于NV项二不用默认值,他只要使用平台的默认0值就可以了,所以在这里他不用声明和定义默认值;
//---------------------------在文件中设置NV的属性:nvram_user_config.c---------
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
,{
NVRAM_EF_MY_NEW_DATA_LID,
NVRAM_EF_MY_NEW_DATA_SIZE,
NVRAM_EF_MY_NEW_DATA_TOTAL,
NVRAM_EF_MY_NEW_DATA_DEFAULT,//lzq:当不好设置默认值时就用默认的0代替;
NVRAM_ATTR_MULTIPLE,
NVRAM_CATEGORY_USER,
"CT52", //lzq:这是做什么的?
VER(NVRAM_EF_MY_NEW_DATA_LID), //lzq:这是做什么的?
"My new data\0", //lzq:这是做什么的?
NVRAM_INVALID_VALUE
}
#endif
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
,{
NVRAM_EF_MY_WEB_PHONE_DATA_LID,
NVRAM_EF_MY_WEB_PHONE_DATA_SIZE,
NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL,
NVRAM_EF_ZERO_DEFAULT,//NVRAM_EF_MY_NEW_DATA_DEFAULT,//lzq:当不好设置默认值时就用默认的0代替;
NVRAM_ATTR_MULTIPLE,
NVRAM_CATEGORY_USER,
"CT53", //lzq:这是做什么的?
VER(NVRAM_EF_MY_WEB_PHONE_DATA_LID), //lzq:这是做什么的?
"My new data2\0", //lzq:这是做什么的?
NVRAM_INVALID_VALUE
}
#endif
//-----------在文件中设置NV的版本号:custom_nvram_editor_data_item.h---------------
//lzq: 为新添加的NV项添加版本号;
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
#define NVRAM_EF_MY_NEW_DATA_LID_VERNO "002"
#endif
//lzq: 为新添加的NV项添加版本号;
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
#define NVRAM_EF_MY_WEB_PHONE_DATA_LID_VERNO "000"
#endif
//-----------在文件中设置meta属性值:custom_nvram_editor_data_item.h---------------
--------------先添加meta说明的结构体-------------------------------
//lzq: 为新添加的NV项添加NV META工具中的说明结构体;
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
typedef struct
{
kal_uint8 nvram_ef_my_new_data_field[NVRAM_EF_MY_NEW_DATA_SIZE];
}nvram_ef_my_new_data_struct;
#endif
//lzq: 为新添加的NV项添加NV META工具中的说明结构体;
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
typedef struct
{
MY_WEB_PHONE nvram_ef_my_new_data2_field;
}nvram_ef_my_new_data2_struct;
#endif
//lzq说明:在这里声明nvram_ef_my_new_data2_field时一定要用自己的数据结构来声明,不然在meta工具中看不到自己的数据;
----------------然后设置meta说明结构体:---------------------------
//lzq: 为新添加的NV项添加NV META工具中的说明字符串;
#ifdef _LZQ_TEST_ //__HQ_ADD_BOOKMARK_DEFAULT__
LID_BIT VER_LID(NVRAM_EF_MY_NEW_DATA_LID) nvram_ef_my_new_data_struct* NVRAM_EF_MY_NEW_DATA_TOTAL
{
nvram_ef_my_new_data_field:"my_new_data setting";
nvram_ef_my_new_data_field[2]
{
MynewData:6 "lzq"
{
};
};
};
#endif
//lzq: 为新添加的NV项添加NV META工具中的说明字符串;
#ifdef __HL_WEB_PHONE__ //__HQ_ADD_BOOKMARK_DEFAULT__
LID_BIT VER_LID(NVRAM_EF_MY_WEB_PHONE_DATA_LID) nvram_ef_my_new_data2_struct* NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL
{
};
#endif
具体的结果看下图:
注意:在步骤六中出现了这样的问题:
Reading custom_data succeeded.
Start to parse the custom NVRAM DATA!
make: *** [.\tst\database_classb\BPLGUInfoCustomAppSrc] Error 1
因为在结构体中使用了说明字符串:
LID_BIT VER_LID(NVRAM_EF_MY_WEB_PHONE_DATA_LID) nvram_ef_my_new_data2_struct* NVRAM_EF_MY_WEB_PHONE_DATA_TOTAL
{
//-------------------web phone-----------
nvram_ef_my_new_data2_field:"my_web_phone setting"{};
status:"open or close switch"{};
phone_number:"the phone number"{};
number_exten:"the phone number pre extern"{};
number_zone:"the zone number"{};
};
此时只要将上面的这段红色的代码注释掉就可以了,本来按照文档的解释这样写是没问题的,但不知道为什么会出现问题;高手路过多指教;
另外附上平台的一个NV的流程,仅作参考:
//------1---------在文件中定义LID: nvram_common_defs.h ---------------------------------
NVRAM_EF_WAP_PROFILE_CONTENT_LID,
//-------2----------在文件中 定义结构体common_nvram_editor_data_item.h---------------------------------------
typedef struct
{
kal_uint8 editable;
kal_uint8 empty;
kal_uint16 proxy_port;
kal_uint8 homepage_url[NVRAM_WAP_PROFILE_HOMEPAGE_URL_LEN];
kal_uint8 data_account;
kal_uint8 conn_type;
kal_uint8 proxy_ip[4];
kal_uint8 username[NVRAM_WAP_PROFILE_USERNAME_LEN];
kal_uint8 password[NVRAM_WAP_PROFILE_PASSWORD_LEN];
} nvram_wap_profile_content_struct;
//-------3--------------在文件中定义内存大小:Nvram_common_defs.h------------------------------------------
#define NVRAM_EF_WAP_PROFILE_CONTENT_SIZE sizeof(nvram_wap_profile_content_struct)
#define NVRAM_EF_WAP_PROFILE_CONTENT_TOTAL 10
//--------4-------------在文件中定义默认值:Nvram_common_config.c--------------------------------------------
nvram_wap_profile_content_struct const NVRAM_EF_WAP_PROFILE_CONTENT_DEFAULT[NVRAM_WAP_PROFILE_MAX]=
{
#ifdef CUSTOM_WAP_PROFILE_CONTENT_DEFAULT
CUSTOM_WAP_PROFILE_CONTENT_DEFAULT
#else
{
1,0,80,"http://mobile.fetnet.net",10,1,210,241,199,199,"",""
},
{
1,0,8080,"http://wap.emome.net",11,1,10,1,1,1,"",""
},
}
//-----------5----------------在文件中设置属性nvram_common_config.c--------------------------------------------
,{
NVRAM_EF_WAP_PROFILE_CONTENT_LID,
NVRAM_EF_WAP_PROFILE_CONTENT_SIZE,
NVRAM_EF_WAP_PROFILE_CONTENT_TOTAL,
(kal_uint8*)NVRAM_EF_WAP_PROFILE_CONTENT_DEFAULT,
NVRAM_ATTR_AVERAGE | NVRAM_ATTR_MULTIREC_READ,
NVRAM_CATEGORY_MULTI_DEFAULT,
"MP2U",
VER(NVRAM_EF_WAP_PROFILE_CONTENT_LID),
"wap profile\0",
NVRAM_RESERVED_VALUE
}
//该nv项的lid为:NVRAM_EF_WAP_PROFILE_CONTENT_LID,
//------------6-----------在文件中:common_nvram_editor_data_item.h中设置mata属性-----------------------;
typedef struct
{
nvram_wap_profile_content_struct wapProfile1;
nvram_wap_profile_content_struct wapProfile2;
nvram_wap_profile_content_struct wapProfile3;
nvram_wap_profile_content_struct wapProfile4;
nvram_wap_profile_content_struct wapProfile5;
nvram_wap_profile_content_struct wapProfile6;
nvram_wap_profile_content_struct wapProfile7;
nvram_wap_profile_content_struct wapProfile8;
nvram_wap_profile_content_struct wapProfile9;
nvram_wap_profile_content_struct wapProfile10;
} nvram_meta_wap_profile_content_struct;
LID_BIT VER_LID(NVRAM_EF_WAP_PROFILE_CONTENT_LID)
nvram_meta_wap_profile_content_struct *NVRAM_EF_WAP_PROFILE_CONTENT_TOTAL
{
};
【lzq2010-4-7 下午 04:28:22 补充】
1,在手机中隐藏了一个盘符:C盘;在modis上我们能看到这个盘符里的文件,都是临时文件和NV文件;这个盘符很重要因为在down软件时半擦不会将这个盘里的文件删除;而如
果是全擦的话就会删除这里的全部文件;所以半擦时没有升级版本号的NV不会生效;
另外,升级了版本号的NV是如何生效的需要另外深入研究;[/size]