MTK提供的NVRAM存取方式有两种,一种读取单条数据,一种是读取结构数据.
读取单条数据的比较常见,在mtk代码中随处可以找到例子,主要的接口函数是ReadValue和WriteValue,函数中nDataType参数对应的是
1 typedef enum /* Pixtel Defined enum */
2 {
3 DS_BYTE = 1,
4 DS_SHORT = 2,
5 DS_DOUBLE = 8
6 } DATASIZE; /* Enum for caching purposes */
2 {
3 DS_BYTE = 1,
4 DS_SHORT = 2,
5 DS_DOUBLE = 8
6 } DATASIZE; /* Enum for caching purposes */
一般我的应用中,DS_BYTE 类型我们对应U8来使用,DS_SHORT对应U16,DS_DOUBLE 对应U64,(double的操作可以参考THEME_MANAGER_MAX_THEME_ID)
可根据数据的需求来用不同的类型,参数nDataItemId定义在custom_mmi_default_value.h中,对应不同类型分别放于BYTEDATA,SHORTDATA,DOUBLEDATA中.
实际工作中我们最常用这种方法存储程序的开关,一般我们会使用DS_BYTE 类型来存储,实则用U8来存储一个0/1的数据太浪费了,所以我们一般要充分利用U8中的每个位,程序上在读出数据后进行位操作即可得到自己想要得数据,存储前的时候也要进行相应位操作后才能进行存储.比如我前面设计的呼吸灯的功能,对于不同情况下的呼吸需要存储开关,速度和效果,我根据数据特征将U8分成三个部分来分别存储,即AABBCCCC,AA开关,BB速度,CCCC效果,将开关设置两位是为了避免nvram存储值为0,不便于对nvram初始值进行判断.
1 //开关
2 typedef enum
3 {
4 SWITCH_NULL,//增加该项使nvram存储值不为0
5 SWITCH_ON,
6 SWITCH_OFF,
7
8 //add item befor this
9 RF_UTPLUS_SWITCH_END
10 }utplus_rf_breath_switch;
11 //从nvram中获取初始化值
12 void utplus_rf_breath_init_nvram_value(void)
13 {
14 U8 data = 0;
15 U8 i;
16 S16 error;
17 for(i=0;i<RF_UTPLUS_FEATRUE_END;i++)
18 {
19 ReadValue(NVRAM_RF_UTPLUS_SETTING_START + i + 1,&data, DS_BYTE , &error);
20 dbg_print("\r\n UtPlus BreathLED init nvram read data = %d , \r\n ",data);
21 if(data==0xff|| data < 0x40 ||error !=NVRAM_READ_SUCCESS)
22 {
23 dbg_print("UtPlus BreathLED init nvram read err i = %d ,err = %d \r\n ",i,error);
24 data = ((U8)(ut_g_rfb[i].switch_id)<<6)|( (U8)(ut_g_rfb[i].speed_level) <<4)|( (U8)(ut_g_rfb[i].breath_type_id));
25 dbg_print("UtPlus BreathLED init nvram write data = %d , \r\n ",data);
26 WriteValue(NVRAM_RF_UTPLUS_SETTING_START + i + 1 ,&data, DS_BYTE , &error);
27 }
28 else
29 {
30 dbg_print("UtPlus BreathLED init nvram read success i = %d \r\n ",i);
31 ut_g_rfb[i].switch_id = (data&0xC0)>>6;
32 ut_g_rfb[i].speed_level = (data&0x30)>>4;
33 ut_g_rfb[i].breath_type_id = (data&0x0f);
34 }
35 }
36 }
37 //在nvram存储对应修改值
38 void utplus_rf_breath_set_nvram_value(U8 index,utplus_rf_breath* utrb)
39 {
40 U8 data = 0;
41 S16 error;
42
43 ASSERT(index<RF_UTPLUS_FEATRUE_END);
44
45 data = ((U8)(utrb->switch_id)<<6)|( (U8)(utrb->speed_level) <<4)|( (U8)(utrb->breath_type_id));
46 dbg_print("\r\n UtPlus BreathLED set nvram read index = %d data = %d , \r\n ",index,data);
47 WriteValue(NVRAM_RF_UTPLUS_SETTING_START + index + 1,&data, DS_BYTE , &error);
48 ut_g_rfb[index].switch_id = utrb->switch_id;
49 ut_g_rfb[index].speed_level = utrb->speed_level;
50 ut_g_rfb[index].breath_type_id = utrb->breath_type_id;
51 }
52
2 typedef enum
3 {
4 SWITCH_NULL,//增加该项使nvram存储值不为0
5 SWITCH_ON,
6 SWITCH_OFF,
7
8 //add item befor this
9 RF_UTPLUS_SWITCH_END
10 }utplus_rf_breath_switch;
11 //从nvram中获取初始化值
12 void utplus_rf_breath_init_nvram_value(void)
13 {
14 U8 data = 0;
15 U8 i;
16 S16 error;
17 for(i=0;i<RF_UTPLUS_FEATRUE_END;i++)
18 {
19 ReadValue(NVRAM_RF_UTPLUS_SETTING_START + i + 1,&data, DS_BYTE , &error);
20 dbg_print("\r\n UtPlus BreathLED init nvram read data = %d , \r\n ",data);
21 if(data==0xff|| data < 0x40 ||error !=NVRAM_READ_SUCCESS)
22 {
23 dbg_print("UtPlus BreathLED init nvram read err i = %d ,err = %d \r\n ",i,error);
24 data = ((U8)(ut_g_rfb[i].switch_id)<<6)|( (U8)(ut_g_rfb[i].speed_level) <<4)|( (U8)(ut_g_rfb[i].breath_type_id));
25 dbg_print("UtPlus BreathLED init nvram write data = %d , \r\n ",data);
26 WriteValue(NVRAM_RF_UTPLUS_SETTING_START + i + 1 ,&data, DS_BYTE , &error);
27 }
28 else
29 {
30 dbg_print("UtPlus BreathLED init nvram read success i = %d \r\n ",i);
31 ut_g_rfb[i].switch_id = (data&0xC0)>>6;
32 ut_g_rfb[i].speed_level = (data&0x30)>>4;
33 ut_g_rfb[i].breath_type_id = (data&0x0f);
34 }
35 }
36 }
37 //在nvram存储对应修改值
38 void utplus_rf_breath_set_nvram_value(U8 index,utplus_rf_breath* utrb)
39 {
40 U8 data = 0;
41 S16 error;
42
43 ASSERT(index<RF_UTPLUS_FEATRUE_END);
44
45 data = ((U8)(utrb->switch_id)<<6)|( (U8)(utrb->speed_level) <<4)|( (U8)(utrb->breath_type_id));
46 dbg_print("\r\n UtPlus BreathLED set nvram read index = %d data = %d , \r\n ",index,data);
47 WriteValue(NVRAM_RF_UTPLUS_SETTING_START + index + 1,&data, DS_BYTE , &error);
48 ut_g_rfb[index].switch_id = utrb->switch_id;
49 ut_g_rfb[index].speed_level = utrb->speed_level;
50 ut_g_rfb[index].breath_type_id = utrb->breath_type_id;
51 }
52
读取结构数据也是比较常用的方式,可能初级的程序员还是比较少的接触这个的,常用的接口函数是WriteRecord和ReadRecord
这两个函数逻辑处理的核心数据是
ltable_entry_struct logical_data_item_table_comm_app[]
在这个结构定义前MTK有如下说明:
1
2 /**
3 * Steps of defining logical data item:
4 * 1> Define LID of new logical data item into `nvram_LID_cust_enum' in
5 * nvram_user_defs.h
6 * 2> Define two constants: SIZE and TOTAL, in nvram_user_defs.h
7 * 3> Define default value of that new logical data item in nvram_user_config.c
8 * 4> Define attributes of that new logical data item into
9 * `logical_data_item_table_cust'
10 * 5> Bypass.
11 * 6> Change version number CODED_DATA_VERSION in nvram_user_config.c
12 */
13 /**
14 * The logical data item table.
15 * Note:
16 * Each logical data item must be:
17 * 1> Size must be EVEN
18 * 2> Size of default value must be equal to the logical data item's size.
19 */
20 /**
21 * The rule for data item changes:
22 * 1. To add a new data item, its name must be the next of the current last LID, for example,
23 * the last LID in the CT reign now is CT20, the new one must be CT21.
24 * 2. Version must be increased if
25 * (a) Size is changed, or
26 * (b) Number of sections is changed, or
27 * (c) Attribute is changed, or
28 * (d) data structure is changed.
29 */
2 /**
3 * Steps of defining logical data item:
4 * 1> Define LID of new logical data item into `nvram_LID_cust_enum' in
5 * nvram_user_defs.h
6 * 2> Define two constants: SIZE and TOTAL, in nvram_user_defs.h
7 * 3> Define default value of that new logical data item in nvram_user_config.c
8 * 4> Define attributes of that new logical data item into
9 * `logical_data_item_table_cust'
10 * 5> Bypass.
11 * 6> Change version number CODED_DATA_VERSION in nvram_user_config.c
12 */
13 /**
14 * The logical data item table.
15 * Note:
16 * Each logical data item must be:
17 * 1> Size must be EVEN
18 * 2> Size of default value must be equal to the logical data item's size.
19 */
20 /**
21 * The rule for data item changes:
22 * 1. To add a new data item, its name must be the next of the current last LID, for example,
23 * the last LID in the CT reign now is CT20, the new one must be CT21.
24 * 2. Version must be increased if
25 * (a) Size is changed, or
26 * (b) Number of sections is changed, or
27 * (c) Attribute is changed, or
28 * (d) data structure is changed.
29 */
上面已经将部分配置说明的比较清楚了,下面拿出mtk的一项举例说明:
1 #ifdef __MMI_FILE_MANAGER__
2 ,{
3 NVRAM_EF_WPSS_FILENAME_LID,
4 NVRAM_EF_WPSS_FILENAME_SIZE,
5 NVRAM_EF_WPSS_FILENAME_TOTAL,
6 NVRAM_NORMAL(NVRAM_EF_ZERO_DEFAULT),
7 NVRAM_ATTR_AVERAGE,
8 NVRAM_CATEGORY_USER | NVRAM_CATEGORY_FACTORY,
9 "MP1S",
10 VER(NVRAM_EF_WPSS_FILENAME_LID),
11 "Dispchar path",
12 NVRAM_APP_RESERVED
13 }
14 #endif /* __MMI_FILE_MANAGER__ */
2 ,{
3 NVRAM_EF_WPSS_FILENAME_LID,
4 NVRAM_EF_WPSS_FILENAME_SIZE,
5 NVRAM_EF_WPSS_FILENAME_TOTAL,
6 NVRAM_NORMAL(NVRAM_EF_ZERO_DEFAULT),
7 NVRAM_ATTR_AVERAGE,
8 NVRAM_CATEGORY_USER | NVRAM_CATEGORY_FACTORY,
9 "MP1S",
10 VER(NVRAM_EF_WPSS_FILENAME_LID),
11 "Dispchar path",
12 NVRAM_APP_RESERVED
13 }
14 #endif /* __MMI_FILE_MANAGER__ */
NVRAM_EF_WPSS_FILENAME_SIZE,定义为 sizeof(PHNSET_WPSS_FILENAME_STRUCT),单个结构体的大小
NVRAM_EF_WPSS_FILENAME_TOTAL 表示存储几个这样的结构体
NVRAM_NORMAL(NVRAM_EF_ZERO_DEFAULT)每个结构体的初始值,此处表示初始化值全为0, 如果想初始化需要的默认值可以参考NVRAM_EF_PROFILES_LID情景模式的初始值.
下面两个参数是
nvram_attr_enum attr; /* U16 */
nvram_category_enum category; /* U32 */
这两个属性在系统进行nvram的read/write中用到,具体意义我也不太清楚,比如IMEI的NVRAM_EF_IMEI_IMEISV_LID就有NVRAM_ATTR_WRITEPROTECT属性.
下面的VER(NVRAM_EF_WPSS_FILENAME_LID)是将NVRAM_EF_WPSS_FILENAME_LID变为NVRAM_EF_WPSS_FILENAME_LID_VERNO,这个定义Record版本号,定义在common_nvram_editor_data_item.h,据说是系统升级后系统会自动对比这个版本号,如果这个版本号不同的话就会自动覆盖原先的值.有研究手段的朋友请告知我,谢谢啊.
上面的byte,short,double的存储也是组合成record来进行的,其size都是NVRAM_CACHE_SIZE=512,也就是说存储byte的个数 上限是512个,short的个数上限是256个,double的个数的上限是64个(如果你的应用需要存储的数据量比较大最好新建record).他们分别对应NVRAM_EF_CACHE_BYTE_LID,NVRAM_EF_CACHE_SHORT_LID,NVRAM_EF_CACHE_DOUBLE_LID.所以对于一些常规的nvram修改如果不像格式化重新校准软件就可以升级对应的nvram版本号即可.
下面阐述关于NVRAM的编译生成和读取流程.
NVRAM的编译生成主要依靠tools\NVRAMStatistic下的相关文件,src是相关源代码文件,通过NVRAMAutogen.bat每次生成新的nvram_auto_gen.exe,nvram数据的生成也是通过logical_data_item_table_comm_app为接口的.
NVRAM系统读取得模块代码位于工程nvram目录下,系统的实现接口是
kal_bool nvram_create(comptask_handler_struct **handle)
比较核心的处理函数是;void nvram_main(ilm_struct *ilm_ptr)
1 /*****************************************************************************
2 * FUNCTION
3 * nvram_main
4 * DESCRIPTION
5 * This is main() function of NVRAM module.
6 * PARAMETERS
7 * ilm_ptr [IN] The primitives
8 * RETURNS
9 * void
10 *****************************************************************************/
11 void nvram_main(ilm_struct *ilm_ptr)
12 {
13 /*----------------------------------------------------------------*/
14 /* Local Variables */
15 /*----------------------------------------------------------------*/
16
17 /*----------------------------------------------------------------*/
18 /* Code Body */
19 /*----------------------------------------------------------------*/
20 ASSERT(ilm_ptr != NULL);
21
22 if (ilm_ptr != NULL)
23 {
24 if ((ilm_ptr->msg_id >= MSG_ID_NVRAM_CODE_BEGIN) && (ilm_ptr->msg_id <= MSG_ID_NVRAM_CODE_END))
25 {
26
27 if (ilm_ptr->msg_id == MSG_ID_NVRAM_STARTUP_REQ)
28 {
29 nvram_startup_handler(ilm_ptr);
30 }
31 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_RESET_REQ)
32 {
33 nvram_reset_handler(ilm_ptr);
34 }
35 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_READ_REQ)
36 {
37 nvram_read_handler(ilm_ptr);
38 }
39 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_WRITE_REQ)
40 {
41 nvram_write_handler(ilm_ptr);
42 }
43 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_WRITE_IMEI_REQ)
44 {
45 nvram_write_imei_handler(ilm_ptr);
46 }
47 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_SET_LOCK_REQ)
48 {
49 nvram_set_lock_handler(ilm_ptr);
50 }
51 }
52 #ifdef TST_HANDLER
53 else
54 {
55 /* not nvram defined message */
56 if (ilm_ptr->msg_id == MSG_ID_TST_INJECT_STRING)
57 {
58 nvram_tst_handler(ilm_ptr);
59 }
60 }
61 #endif /* TST_HANDLER */
62
63 }
64 } /* end of module main function */
2 * FUNCTION
3 * nvram_main
4 * DESCRIPTION
5 * This is main() function of NVRAM module.
6 * PARAMETERS
7 * ilm_ptr [IN] The primitives
8 * RETURNS
9 * void
10 *****************************************************************************/
11 void nvram_main(ilm_struct *ilm_ptr)
12 {
13 /*----------------------------------------------------------------*/
14 /* Local Variables */
15 /*----------------------------------------------------------------*/
16
17 /*----------------------------------------------------------------*/
18 /* Code Body */
19 /*----------------------------------------------------------------*/
20 ASSERT(ilm_ptr != NULL);
21
22 if (ilm_ptr != NULL)
23 {
24 if ((ilm_ptr->msg_id >= MSG_ID_NVRAM_CODE_BEGIN) && (ilm_ptr->msg_id <= MSG_ID_NVRAM_CODE_END))
25 {
26
27 if (ilm_ptr->msg_id == MSG_ID_NVRAM_STARTUP_REQ)
28 {
29 nvram_startup_handler(ilm_ptr);
30 }
31 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_RESET_REQ)
32 {
33 nvram_reset_handler(ilm_ptr);
34 }
35 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_READ_REQ)
36 {
37 nvram_read_handler(ilm_ptr);
38 }
39 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_WRITE_REQ)
40 {
41 nvram_write_handler(ilm_ptr);
42 }
43 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_WRITE_IMEI_REQ)
44 {
45 nvram_write_imei_handler(ilm_ptr);
46 }
47 else if (ilm_ptr->msg_id == MSG_ID_NVRAM_SET_LOCK_REQ)
48 {
49 nvram_set_lock_handler(ilm_ptr);
50 }
51 }
52 #ifdef TST_HANDLER
53 else
54 {
55 /* not nvram defined message */
56 if (ilm_ptr->msg_id == MSG_ID_TST_INJECT_STRING)
57 {
58 nvram_tst_handler(ilm_ptr);
59 }
60 }
61 #endif /* TST_HANDLER */
62
63 }
64 } /* end of module main function */
主要处理的是 : startup,reset,read,write,write_imei,set_lock
在这里对imei的单独处理可能跟他的NVRAM_ATTR_WRITEPROTECT属性有关吧.
作者:张素丰,转载请注明出处:http://www.cnblogs.com/zhangsufeng/archive/2010/09/11/1824100.html
这只是表面的分析,深入的研究需要更多的能力,我现在还比较欠缺,渴望和大家多交流,我QQ号是275000205。
20100912 0:22补充:
今日研究了下电话本的nvram存储,不惑,得一高人点拨,发现在记录里还有一个重要的特性:
LID_BIT VER_LID(NVRAM_EF_WPSS_FILENAME_LID)
nvram_wpss_filename_struct *NVRAM_EF_WPSS_FILENAME_TOTAL
{
};
用来将LID和结构体关联,而且我们找LID所用的结构可以快速的通过这个找到。
关于这方面的详细介绍请见:http://blog.ednchina.com/Jerome_home/1801884/message.aspx