论坛» DIY与开源设计» 开源硬件

疯壳-MTK智能穿戴入门篇-MTK编程——资源

菜鸟
2020-10-26 15:59 1楼


官网地址:https://www.fengke.club/GeekMart/views/mall/goodsDetails.html?productId%3D33

配套书籍:https://www.fengke.club/GeekMart/views/mall/goodsDetails.html?productId%3D73

配套视频:http://www.fengke.club/GeekMart/su_fihsGbMhu.jsp

淘宝地址http://shop115904315.taobao.com/

QQ群:457586268

MTK编程——资源

MTK的资源分为很多种,有图片资源、铃声资源、字符串资源、屏幕资源、菜单资源、定时器资源、nvram资源,消息接收器等。所有的资源都定义在.res文件中,使用XML语句书写,所有的资源在res文件中都是用APP_NAME">包含,而APP_NAME需要在mmi_pluto_res_range_def.h文件中设置各个资源的个数。

例如:

blob.png

1MMI_RES_DECLARE(APP_MAINMENU, 300, ".\\MMI\\MainMenu\\MainMenuRes\\")

APP_MAINMENU定义在MainMenuRes.res文件中,包含所有的资源。300是指资源的最大个数,这里并不是所有资源相加的,而是图片、字串等资源各自可以添加300个。".\\MMI\\MainMenu\\MainMenuRes\\"表示APP_MAINMENU所在资源文件的目录。

2#define MAIN_MENU_BASE ((U16) GET_RESOURCE_BASE(APP_MAINMENU))

资源ID的最小取值,所有资源ID的数字大于MAIN_MENU_BASE

3#define MAIN_MENU_BASE_MAX ((U16) GET_RESOURCE_MAX(APP_MAINMENU))

资源ID的最大取值,所有资源ID的数字小于MAIN_MENU_BASE,实际上MAIN_MENU_BASE +300=MAIN_MENU_BASE_MAX

添加完资源之后,都需要使用make resgenmakeFengKe2502C_11CGPRSresgen)编译资源,生成二进制。如果在真机上调试,在make resgen之后还需要使用make rmmiresource重新编译资源模块,或者直接使用make u mmiresource编译,在模拟器上调试可以不用编译mmiresource

资源编译之后,都会在plutommi\Customer\CustomerInc目录下生成一个mmi_rp_app_name_def.h的文件,比如上面的app_nameAPP_MAINMENU,则生成的文件名为mmi_rp_app_mainmenu_def.h。在该文件中,所有同类型的资源都会生成一个enum枚举,枚举命名格式为mmi_rp_app_name_style_enumstyle为资源类型,比如mmi_rp_app_mainmenu_str_enum则为所有的字串资源ID。如果res文件中的ID,在这个文件里能够找到,说明资源生成成功。习惯上所有资源ID名称都用大写。

屏幕资源

MTK设备上,每一个屏幕都对应唯一一个屏幕ID。屏幕之间的相互切换,屏幕历史堆栈管理,都是通过屏幕ID进行的。屏幕资源的添加方法使用如下语句:

_NAME"/>或者GROUP_NAME"/>

屏幕ID资源的命名方式,习惯上以SCR_开头,比如,或者以GRP_开头。比如。通常情况下,以SCR_开头的资源一般作为实际的单个屏幕,而以GRP_开头的资源都用于屏幕组(group),一个GRP屏幕组下面,可以包含多个SCR屏幕,当你关闭一个GRP屏幕组时,那么其下的所有SCR屏幕都被关闭了。实际上SCRGRP都是同类型的资源,在使用的时候反过来也没有问题,但我们反对这么做,因为从命名上来看会导致歧义,减弱代码的可读性和可维护性。在MTK中所有的屏幕是呈一个树形结构,(见下图)

以下介绍几个常用的屏幕相关接口:

1、MMI_ID mmi_frm_group_create (MMI_ID parent_id, MMI_ID group_id, mmi_proc_func proc, void *user_data)

函数功能:创建一个屏幕组。

参数parent_id:屏幕组的父类,通常情况下可以填GRP_ID_ROOT

参数group_id:是要创建的屏幕组ID

参数proc:屏幕组的消息处理函数

参数user_data:用户需要传递的数据,通常情况下用NULL

2、MMI_BOOL mmi_frm_scrn_enter (MMI_ID parent_id, MMI_ID scrn_id, FuncPtr exit_proc, FuncPtr entry_proc, mmi_frm_scrn_type_enum scrn_type)

函数功能:进入一个屏幕。

参数parent_id:屏幕的父类,可以是我们自定义的屏幕组,也可以填GRP_ID_ROOT

参数scrn_id:屏幕ID

参数exit_proc:退出屏幕时的处理函数,一般用于释放资源。如果没有退出函数,则填NULL

参数entry_proc:屏幕的入口函数,当屏幕从历史堆栈中弹出时,会执行这个函数。

参数scrn_type:屏幕类型,一般常用的是MMI_FRM_FULL_SCRNMMI_FRM_UNKNOW_SCRN

3、mmi_ret mmi_frm_group_close (MMI_ID group_id)

函数功能:关闭屏幕组group_id

4、mmi_ret mmi_frm_scrn_close (MMI_ID parent_id, MMI_ID scrn_id)

函数功能:关闭屏幕组parent_id下的scrn_id屏幕

5、void mmi_frm_scrn_close_active_id (void)

函数功能:关闭当前处于激活状态的屏幕,即用户能够看到的屏幕。

6、U16 GetActiveScreenId(void)

函数功能:获取当前处于激活状态的屏幕ID

blob.png

屏幕ID树状结构

接下来我们自己定义一个屏幕ID,屏幕组ID暂时不讲解。在Idle.res文件中找到ID_IDLE_SUBLCD"/>,在后面添加一句,代码如下:

blob.png

然后用make resgen 编译,编译完成之后打开mmi_rp_app_idle_def.h文件,在mmi_rp_app_idle_scr_enum枚举中看是否能找到SCR_ID_MY_MTK_FUNC,如果能找到说明资源添加成功了。接下来我们将mmi_my_mtk_func函数作为一个屏幕入口函数,让它进入一个屏幕,同样打印出"Hello MTK !",并注册右软键功能关闭该屏幕,然后添加一个屏幕退出函数mmi_my_mtk_func_exit,在退出该屏幕时,我们打印"Exit Hello MTK !",具体代码如下:

blob.png

VS2008中编译,运行模拟器。我们点击左软件的时候,屏幕上依旧会显示"Hello MTK !",当我们点击右软键的时候,屏幕上会显示"Exit Hello MTK !",但是会闪一下就消失,因为先执行退出函数,然后会立即执行idle界面的入口函数,绘制idle界面的内容,从而把"Exit Hello MTK !"覆盖掉了。读者可自己使用断点,查看代码执行流程。

字符资源

在上一个例子中,我们显示"Hello MTK !"直接使用的是字符常量,这样的方式在单一语言下是没有问题的,但如果系统包含多国语言,比如从英文切换到中文,如何把"Hello MTK !"直接显示成中文呢?这里就要用到字符资源,字符资源全部添加在plutommi\Customer\CustResource\PLUTO_MMI\ref_list.txt文件中,里面包含约80种语言字符,我们只要输入对应语言的字符,那么字符显示成何种语言就会随系统的语言设置而变化。MTK提供了一个专用于修改字符资源的工具——plutommi\Customer\STMTView.exe。接下来我们把"Hello MTK !"添加成字符资源,然后通过GetString函数接口提取字符串。添加字符资源的语句格式为:

NAME">"default string"NAME"/>

字符资源ID命名通常以“STR_”开头,这两种方法的区别在于前者设置了默认值,如果STR_NAMEref_list.txt不存在的话,那它在任何语言下都会显示"default string"(注意:此处添加的默认值只能是英文字符)。而后者没有默认值,如果STR_NAMEref_list.txt不存在的话,请读者自己测试会显示什么内容。

我们采用设置默认值的方式添加字符资源,在idle.res文件中添加字符资源ID——STR_ID_HELLO_MTK,代码如下:

blob.png

然后在plutommi\Customer\CustResource\FengKe2502C_11C_MMI\MMI_features_switchFengKe2502C_11C.h文件中找到宏开关CFG_MMI_LANG_SM_CHINESE把后面的(__OFF__)改为(__ON__)这里是让系统支持简体中文,为方便我们验证字符资源的多国语言翻译问题。接下来还要为系统添加字库,在FengKe2502C_11C_GPRS.mak文件中设置FONT_ENGINE = FONT_ENGINE_ETRUMP,使用矢量字库。

打开plutommi\Customer\STMTView.exe,点击File>Open STMT会显示两个表格栏,随便选择一个,单击点击红色标注的图标,在弹出的文件选择对话框中,选择plutommi\Customer\CustResource\PLUTO_MMI\ref_list.txt然后打开,出现如下界面:

blob.png

在打开文件的一栏中单击鼠标右键,选择Insert new row。如下图所示填充弹出框:

blob.png

1Enum value:字符资源的枚举ID,必须跟.res文件中添加的资源ID一一对应,否则资源无法加载。

2Mode name:字符资源所在的功能模块,这个可以使用默认的值,仅作为描述。

3Region ID:这个也仅是描述作用,可以手动输入,也可以点击旁边的按钮选择,也可以不填。

4Description:这个也仅是描述作业,可以描述字符ID的用途。

5Default value:字符资源ID的默认值,在任何语言下都是会默认使用这个值。

下面的复选框打勾,把资源ID添加到文件的最后一行,点击OK。在新增的一行,对应Si_Chinese列把"Hello MTK !"改成“你好,MTK !”,添加效果如图:

blob.png

mmi_my_mtk_func函数中把L"Hello MTK !"改成GetString(STR_ID_HELLO_MTK),暂且把mmi_my_mtk_func_exit函数中的代码清空,具体代码如下:

blob.png

上面我们修改了MMI_features_switchFengKe2502C_11C.hFengKe2502C_11C_GPRS.mak这两个文件,只要修改了这两个文件的任意一个,都必须执行make new编译,再用make gen_modis重新生成模拟器。如果这两个文件没有修改,则make resgen就可以了。编译完后打开plutommi\Customer\ResGenerator\debug\string_resource_usage.txt文件看是否能找到STR_ID_HELLO_MTK,系统中所有的字符资源ID编译成功之后都可以在这个文件中找到,如果找不到则说明资源添加失败。字符资源编出来之后就是UCS2编码。在VS2008中运行模拟器,点击KEY_LSK,运行效果如下:

blob.png

系统默认是英语环境,所以依旧显示"hello MTK !",接下来我们把系统切换成中文。打开GeneralSettingSrv.c文件,在srv_setting_get_language函数中把return data;改为return1;再次运行模拟器,点击KEY_LSK,运行效果如下:

blob.png

字符资源的最大优势,就是可以支持多国语言,而对于程序员来说,只有一个资源ID。在调用GetString时,它会根据系统环境的语言设置,获取对应的字符串指针。

图片资源

MTK中显示的图片有三种,一是通过资源加载的,二是显示磁盘中的文件,三是直接把图片转成二进制数组显示,这种方式常用于SP游戏或应用开发。此处我们只讲图片资源。图片资源跟字符资源一样,也是添加在.res文件中,添加图片资源的语句格式为:

CUST_IMG_PATH"image_filepath\\\\image_filename"

图片资源ID命名通常以“IMG_”开头,所有的图片资源都放在plutommi\Customer\Image文件夹中,在这个文件夹中包含不同屏幕尺寸的图片资源,每个屏幕尺寸对于的文件夹下都有一个image.zip压缩包中,系统中的图片资源就放在这个压缩包中,我们添加的图片也要放到压缩包对应的目录中,在编译资源的时候,系统会将其解压成MainLCD目录。CUST_IMG_PATH是一个宏,定义在plutommi\Customer\CustResource\PLUTO_MMI\CustResDefPLUTO.h文件中,它指向image.zip所在的目录,比如当前屏幕尺寸为240X320(屏幕尺寸的配置在FengKe2502C_11C_GPRS.mak文件中查看MAIN_LCD_SIZE宏定义),则CUST_IMG_PATH定义指向plutommi\Customer\Images\PLUTO240x320目录,系统中定义的代码如下:

blob.png

image_filepath是相对于MainLCD的目录,image_filename就是图片的文件名,包含后缀名。图片资源的格式可以是bmppngjpggif还有MTK系统特定的一些图片格式。系统中添加成功的图片资源,其资源ID都可以在文件plutommi\Customer\ResGenerator\debug\image_resource_usage.txt中找到。如果资源加载失败,则资源ID会被添加到相同目录的image_load_fail.txt文件中,这种情况通常都是图片的目录错误,或者image.zip中没有这个图片文件。

接下来我们添加一个图片资源,plutommi\Customer\Images\PLUTO240x320\MainLCD\IdleScreen\Wallpaper目录下,随便找一张图片,或者自己随便找一张图片放到image.zip对应的目录中。这里我就使用WALL01.jpg来做测试。在idle.res文件中添加一个资源ID——IMG_ID_HELLO_MTK,并加载WALL01.jpg图片,代码如下:blob.png

然后使用make resgen编译,编译完成之后在image_resource_usage.txt看是否能找到IMG_ID_HELLO_MTK,如果能找到,说明资源加载成功。接下来在mmi_my_mtk_func函数中调用gdi_image_draw_id接口把图片显示出来。因图片是黑色,所以我们把字符颜色改为白色(UI_COLOR_WHITE),代码如下:

blob.png

运行模拟器,效果如图:

blob.png

显示图片的资源有:

1、gdi_image_draw_id(OFFSET_X,OFFSET_Y,IMAGE_ID)

函数功能:这是一个宏函数,根据图片ID在屏幕上显示图片

OFFSET_X:图片的显示的X坐标。

OFFSET_Y:图片的显示的Y坐标。

IMAGE_ID:图片资源ID

2、gdi_image_draw_resized_id(OFFSET_X,OFFSET_Y,RESIZED_WIDTH,RESIZED_HEIGHT,IMAGE_ID)

函数功能:这个函数可以实现图片的缩放,不管图片的尺寸是多少,都显示成指定的大小。

OFFSET_X:图片的显示的X坐标。

OFFSET_Y:图片的显示的Y坐标。

RESIZED_WIDTH:图片显示的宽度,如果大于这个宽度则缩小,如果小于这个宽度则放大。

RESIZED_HEIGHT:图片显示的高度,同RESIZED_WIDTH一样缩放图片。

IMAGE_ID:图片资源ID

3、gdi_image_draw(OFFSET_X,OFFSET_Y,IMAGE_PTR)

函数功能:这个函数的执行效果跟gdi_image_draw_id函数是一样的,只不过参数需传入一个图片的数组

OFFSET_X:图片的显示的X坐标。

OFFSET_Y:图片的显示的Y坐标。

IMAGE_PTR:图片二进制数组,通常可通过GetImage(IMAGE_ID)获取。

另外,图片资源还有gif动画,动画资源的添加方式跟图片资源是一样的,只不过显示的函数接口有点区别,动画的接口包含在gdi_include.h文件中,通常是以gdi_anim_开头的函数,比如gdi_anim_draw_id,关于动画的使用本章暂时不做过多的讲解,有兴趣的读者可以自己看代码学习。

菜单资源

菜单的添加方法比图片和字符稍微复杂些,格式有如下三种:

1菜单中包含子菜单。

<MENU……[item value]……>

MENU_ITEM_IDITEM_ID"……/>

…………………………

MENU>

如果不包含子菜单则可以写成:

<MENU……[item value]……/><MENU……[item value]……>MENU>

2、菜单中不包含子菜单

ITEM_ID"……/>

3、菜单作为主菜单

id="MENU_ID"……/>

此处的MENU_ID必须是通过第一种方式已经加载成功的菜单资源ID

以上三种格式的省略号(……)省略了一些属性值,有些属性是可有可无的,在后面通过代码来讲解。在上一个例子中,我们直接把mmi_my_mtk_func放在idle界面的,通过注册按键的方式执行。在这一节中我们把mmi_my_mtk_func放到菜单中,作为菜单的功能入口函数。

首先我们把idlecommon.c文件中mmi_idle_set_handler函数里最后一行SetKeyHandler(mmi_my_mtk_func, KEY_LSK, KEY_EVENT_UP);去掉。添加一个mmi_highlight_my_mtk函数,作为菜单的高亮处理函数,并注册左右软键功能,代码如下:

blob.png

然后在MainMenuRes.res文件中添加一个菜单MENU_MY_MTK_ID,并把它放到MAIN_MENU_SETTINGS_MENUID设置菜单下面,代码如下:

blob.png

idlecommon.c文件中mmi_idle_set_handler函数最后一行,把SetKeyHandler(mmi_my_mtk_func, KEY_LSK, KEY_EVENT_UP);改为SetKeyHandler(EntryScrSettingMenu, KEY_LSK, KEY_EVENT_UP);强制进入设置菜单选项。执行make resgen再到VS2008中重新编译并运行模拟器,点击LSK,进入“设置”菜单,在设置菜单界面就可以看到我们自己添加的菜单了“你好,MTK !”,再点击确定,就执行了我们之前添加的函数mmi_my_mtk_func。如下图所示:

blob.png

1.

type="APP_MAIN":描述菜单的类型。取值可选APP_SUBOption

str="STR_ID_HELLO_MTK":菜单名称的字符串资源ID,如上图设置菜单列表界面显示的你好,MTK!”

img="IMG_GLOBAL_OK":菜单的图标资源ID,显示在菜单的最坐标,但这里没有显示,而是用编号代替,如上图编号1。如果显示菜单自己的图标,需要修改代码,打开相关功能宏。

highlight="mmi_highlight_my_mtk":菜单被选中的时候,会执行该处理函数。

2.MENU_MY_MTK_ID

在其他菜单下面添加子菜单。此处还有另一种写法,可用下面的语句代替,并删除上面第1条语句。最终执行的结果是一样的,请读者自己尝试。

菜单添加成功可以在plutommi\Customer\CustResource\CustMenuTree_Out.c文件中找到对应的ID,这个文件包含系统中所有菜单ID的依赖关系,菜单跟屏幕一样也是呈树形结构,IDLE_SCREEN_MENU_ID是树的根,除此之外,所有的菜单ID在该文件中至少出现两次。

如果添加菜单时有highlight属性,则在plutommi\Framework\EventHandling\EventsInc\mmi_menu_handlers.h文件中可以查看到IDhighlight函数的对应关系。

铃声资源

铃声资源的添加方式跟图片资源相似,系统中所有的铃声文件都包含在plutommi\Customer\Audio\PLUTO\audio.zip压缩包中,编译资源时会被解压,所以我们添加的铃声文件也要放到这个压缩包中。添加铃声资源的格式为:

_path\\\\file_name"

说明:

id="AUD_ID_NAME":资源ID的名称。

flag="MULTIBIN":描述资源的属性,这个属性可有可无。

CUST_ADO_PATH:宏定义,指向plutommi\Customer\Audio\PLUTO目录

file_pathaudio.zip压缩包中,铃声文件所在的目录。

file_name:铃声文件名。格式可为mp3wavmidimy等。

系统中大多数铃声资源都在情景模式中,见ProfilesSrv.res文件。铃声资源编译成功后,可以在plutommi\Customer\ResGenerator\debug\audio_resource_usage.txt文件中找到ID以及与其对应的铃声文件。铃声资源的播放,可以用get_audio获取铃声资源的数组,然后再用mdi_audio_play_string_with_vol_path函数播放。此处不做代码测试,留给读者自己完成。

nvram资源

MTK设备有些数据在关机之后也要保存。实现这种功能的方法有两种,一种方法是存储到磁盘文件中,另一种方法就是我们本节要讲的nvram(简称NV)。而nvram也分为两种,一种可以存储复合数据类型,比如结构体;而另一种只能存储数值类型,比如byteshortdouble,我们用的最多的是byteshort。存储数值类型的NV就是通过资源的方式添加,添加NV资源的格式为:

[value]

description

_number" max="max_number">

说明:

type=" type"type的取值有byteshortdoublebyte只能存一个字节,short能存两个字节,double可以存8个字节,一般用的很少,如果存储的数据量较大,则作为复合数据类型存储。

id="NVRAM_NAME": NVRAM的资源IDNV的读写都是通过ID进行。

restore_flag="TRUE/FALSE"TRUE恢复出厂设置时重置该NV的值为默认值

[value] NV的默认值,typebyte,取值最大为[0xFF]short最大为[0xFF,0xFF],左侧为高为,右侧为低位;double最大为[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],同样是左侧高位,右侧低位。比如typeshort,存储value300,转换成十六进制为[0x01,0x2C]

description NV的描述,相当于注释。这个属性可以缺省。

_number" max="max_number">:描述NV的取值范围。这个属性也可以缺省。

比如,系统中保存背光亮度和背光时间的NV,在gpiosrv.res文件中定义如下:

blob.png

NV资源的读写通常用以下两个函数:

1、S32 ReadValue(U16 nDataItemId, void *pBuffer, U8 nDataType, S16 *pError)

函数功能:读取NV中存储的值。

nDataItemId:NV的资源ID。

pBuffer:保存NV中读取到的数值。

nDataType:NV的类型,取值有DS_BYTE、DS_SHORT、DS_DOUBLE,分别对应资源中的byteshortdouble类型

pError;这个参数在函数实现中暂时并没有实际的作用。

例句:ReadValue(NVRAM_BYTE_BL_SETTING_HFTIME, &hftime, DS_SHORT, &error);


2、S32 WriteValue(U16 nDataItemId, void *pBuffer, U8 nDataType, S16 *pError)

函数功能:把pBuffer中的数值写入NV中。

nDataItemId:NV的资源ID。

pBuffer:需要写入NV中的数值。

nDataType:NV的类型,取值有DS_BYTE、DS_SHORT、DS_DOUBLE,分别对应资源中的byteshortdouble类型

pError;这个参数在函数实现中暂时并没有实际的作用。

例句:WriteValue(NVRAM_BYTE_BL_SETTING_HFTIME, &hftime, DS_SHORT, &error);

本节只简单的介绍NV资源的添加,以及读写方式,在后面的章节中会有单独一章详细讲解NVRAM,包括存储简单数据类型和复合数据类型。

定时器资源

定时器的作用就是延后执行某一个操作,也可以每隔一段时间就执行一次。定时器ID的添加方式有两种,一种是在TimerEvents.h文件中的MMI_TIMER_IDS枚举中添加,只要添加在KEY_TIMER_ID_NONEMAX_TIMERS之间就可以了,这种添加方式比较简单,通常驱动里面要用的定时器都添加在这个文件中。另一种方式是通过资源ID方式添加,这种方式添加的定时器跟第一种方式添加的定时器没有本质的区别,在使用上也是完全一模一样。MMI层用到的定时器两种添加方式都没有问题,但是强烈建议使用第二种,方便代码的模块化。

定时器资源的添加方式为:

TIMER_ID_NAME为自定义的定时器ID名称。定时器启动和停止的常用函数接口如下:

1、void StartTimer(U16 timerid, U32 delay, FuncPtr funcPtr)

函数功能:启动定时器。

timerid:定时器的资源ID。

delay:定时器执行的时间间隔。

funcPtr:定时器执行的函数。

2、void StopTimer(U16 timerid)

函数功能:停止定时器。

timerid:定时器的资源ID。

消息接收器

这个资源在实际开发中用的比较少,一般都是系统自带的。我们只需要了解一下就可以了,消息接收器的定义方式如下:

_ID_NAME" proc="reveiver_func"/>

说明:

id=" RECEIVER_ID_NAME":为消息ID

proc="reveiver_func":消息ID的处理函数。这个函数一般由系统调用。


工程师
2020-10-26 20:14 2楼

讲解的太全面了

工程师
2020-10-26 21:59 3楼

确实是个不错的产品

共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]