MTK平台相关资料
更新时间:2024-05-04 19:14:01 阅读量: 综合文库 文档下载
- MTK平台推荐度:
- 相关推荐
MTK平台相关资料
ADD
添加文件:
开发过程中,少不了加减文件,删除文件实际上是添加文件的相反过程,因此略过。 MTK设置了很多lst和pth文件供用户添加文件,这些都make文件夹下。用户可以自己添加模块,也可利用原有的lst和pth文件添加。以下以添加在MTK\\make\\plutommi为例。
添加头文件路径: plutommi.inc
添加本模块路径: plutommi.pth
添加源文件路径: plutommi.lis
添加完毕,这些文件就可参与编译了。 添加开关:
开关真是个好东西。依靠它,可以将没有价值的功能瞬间屏蔽,又可以将我们需要但又搁置的功能瞬间启用。能者上,不能者下,多么类似于社会法则。添加开关在make文件
夹下面的.mak文件里面。 注意事项:
有人喜欢模仿MTK原做法,在.mak文件里面使用一个开关管住另外一个开关。那么两个开关不要同名,否则开关起不了关闭的作用。 添加string资源:
1.在stringid定义的地方添加相应的id (如SettingResDef.h STR_ID_SETTING_ENUM)中增加ID;
2.在plutommi\\Customer\\CustResource\\PLUTO_MMI下相应的res_xxx.c文件里,PopulateXXX函数里面把stringid添加上去例如:STR_MENU_SETTING_BUSINESS_CONCEAL
ADD_APPLICATION_STRING2(STR_MENU_SETTING_BUSINESS_CONCEAL,\nessConceal\(如Res_Setting.c ADD_APPLICATION_STRING2)中将ID和string关联; 3.plutommi\\Customer\\CustResource\\PLUTO_MMI\\ref_list.txt中增加ID和各种语言的文本即添加相应的字符串。
有了以上3个步骤,即可使用该文本资源了(使用
gui_print_text((UI_string_type)GetString(STR_ID_MY_TRY));)。
编译后,在plutommi\\Customer\\CustResource下面会生成新的CustStrMap.c和 CustStrRes.c这两个文件中就包含了新增的string资源
添加图片:
1.在imgid定义的地方添加相应的id (如SettingResDef.h IMG_ID_SETTING_ENUM)中增加ID
2.在plutommi\\Customer\\CustResource\\PLUTO_MMI下相应的res_xxx.c文件里,PopulateXXX函数里面把imgid添加上去例如:IMG_IDLE_MAINMENU_SHORCUT的添加
ADD_APPLICATION_IMAGE2(IMG_IDLE_MAINMENU_SHORCUT,CUST_IMG_PATH\ge.\
(如Res_Setting.c ADD_APPLICATION_IMAGE2(IMG_ID_MY_TRY,CUST_IMG_PATH\\\\\\\\\mygif.gif\)中将ID和图片关联
3.增加图片到解压后的包里,增加完毕,应打包。 plutommi\\Customer\\Images\\PLUTO176X220
里面的文件夹是生成的,可以在cc上看到为private。
4.添加进去后,要打包,如果仅添加在文件夹里面会被清除。 如果没有找到图片文件,手机显示的时候是一个红色的*,添加图片时,注意路径用4杠。 (使用gdi_image_draw(30,110,(U8*)GetImage(IMG_ID_MY_TRY));)
在NVRam中增加成员:
需要增加ID,指出每块大小,以及总的块数和缺省值。每块大小最好为偶数。 修改下面的文件:
Nvram_user_defs.h: ID,大小,个数 NVRAMEnum.h Nvram_user_config.c
custom_nvram_editor_data_item.h 添加menu
1.在menuid定义的地方添加相应的id
2.在plutommi\\Customer\\CustResource\\PLUTO_MMI下相应的res_xxx.c文件里,PopulateXXX函数里面把menuid添加上去例如:MENU_ID_SETTING_BUSINESS_CONCEAL的添加
ADD_APPLICATION_MENUITEM((MENU_ID_SETTING_BUSINESS_CONCEAL,MENU9101_SECURITY,2,
MENU_ID_SETTING_BUSINESS_CONCEAL_PHONE, MENU_ID_SETTING_BUSINESS_CONCEAL_SMS,
SHOW,MOVEABLEWITHINPARENT,DISP_LIST,STR_MENU_SETTING_BUSINESS_CONCEAL,0));
举例:在手机主菜单设置菜单中添加子菜单
1、在SettingResDef.h(plutommi\\mmi\\setting\\settinginc)文件中增加
在enumSTR_ID_SETTING_ENUM的最后增加三个字符串ID的声明: STR_ID_MY_SETTING, STR_ID_MY_SETTING1, STR_ID_MY_SETTING2,
在enumSCR_ID_SETTING_ENUM的最后增加三个ScreenID的声明: SCR_ID_MY_SETTING, SCR_ID_MY_SETTING1, SCR_ID_MY_SETTING2,
在enumIMG_ID_SETTING_ENUM的最后增加一个ImageID的声明: IMG_ID_MY_SETTING;
在enumGLOBALMENUITEMSID[GlobalMenuItems.h(plutommi\\mmi\\inc)目录下
GlobalMenuItems.h文件中(有的是在本AP或模块的*Defs.h中声明)]的最后增加三个菜单ID的声明:
MENU_MY_SETTING, MENU_MY_SETTING1, MENU_MY_SETTING2,
2、在..\\plutommi\\Customer\\CustResource\\PLUTO_MMI目录下的Ref_list.txt中添加三个字符串:
STR_ID_MY_SETTING Undefined 10 MySetting MySetting 我的设定 我的设定
STR_ID_MY_SETTING1 Undefined 10 MySetting1 MySetting1 我的设定1 我的设定1
STR_ID_MY_SETTING2 Undefined 10 MySetting2 MySetting2 我的设定2 我的设定2
3、在..\\plutommi\\Customer\\CustResource\\PLUTO_MMI\\Res_MMI目录下的Res_Setting.cvoidpopulateSettingMenu(void)函数前增加如下资源:
ADD_APPLICATION_MENUITEM((MENU_MY_SETTING,MAIN_MENU_SETTINGS_MENUID,2,MENU_MY_SETTING1,MENU_MY_SETTING2,SHOW,MOVEABLEWITHINPARENT,DISP_LIST,STR_ID_MY_SETTING,0)); ADD_APPLICATION_MENUITEM ((MENU_MY_SETTING1,MENU_MY_SETTING,0,SHOW, MOVEABLEWITHINPARENT,DISP_LIST,STR_ID_MY_SETTING1,0)); ADD_APPLICATION_MENUITEM ((MENU_MY_SETTING2,MENU_MY_SETTING,0,SHOW, MOVEABLEWITHINPARENT,DISP_LIST,STR_ID_MY_SETTING2,0)); ADD_APPLICATION_IMAGE2(IMG_ID_MY_SETTING,CUST_IMG_PATH\nLCD\\\\\\\\SubMenu\\\\\\\\Settings\\\\\\\\MY_SETTING.GIF\ ADD_APPLICATION_STRING2(STR_ID_MY_SETTING,\ ADD_APPLICATION_STRING2(STR_ID_MY_SETTING1,\1\ ADD_APPLICATION_STRING2(STR_ID_MY_SETTING2,\2\
4、在..\\plutommi\\Customer\\CustResource\\PLUTO_MMI\\Res_MMI目录下的Res_MainMenu.c中修改如下: ADD_APPLICATION_MENUITEM
((MAIN_MENU_SETTINGS_MENUID,IDLE_SCREEN_MENU_ID,5, MENU9102_INITIAL_SETUP,... 改为:
ADD_APPLICATION_MENUITEM
((MAIN_MENU_SETTINGS_MENUID,IDLE_SCREEN_MENU_ID,6, MENU_MY_SETTING,MENU9102_INITIAL_SETUP,... 或者有的是在
ADD_APPLICATION_MENUITEM2((MAIN_MENU_SETTINGS_MENUID,IDLE_SCREEN_MENU_ID,后加MENU_MY_SETTING,
5、在..\\plutommi\\mmi\\Setting\\SettingInc\\目录下的SettingProt.h中增加如下的函数声明: externvoidHighlightMySetting(void); externvoidHighlightMySetting1(void); externvoidHighlightMySetting2(void); externvoidEntryMySetting(void); externvoidEntryMySetting1(void); externvoidEntryMySetting2(void);
6、在..\\plutommi\\mmi\\Setting\\SettingSrc\\目录下的SettingSrc.c中增加如下的函数定义: voidHighlightMySetting(void) { SetKeyHandler(GoBackHistory,KEY_LEFT_ARROW,KEY_EVENT_DOWN); SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP); SetKeyHandler(EntryMySetting,KEY_RIGHT_ARROW,KEY_EVENT_DOWN); SetLeftSoftkeyFunction(EntryMySetting,KEY_EVENT_UP); }
voidHighlightMySetting1(void)
{ SetKeyHandler(GoBackHistory,KEY_LEFT_ARROW,KEY_EVENT_DOWN); SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP); SetKeyHandler(EntryMySetting1,KEY_RIGHT_ARROW,KEY_EVENT_DOWN); SetLeftSoftkeyFunction(EntryMySetting1,KEY_EVENT_UP); }
voidHighlightMySetting2(void) { SetKeyHandler(GoBackHistory,KEY_LEFT_ARROW,KEY_EVENT_DOWN); SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP); SetKeyHandler(EntryMySetting2,KEY_RIGHT_ARROW,KEY_EVENT_DOWN); SetLeftSoftkeyFunction(EntryMySetting2,KEY_EVENT_UP); }
voidEntryMySetting(void) { U16nStrItemList[MAX_SUB_MENUS];/*Storesthestringsidofsubmenusreturned*/ U16nNumofItem;/*Storesnoofchildreninthesubmenu*/ U8*guiBuffer;/*Bufferholdinghistorydata*/ U16ImageList[MAX_SUB_MENUS]; EntryNewScreen(SCR_ID_MY_SETTING,NULL,EntryMySetting,NULL); /*2Getcurrentscreentoguibufferforhistorypurposes*/ guiBuffer=GetCurrGuiBuffer(SCR_ID_MY_SETTING); /*3.Retrievenoofchildofmenuitemtobedisplayed*/ nNumofItem=GetNumOfChild(MENU_MY_SETTING); /*4.Retrievestringidsinsequenceofgivenmenuitemtobedisplayed*/ GetSequenceStringIds(MENU_MY_SETTING,nStrItemList); GetSequenceImageIds(MENU_MY_SETTING,ImageList); /*5Setcurrentparentid*/ SetParentHandler(MENU_MY_SETTING); /*6Registerhighlighthandlertobecalledinmenuscreen*/ RegisterHighlightHandler(ExecuteCurrHiliteHandler); /*7DisplayCategory1Screen*/ ShowCategory15Screen(STR_ID_MY_SETTING,IMG_SCR_SETTING_CAPTION,STR_GLOBAL_OK,IMG_GLOBAL_OK,STR_GLOBAL_BACK,IMG_GLOBAL_BACK,nNumofItem,nStrItemList,ImageList,LIST_MENU,0,guiBuffer); /*8.Registerfunctionwithrightsoftkey*/ SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP); }
voidEntryMySetting1(void) { S8*string=GetString(STR_ID_MY_SETTING1); U16imageId=IMG_ID_MY_SETTING; EntryNewScreen(SCR_ID_MY_SETTING1,NULL,EntryMySetting1,NULL); ShowCategory65Screen((U8*)string,imageId,NULL);
SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP); }
voidEntryMySetting2(void) { S8*string=GetString(STR_ID_MY_SETTING2); U16imageId=IMG_ID_MY_SETTING; EntryNewScreen(SCR_ID_MY_SETTING2,NULL,EntryMySetting2,NULL); ShowCategory65Screen((U8*)string,imageId,NULL); SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP); } 7、在..\\plutommi\\mmi\\Setting\\SettingSrc\\目录下的SettingSrc.c中voidInitSettingApp(void)函数下增加如下代码:
SetHiliteHandler(MENU_MY_SETTING,HighlightMySetting); SetHiliteHandler(MENU_MY_SETTING1,HighlightMySetting1); SetHiliteHandler(MENU_MY_SETTING2,HighlightMySetting2); 基本概括如下:
a.在Ref_list.txt和Res_*.c中增加资源;
b.在*Defs.h中声明所有资源的ID,包括字符串ID、图片ID、菜单ID、窗口ID。 c.在具体的实现代码文件中增加处理代码。
MTK手机软件系统工程和配置简介
MTK是现在市场上所有国内手机设计、制造商使用的最多的一个完整的手机产品解决方案,大部分做手机的技术人员都对此有接触和了解。不过,MTK的整套软件系统十分庞大且复杂,很多刚接触这套系统的软件工程师一时不知如何进行配置和客户化定制。本文在此对整个MTK软件系统的工程结构和配置进行了简单介绍,希望通过此文和大家相互交流MTK软件系统的维护和修改、定制方面的心得。 MTK使用了nucleus实时操作系统,在其上做了个内核抽象层的封装,以适应多种实时操作系统,如oscar、ThreadX、nucleus。整个软件系统包括nucleus操作系统、平台设备驱动、协议栈、文件系统、WGUI、MMI、J2ME等。在这里MMI部分几乎包括了操作系统内核、协议栈、文件系统之上的所有部分,其中WGUI也在其中。
MTK的PC模拟版使用VC的编译器和链接器生成,ARM版使用ADS1.2的编译器和链接器生成。因为MTK的整个软件系统是一个很庞大而且复杂的工程,并且要支持多个MTK的产品系列和多家客户的客户化支持,使用集成开发环境(IDE)已经无法胜任,而且很难做到整个工程的自动构建和资源、代码的生成。所以MTK的软件系统使用了windows下的GNU开发工具链(MinGW)来进行工程的管理、配置和构建,MTK将
MinGW放到了第三方工具中。另外还使用了perl脚本来解析用户输入的命令行参数,因此第三方工具中还包含了ActivePerl(windows下的perl解释器)。不过,整个软件系统并没有使用MinGW的全部工具,好象只使用了make这个工具,由几个Makefile控制了构建的过程,在编译和链接时根据最终生成PC模拟版还是ARM版而分别调用VC的编译器和链接器或ADS1.2的编译器和链接器。
接下来我们从具体的工程实践来看MTK的手机软件系统。 一.MTK手机软件系统的目录结构简介
MTK手机软件系统的主要目录如下所示,因整个工程的目录树非常庞大,为简单起见和减小篇幅,去除了在工程结构中相对不重要的目录。
|--Fast_DL |--ROM |--adaptation |--applib |--bootloader |--config |--custom | |--app | | `--TOP_6227_BB | |--common | |--drv | | |--LCD | | | `--TOP_6227_LCM | | `--image_sensor | | `--MT9D011 |--drv |--fs |--inc |--init
|--interface |--j2me |--kal |--make | |--applib | | |--applib.def | | |--applib.inc | | |--applib.lis | | `--applib.pth | |--bootloader | |--config | |--custom |--media |--mmi |--modis |--mtk_lib | `--MT6227 | `--S01 | `--gprs | |--abm.lib
| |--adaptation.lib | |--applib_inet.lib |--nucleus |--nvram |--plutommi |--tools
Fast_DL是开发时下载二进制映像和资源等的相关文件的目录。ROM是固化在ROM(可能是Flash的只读区)中的相关代码和头文件的目录,在给客户的发布版中大都只有一些导出函数的头文件,其中似乎还有一个跳转表的东西ROMSA_FuncTable。
kal是上面所说的内核抽象层的相关文件的目录。nvram是存取NV中的内容的相关代码的目录。nucleus是nucleus实时操作系统的目录,在给客户的发布版中只有头文件。drv是驱动相关的代码的目录。fs是文件系统相关的目录,好像只支持fat格式的。tools是工程相关工具的目录,包括MinGW。interface是系统各层的接口的目录,还包含重要模块的接口,如bluetooth、WIFI。config是一些系统和任务(task)相关头文件的目录,感觉不像是配置相关的目录。inc是中断控制和寄存器地址相关头文件的目录。
modis是PC模拟版的相关目录,包括了虚拟的GSM网络、SIM卡等,以及模拟器需要的字符串、图片等资源,还有PC模拟版的库、VC的相关工程文件。
mmi是一个缺省的空的MMI应用的目录,其中只是创建了一个什么也不干的MMI任务(线程),处理下层发送上来的消息。plutommi是pluto组织(也可能是原本的mmi应用的代号)所写的整套MMI应用所在的目录,而实际上也就是我们需要定制和修改的MMI应用。其中的mmi目录中是pluto原本写好的mmi应用,mtkapp中是mtk后来所写的mmi应用,而Customer中是图片、字符串等资源的定制目录,大部分只是修改了字符串和图片、声音等的项目只要修改这个目录下的资源即可。
mtk_lib中是已经编译链接好的ARM版的库。因整个工程过于庞大,若完整的全新构建一次需要很长的时间。为了减少构建的时间,将一些已经完全调试稳定且基本不再改动的库和MTK不开放源代码的库放到这个目录,这样每次构建时只需要将这些库和其他编译好的库链接起来就可以了。这些库一般是ARM版的,若有thumb版的,则再增加一个和ARM版相对的thumb版的库,一般叫第二个库,如media_sec.lib就是thumb版的多媒体库。
custom是所有客户化项目的驱动程序及系统和MMI应用定制相关的文件的目录。如你的手机主板的RAM、FLASH等存储器的尺寸和地址空间有改动,MMI应用的特性有不同,蓝牙、WAP的配置有变化,或是有项目相关的新应用,其相关文件都是放在这个目录中和特定项目对应的目录下,如项目CUST1_6227,则放在CUST1_6227_BB下。要注意的是custom也作为一个模块存在,这使得其可以通过make目录中的custom模块的四个文件进行客户化的一些定制。
applib、bootloader、init、media、j2me等是这个系统各个层次的相对独立的模块各自的目录,其实drv和fs等目录也可以看成是相对独立的模块,只不过其更重要些而在前面介绍。这些目录包含了这些模块的C文件和头文件。每个目录(模块)都在下面的make目录中有相对应的目录保存构建时的编译链接配置文件。
make是工程构建过程中最重要的一个目录了,工程构建用的Makefile和一些中间配置文件将放在这里,Makefile在讲解构建过程时再具体介绍。在每个模块对应的目录下,都有四个文件控制了编译链接时的过程和配置。分别是:
程根目录的路径。
build目录中保存了构建过程中产生的目标文件和库文件,及其他一些中间文件。 二.MTK手机软件系统的构建过程
如前面一节所述,MTK手机软件系统的构建使用了GNU的make,使得整个工程的构建可以自动进行,且可以灵活控制。整个构建过程由Make.bat、make2.pl、MoDIS.dsw、Gsm2.mak、Option.mak、
在MTK手机软件系统的根目录下有一个批处理文件Make.bat,这个批处理文件启动了整个工程的构建过程。在windows的命令行下,在该系统的根目录下输入命令make和相应的参数即可开始工程的构建,该批处理文件的使用方法如下所示。 Usage:
make[\Description: customer =mtk (Defaultcustomer) =firefly17_demo(FIREFLY17_DEMOproject) =[mt6217|mt6219|mt6226|mt6227|mt6228|mt6229](EVBonly) =... project =l1s (Layer1stand-alone) =gsm (GSMonly) =gprs (GPRSonly) =basic (BasicFramework) action =new (codegen,resgen,clean,update)(default) =updateoru (scan,compile,link) =remakeorr (compile,link) =cleanorc (clean)
=resgen (resgen) =c,u (cleanthenupdate) =c,r (cleanthenremake) =codegen (codegen) =viewlog (openedittoviewbuildlog) =emigen (emigen) =emiclean (emiclean) module(s)=modules'name (kal,l1,...) =>OPTIONALwhenactionisoneof(cleancremakerupdateuc,rc,u) Example:
makegsmnew (MT6205BEVBnew) makegprscodegen (MT6218BEVBcodegen) makemt6219gprsupdate (MT6219EVBupdate) makefirefly17_demogprsnew
makemilan_demogprsc,uinitcustom makemt6219gprsrinitcustomdrv
其中较常用的action有new、update、remake、new_modis这几个。
new是全新开始构建整个工程的ARM版,包括图片、声音、字符串等资源都要重做,依赖的其他动作最多,是最彻底也是耗时最长的一个动作,一般得到一个新的MTK发布版本后要做一次。
update是重新更新整个工程的ARM版,该动作会扫描工程中文件和库的依赖关系,若依赖关系有变化会建立新的依赖关系,随后根据新的依赖关系重新编译链接有改动的部分,一般在增加或删除一些驱动或应用的情况下需要用update。 remake是重新编译整个工程的ARM版,该动作只是简单的重新编译链接有改动的部分,不检查依赖关系,是耗时最短的一个动作,也是最常用的动作。
new_modis是全新构建整个工程的PC模拟版,其调用VC的编译器和链接器得到一个可以在windows上运行的PC模拟版。MMI应用软件工程师可以在没有硬件板的情况下在PC上检查和调试自己写好的应用。
Make.bat实际上只起引导作用,其只有一行批处理语句perlmake2.pl%*,于是运行该批处理文件后控制权转给了perl脚本make2.pl。在这个perl脚本中解析了用户输入的命令行参数,设置变量,准备make时需要的临时配置文件,随后根据生成的可运行映像是PC模拟版还是ARM版而分别调用不同的构建过程。 Pc模拟版的构建通过调用如下命令实现。
system(\/OUT${MoDISLogDir}\\\\${argu}.log\
在这里$msdev就是VC的msdev,通过VC的工程文件MoDIS.dsw和后面的参数进行具体的构建过程。熟悉VC工程的朋友应该比较清楚,因此就不再具体解释了。之后将只以ARM版为主来讲解整个工程的构建过程。 ARM版的构建通过调用如下命令实现。
system(\CUSTOMER=$customPROJECT=$project$action\
在这里${makeCmd}是tools\\make.exe,即GNU的make,${makeFolder}${myMF}是make\\Gsm2.mak,$action是new、update、remake等。变量CUSTOMER和PROJECT分别是客户名和项目名,在构建过程中将根据此两个变量的值选定项目相关的配置文件,
从而实现客户化的定制。通过给make指定ARM版的核心Makefile文件Gsm2.mak,开始了ARM版的构建过程。
Gsm2.mak文件中包含了Option.mak这个配置用的Makefile文件,另外还包含了一些以.tmp和.bld为后缀的由perl脚本make2.pl生成的临时配置文件。这些临时配置文件主要是一些action如clean、remake等所需的变量设置,及客户化和版本号等的一些信息。Gsm2.mak控制了new、update、remake等动作的过程。具体分别如下所示。
new:cleanallcmmgenmmi_feature_checkasngencodegenasnregen\\ operator_check_liteupdate
update:cleanlogcleanbinmcddll_updatecodegenresgencksysdrvremake remake:cleanlogcleanbingenvernolibs$(BIN_FILE)done 上面的构建过程的几个步骤中,最重要的两个步骤是libs、$(BIN_FILE)。libs调用ARM版的编译器和连接器将各个模块目录下的C文件编译链接为独立的库。$(BIN_FILE)这个步骤将各个模块编译链接得到的库和mtk_lib目录下的库一起链接起来得到一个映像文件,然后使用ADS的工具fromelf将映像文件生成以变量BIN_FILE命名的二进制文件,该文件可以下载到硬件板上运行。 libs这个步骤如下所示。
libs:cleanlibstartbuildlibs$(COMPLIBLIST)
libs中真正进行编译链接的步骤是$(COMPLIBLIST),要生成的库由变量COMPLIBLIST列出,在ARM版中,变量COMPLIBLIST从变量COMPLIST得到。变量COMPLIST是在Option.mak及其包含的Makefile文件中赋值的。因有很多库需要编译链接,变量COMPLIBLIST展开后包含多个步骤,而这些步骤都是重复不变的,因此在定义步骤$(COMPLIBLIST)的构建过程时使用%.lib代替。%.lib这个步骤先清除了之前的一些依赖关系文件,将一些变量的设置写入~compbld.tmp这个临时文件中,然后给make指定Makefile文件comp.mak,完成库的编译和链接,如下所示。 %.lib: … @if/I%OS%EQUWINDOWS_NT\\ (if/I$(BM_NEW)EQUTRUE\\ (tools\\make.exe-fmake\\comp.mak-k-r-R$(strip$(CMD_ARGU))COMPONENT=$*>$(strip$(COMPLOGDIR))\\$*.log2>&1) \\ else\\ (tools\\make.exe-fmake\\comp.mak-r-R$(strip$(CMD_ARGU))COMPONENT=$*>$(strip$(COMPLOGDIR))\\$*.log2>&1)\\ )\\ else\\ (if/I$(BM_NEW)EQUTRUE\\ (tools\\make.exe-fmake\\comp.mak-k-r-R$(strip$(CMD_ARGU))COMPONENT=$*>$(strip$(COMPLOGDIR))\\$*.log)\\ else\\
(tools\\make.exe-fmake\\comp.mak-r-R$(strip$(CMD_ARGU))COMPONENT=$*>$(strip$(COMPLOGDIR))\\$*.log)\\ )
上面的命令语句中,参数-k是指有错误也要继续编译,-r和-R是指没有GNUmake的默认规则和变量。COMPONENT=$*把当前要生成的库赋给变量COMPONENT。要注意%.lib匹配了所有要生成的库,但这个步骤一次只生成一个模块的库,这个步骤对所有匹配到的库都会执行一次。
comp.mak这个Makefile文件控制了模块的编译链接过程。在这个文件中,首先将当前模块要生成的库(由变量COMPONENT传入)设置给了变量TARGLIB。之后从
库的编译链接由update_lib步骤完成,这个步骤直接依赖了$(TARGLIB)。目标
$(TARGLIB)是由所有按照.c.obj、.s.obj、%.obj:%.cpp等规则编译得到的中间目标文件链接得到的。其主要过程如下所示。 $(TARGLIB): ... @ifexist$(FIXPATH)\\$(CUS_MTK_LIB)\\$(COMPONENT).lib\\ (copy/z$(FIXPATH)\\$(CUS_MTK_LIB)\\$(COMPONENT).lib$(subst/,\\,$(TARGLIB)))&\\ ($(LIB)-r$(TARGLIB)$(COMPOBJS_DIR)/*.obj)\\ else\\ ($(LIB)-create$(TARGLIB)$(COMPOBJS_DIR)/*.obj) ...
Option.mak是整个工程构建过程中的总控配置文件,在这个文件中还包含了
MTK手机软件系统的大部分配置都已经确定,基本上不需要再改变,一般是MTK发布新的版本时会作些改变,客户不大需要关心。最主要的配置文件是Option.mak,而客户化定制需要需要修改的主要是
Option.mak文件中设置了工程构建时用到的编译器、链接器、库管理、二进制文件生成等工具的路径和可执行程序名,设置了基本的编译链接参数,指定CPU类型(ARM7EJ-S),
确定最终使用的库列表(COMPLIST)。 一个项目是由工程中的多个基本库、第三方库和由源代码新编译链接的库组成的,最终这些库链接到一起得到一个完整的可执行映像文件。由哪些新编译链接的库来组成一个项目是由四个关键的变量决定,其中一个是前面提到的COMPLIST,另外三个分别是CUS_REL_SRC_COMP、CUS_REL_PAR_SRC_COMP、CUS_REL_MTK_COMP。这个几个变量的关系如下所示。
#************************************************************************* #CustomReleaseComponentConfiguration
#************************************************************************* #Besurethefollowing:
#1.CUS_REL_SRC_COMP+CUS_REL_PAR_SRC_COMP=COMPLIST(CUSTOM_RELEASE=True)
#2.CUS_REL_SRC_COMP+CUS_REL_PAR_SRC_COMP+CUS_REL_MTK_COMP=COMPLIST(CUSTOM_RELEASE=False)
COMPLIST确定了该项目最终是由哪些库(组件)组成的。MTK的内部版本构建时,则包括CUS_REL_SRC_COMP、CUS_REL_PAR_SRC_COMP、CUS_REL_MTK_COMP这些库。客户版本构建时,则只包括CUS_REL_SRC_COMP、
CUS_REL_PAR_SRC_COMP这些库。手机设计公司构建的版本都是客户版本,因此只要改变CUS_REL_SRC_COMP、CUS_REL_PAR_SRC_COMP这两个变量的值即可以定制自己的项目了。
MTK_LIBS确定了该项目最终包含了哪些MTK提供的基本库。
COMPOBJS确定了该项目最终包含了哪些第三方提供的不带源代码的库。变量CUS_RES_OBJ_LIST用于把这些第三方库随项目发布。
Option.mak和REL_CR_MMI_
J2ME_SUPPORT =NONE #J2MEsupport:NONE,MTK_J2ME,J2ME_LIB,\\ MTK_J2MEHI,J2MEHI_LIB,MTK_DUMMYVM DRM_SUPPORT=NONE#DRMVENDOR:NONE,MTK,BSCI DRM_VERSION=NONE#DRMVERSION:NONE,V01,V02,ALL AMRWB_DECODE =TRUE #TRUE/FALSE AMRWB_ENCODE =FALSE #TRUE/FALSE #MT6219DSPcannotsupportAMRWB_ENCODEwhenGPRSconnection JPG_DECODE =JPG_HW #NONE,JPG_HW,JPG_SW JPG_ENCODE =JPG_HW #NONE,JPG_HW,JPG_SW GIF_DECODE =TRUE #TRUE/FALSE
PNG_DECODE =NONE #NONE,PNG_HW,PNG_SW DAF_DECODE =TRUE #TRUE/FALSE MJPG_SUPPORT =FALSE #TRUE/FALSE MP4_CODEC =TRUE #TRUE/FALSE AAC_DECODE =TRUE #TRUE/FALSE ISP_SUPPORT =TRUE #TRUE/FALSE CMOS_SENSOR =OV7660 #OV9640,PAS105,PAS302,NONE,MT9D011,\\ MT9M111,OV9650 四.增加模块的配置实例
若我们需要加入zlib这么一个模块(zlib包含了很多程序都用到的压缩和解压函数),我们可以按如下步骤进行。
1.把zlib的源代码包拷贝到你的MTK软件系统根目录下,这样所有的zlib代码都在zlib目录或zlib-1.2.3目录下(用哪个目录名由你的喜好来确定),在此为简单起见就放在zlib目录。
2.在make目录下新增一个zlib的目录(最好和根目录下的目录名一样),增加四个文件,分别是zlib.def、zlib.inc、zlib.lis、zlib.pth。zlib.def文件只要加上APCS_INTWORK就可以了,其他三个文件中加上源文件及其目录、头文件目录即可。 3.在REL_CR_MMI_
4.把这个工程remake一下,若没有错误,zlib模块就成功加上去了。其他模块就可以调用zlib提供的压缩和解压缩函数了。
若我们需要加入一个没有源代码的第三方库,譬如加入wifi,我们可以按如下步骤进行。 1.把wifi的所有第三方库文件拷贝到一个新建的wifi目录下。 2.在Option.mak这个文件的合适位置加上如下语句。 ifeq($(strip$(WIFI_SUPPORT)),WIFI_LIB) COMPOBJS+=wifi\\sslplus.lib CUS_REL_OBJ_LIST+=wifi\\sslplus.lib COMPOBJS+=wifi\\sb.lib CUS_REL_OBJ_LIST+=wifi\\sb.lib endif
3.把这个工程remake一下,若没有错误,wifi库就成功加上去了。其他模块就可以调用wifi提供的功能了。
MTK6225开机过程-系统启动
以下开机过程都是在simulator上跑时得出的结论
第一步:启动simulator的时候,直接进入:MMI_task() 1.iacMemInit();
2.进入一个while(1)循环。以后的过程都是通过消息机制,即:一直在这个循环中读取消息,然后做相应的处理。
第一次进入while(1)之后,OslReceiveMsgExtQ(qid,&Message)就读取到一个消息:PRT_MMI_TIMER_IND。然后就一直在这个循环中读消息。 第二步:PowerOn
读取到消息:MMI_EQ_POWER_ON_IND caseMMI_EQ_POWER_ON_IND: gdi_init(); switch(p->poweron_mode) //判断poweron的模式 { casePOWER_ON_KEYPAD://用户按下开机键 OslMemoryStart(TRUE); g_charbat_context.PowerOnCharger=0;//不是因为充电而开机的 InitializeAll();//初始化,重点学习 OslDumpDataInFile();//这个函数不能进入,直接跳过 InitNvramData(); //加载保存在NVRAM中的设置的参数 mmi_pwron_entry_animation_screen();//开机动画 break; casecasePOWER_ON_PRECHARGE: casePOWER_ON_CHARGER_IN: g_pwr_context.PowerOnMode=p->poweron_mode; InitializeChargingScr(); break; casePOWER_ON_ALARM: //定时开机 AlmInitRTCPwron(); break; casePOWER_ON_EXCEPTION://ForabnormalresetwheninvalidSIM OslMemoryStart(TRUE); SetAbnormalReset(); InitializeAll(); OslDumpDataInFile(); ClearInputEventHandler(MMI_DEVICE_ALL); ClearKeyHandler(KEY_END,KEY_LONG_PRESS); InitNvramData(); AlmReInitialize(); InitAllApplications(); mmi_pwron_exception_check_display(); break; }
执行过开机之后,就不会进入这里了。
第三步、在模拟器上随便按键,就进入defalt这里: default: ProtocolEventHandler( (U16)Message.oslMsgId, (void*)Message.oslDataPtr, (int)Message.oslSrcId,
(void*)Message.oslPeerBuffPtr); break;
以上是总体的开机过程。下面学习蓝色部分具体内容: InitializeAll() { InitUnicodeSupport();//设置使用的编码函数 gdi_init(); //图形库初始 mdi_audio_init(); //音频初始化 jdi_audio_init(); InitProtocolEvents();//初始化协议事件(函数是空的) InitFramework(); //初始化事件的处理函数,以及histroy等。 { InitEvents(); //Initializeeventhandlers InitProcessKeyEvent(); //Initializekeyprocess InitHistory(); //Initializehistory } InitHardwareEvents(); //设置一些硬件事件的protocolhandler。 InitTime(); InitMMI_App(); setup_UI_wrappers(); //初始化图形界面相关的参数 PopulateResData(); //装载资源包括:menu,string,image {
增加applications
ADD_APPLICATION(APP_MAINMNNU,APP_IDLEAPP,APP_BOOTUP, APP_SIMTOOLKIT,APP_GLOBALDEFS, APP_CHARGER,APP_UIFRAMEWORK, APP_HONEBOOK,APP_SHORTCUTS, APP_SERVICES,APP_ORGANIZER,
APP_MESSAGES,APP_CHAT,APP_SETTINGS, APP_CALLMANAGEMENT,APP_DEMOAPP, APP_CLLHISTORY,APP_CALLSETUP, APP_PROFILES,APP_NEWORKSETUP, APP_DATAACCOUNT,APP_PHONESETUP, APP_TODOLIST,APP_INPUTMETHOD。。。。。。);
装载每一个application的资源(MUNE,IMAGE,STRING) (1)PopulateNFBProgressImg(); //0—9及其他的image (2)PopulateGlobalData();
装载全局资源:主要就是加载字串
ADD_APPLICATION_STRING2和加载图像
ADD_APPLICATION_IMAGE2。注意:有很多image的图像是空的,即在显示时,即使设置了显示的imageID,但还是没有图片。只有STRING。 (3)PopulateMainMenuRes();
在代码中有3个此函数,利用宏的控制以达到不同的应用。 GW606进入的是中间的这个函数,即:宏
__MMI_BI_DEGREE_MAIN_MENU_STYLE__关闭,宏__MMI_VERSION_2__打开。 加载左软件开始进入的九宫图MENU。 ADD_APPLICATION_MENUITEM(( IDLE_SCREEN_MENU_ID,0,9, MAIN_MENU_PHONEBOOK_MENUID, MAIN_MENU_MESSAGES_MENUID, MAIN_MENU_CALL_HISTORY, MAIN_MENU_SETTINGS_MENUID, MAIN_MENU_MULTIMEDIA_MENUID, MAIN_MENU_FILE_MNGR_MENUID, MAIN_MENU_PROFILES_MENUID, MAIN_MENU_EXTRA_MENUID, MAIN_MENU_SERVICES_MENUID, 0,INSERTABLE, MATRIX_MENU MAIN_MENU_MENU_TEXT, MAIN_MENU_PHONEBOOK_ICON)); 装载电话簿的MENU(SIM卡有效) ADD_APPLICATION_MENUITEM(( MAIN_MENU_PHONEBOOK_MENUID。。。 装载电话簿的MENU(SIM卡无效) ADD_APPLICATION_MENUITEM(( MAIN_MENU_PHONEBOOK_NO_SIM_MENUID。。。 装载通话记录的MENU ADD_APPLICATION_MENUITEM(( MAIN_MENU_CALL_HISTORY。。。 装载功能设置的MENU ADD_APPLICATION_MENUITEM(( MAIN_MENU_SETTINGS_MENUID。。。 装载没有SIM卡时,电话设置的MENU ADD_APPLICATION_MENUITEM(( MAIN_MENU_SETTINGS_NO_SIM_MENUID, MENU_SIM_OPTION_ID, 。。。 装载多媒体娱乐的MENU ADD_APPLICATION_MENUITEM(( MAIN_MENU_MULTIMEDIA_MENUID 装载文件管理的MENU ADD_APPLICATION_MENUITEM(( MAIN_MENU_FILE_MNGR_MENUID。。。 装载网络服务的MENU ADD_APPLICATION_MENUITEM2(( MAIN_MENU_SERVICES_MENUID。。。 装载工具箱的MENU
ADD_APPLICATION_MENUITEM(( MAIN_MENU_EXTRA_MENUID。。。 到这里,就装载了九宫图的MENU,以及其其大部分MENU的child MENU。红色的两个: MAIN_MENU_MESSAGES_MENUID (信息) MAIN_MENU_PROFILES_MENUID (情景模式) 没有装载其childMENU。 加载以上MENU中需要使用的STRING和IMAGE。 (4)PopulateIdleMenuRes();加载IDLEapplication使用的资源 { PopulateStatusIconResources();加载IDLE界面的image PopulateCommonCategoryResources(); PopulateThemeResources(); } (5)PopulatePbResData(); Populatephonebookresourcedata 加载【电话簿】中的每个EMNU的childmenu,stirng,image。 (6)PopulateMainDemoRes(); PopulatingMainDemoResources (7)populateSettingMenu(); PopulatingSettingResources 加载【功能设置】中的每个childmenu的各种资源。包括:话机设置, 通话设置,网络设置,GPRS连接设置,安全设置,恢复出厂值,音效,蓝牙。 { 加载[话机设置]的childmenu,string和image,以及下一层?的childmenu,stirng,image。 ADD_APPLICATION_MENUITEM(( MENU9102_INITIAL_SETUP。。。 PopulateNetworkSetupResData(); //加载【网络设置】资源 populateManageCalls(); //加载【通话设置】资源 PopulatePhoneSetupResData();//刚进入populateSettingMenu() 的时候,加载了【话机设置】中一部分的资源。更 多的资源是在这个函数中加载的。 populateSecuritySetup(); //加载【安全设置】资源 PopulateLanguageStrings(); #ifdef__MMI_SOUND_EFFECT__ PopulateSoundEffectResData(); #endif #ifdef__FLIGHT_MODE_SUPPORT__ PopulateFlightModeResData(); PopulateConnectSetting(); #endif }
(8)populateFunAndGamesMenu(); PopulatingFun&GamesResources (9)PopulateSimDetectionMenuRes(); PopulatingSIMDetectResources (10)PopulateChgrPwrOnScrRes(); PopulatingChargerPowerOn (11)PopulateCommonScreensResData();PopulatingCommonScreen (12)PopulateEMSObjectResources(); PopulatingEMSobjectResources (13)PopulateCmResData(); PopulatingCMResources 加载通话过程中使用的各种资源 首先加载来电时,各种状态下的资源:MENU,STIRNG,IMAGE 然后调用PopulateCmOutResData();加载呼出电话时各种资源 (14)PopulateQuickAccessData(); PopulatingQuickAccessResources (15)PopulateInputMethodRes(); PopulatingInputMethodResources (16)PopulateprofileMenu(); PopulatingProfilesResources 。。。。。。 }//加载资源结束
PopulateResGetBaseIDTable(); PowerAndEndKeyHandler(); //setspowerkey&endkeyhandlers
MTK开机流程—应用部分
应用启动四个阶段:系统资源配置等待开机事件开机动画进入待机界面。 1 说明:
(适用于MTK6223平台)
在分析开机流程的过程中,我们首先需要学习平台的相关文档,并阅读代码,有初步的了解后,再搭建调试环境,通过跟踪和打印LOG来分析验证实际的开机流程。由于目前的条件限制以及平台存在的一些缺陷,目前我调试的方法是结合串口打印和模拟器打印、跟踪的方法来调试的。
因为开机流程跟开机触发原因、卡状态、网络状态、本机设置以及用户交互都有关系,流程各不相同,本文档只分析其中一种过程,在这个过程下学会分析问题和解决问题的方法之后,其他的流程可按此方法分析得来。 2 应用启动第一阶段—系统资源配置:
应用启动的第一阶段是创建系统环境,对TARGET开发板来说,就是启动底层硬件、配置MCU、配置外围器件,创建操作系统、配置系统资源、创建各种任务等;对模拟器了说,主要是创建工作环境来模拟开发板,并提供一套GUI来提供输入输出,和用户交互。下图是模拟器在启动但没开机的时候的串口信息,目标板的信息与之相似: 3 应用启动第二阶段—等待开机事件: 下图是在添加打印语句后在模拟器上得到的打印信息:
由于模拟器是无法完全模拟TARGET上的硬件信息和嵌入式系统的BOOT过程、操作系统创建、任务加载过程的,所以我们目前暂时先不重点关注这个部分,本文档的目的
也是在模拟器能完成的应用启动流程上进行说明和介绍。 从上图我们可以看到,在应用启动的过程中,先是创建mmi_task(),然后进入MMI_task()功能实体,进行MMI应用的初始化,并进入无限循环等待事件处理。在最开始的时候,是等待开机事件,进行应用部分的开机。
开机事件是MSG_ID_MMI_EQ_POWER_ON_IND,在MMI_task收到这个事件后,进入函数分支: ??
switch(p->poweron_mode) casePOWER_ON_KEYPAD: …… mmi_bootup_entry_disk_check(); 然后再逐层调用:
mmi_bootup_exit_disk_check()
mmi_bootup_entry_flight_mode_query() FlightModeCheckBeforeAnimation() MTPNP_AD_Bootup()
(这个调用过程到这里就结束了,这个函数是底层封装函数,通过反汇编以及函数调用栈,我们可以看到程序的运行状态。)
我们可以看到,这个封装函数调用了MTPNP_PFAL_Master_Startup_Normal(),再看MTPNP_PFAL_Master_Startup_Normal()的反汇编函数,如下: 调用了PowerOnNormalMode()。
所以程序能够继续运行下去,整个开机过程的栈结构如下: 4 应用启动第三阶段—开机动画: PowerOnNormalMode()的执行过程如下: 具体的实现我们可以参照代码来阅读。可以看到此时手机还处在播放开机动画的过程当中,调用SimPasswdReqResponse()进入其中的一个函数分支。
到开机动画播放完后,会有一个定时器事件上面给MMITASK,进行相关的处理后,退出动画播放,再调用SimPasswdReqResponse()进入它的另一个分支,下面是动画播放完后的函数调用关系。
最后调用到mmi_ready_to_idle_screen_ind(),该函数是MOD_MMI任务自己给自己发一个MSG_ID_MMI_READY_TO_IDLE_SCREEN_IND消息到外部消息队列,并设置好该事件的处理函数mmi_ready_to_idle_screen_ind_hdlr(),本轮消息处理调用过程结束。 5 应用启动第四阶段—进入待机界面:
在MMI_task主循环里收到事件MSG_ID_MMI_READY_TO_IDLE_SCREEN_IND,根据注册的事件处理函数,调用mmi_ready_to_idle_screen_ind_hdlr(),具体的处理过程见下面的函数调用栈:
下面是该过程的串口打印信息,注意看函数的执行过程,与调用栈的阅读方式是相反的。到这个过程执行完成,就进入了待机界面了,我们的应用开机过程就基本完成了。
MTKPhoneBook开机流程
开机之后,初始化时,设置如下三个PS消息CBack函数: InitializeAll()
mmi_phb_init_protocol()
SetProtocolEventHandler(mmi_phb_ind_startup_finish,PRT_PHB_STARTUP_FINISH_IND);
SetProtocolEventHandler(mmi_phb_ind_startup_begin,PRT_PHB_STARTUP_BEGIN_IND);
SetProtocolEventHandler(mmi_phb_ind_startup_read,PRT_PHB_STARTUP_READ_IND); 1.L4在到NVRAM读取data之前,发送消息到MMI:PRT_PHB_STARTUP_BEGIN_IND,进入:
mmi_phb_ind_startup_begin()
初始化一些变量,准备重新reloadentries. 2.L4每读取一个ANDentry,都有发送消息到MMI:PRT_PHB_STARTUP_READ_IND,进入:
mmi_phb_ind_startup_read() L4返回消息的结构: typedefstruct { LOCAL_PARA_HDR l4c_phb_entries_structphb_entries[1]; kal_uint8 access_id; }mmi_phb_startup_read_ind_struct; typedefstruct { kal_uint16num_of_entry; l4c_phb_bcd_entry_structphb_entry[2000/NVRAM_PHB_SIZE]; }l4c_phb_entries_struct; typedefstruct{ kal_uint8storage; kal_uint8type; kal_uint16index; kal_uint16record_index; l4_addr_bcd_structtel; l4_name_structalpha_id; }l4c_phb_bcd_entry_struct; MMI中,保存电话entries的全局变量PhoneBook结构如下: MMI_PHB_ENTRY_BCD_STRUCTPhoneBook[MAX_PB_ENTRIES]; typedefstruct { //U8 storage; //U8 type; //U16 index; //U16 record_index; MMI_PHB_NUMBER_BCD_STRUCTtel; MMI_PHB_NAME_STRUCTalpha_id; U8field; U8dummy;
}MMI_PHB_ENTRY_BCD_STRUCT; typedefstruct { U8type; U8length; U8number[(MAX_PB_NUMBER_LENGTH+1)/2]; }MMI_PHB_NUMBER_BCD_STRUCT; typedefstruct { U8name_length; U8name_dcs; U8name[(MAX_PB_NAME_LENGTH+1)*ENCODING_LENGTH]; }MMI_PHB_NAME_STRUCT; mmi_phb_ind_startup_read()流程 mmi_phb_ind_startup_read_next_req() if(MMI_SIM) mmi_phb_startup_read_entry() 把消息保存到全局变量PhoneBook中 mmi_phb_util_make_pinyin_cache()//保存name拼音 g_phb_name_pinyin_index[][] g_phb_name_index[PhoneBookEntryCount]=store_index; PhoneBookEntryCount++; else//NVRAM for()//读取一批nvram记录 mmi_phb_startup_read_entry() 3.当L4从NVRAM中读取完之后,发送消息PRT_PHB_STARTUP_FINISH_IND到MMI,表示L4已经读完了。MMI接收到这个消息之后,开始loadallentriesfromL4。 返回的消息结构: typedefstruct { LOCAL_PARA_HDR kal_uint16 sim_max_num; kal_uint16 phb_max_num; kal_uint8 phb_len; kal_uint8 fdn_len; kal_uint8 bdn_len; kal_uint8 owner_len; }mmi_phb_startup_finish_ind_struct; mi_phb_ind_startup_finish()流程 初始化g_phb_cntx中的结构 if(!g_phb_cntx.nvram_data_init) { //从NVRAM中读取电话簿的一些信息。比如:群组,栏位设置,存储选择等等。
mmi_phb_init_get_data_from_nvram(); g_phb_cntx.view_field g_phb_cntx.prefer_storage g_phb_cntx.name_list_filter g_phb_cntx.caller_group g_phb_cntx.nvram_data_init=TRUE; } mmi_phb_startup_finish_final_step() mmi_phb_sort_build_name_index() //利用分治策略和插入排序进行快速排序g_phb_name_index[]。 //g_phb_name_index[]中存储的是PhoneBook[]中entries的存储索引。 mmi_phb_ind_startup_finish_after_name_sort() mmi_phb_init_build_lookup_table() //把PhoneBook中以g_phb_name_index[]中的内容为索引的entry的号码,转换成ASCII码, //然后转换成32为int型数据,并保存在全局变量LookUpTable[]中。 //注意:一并保存的还有store_index也就是该entry在PhoneBook中存储位置。 StartTimer(PHB_READ_OPT_FILED_TIMER,500, mmi_phb_init_populate_lookup_table); //500ms后执行mmi_phb_init_populate_lookup_table() //以g_phb_name_index[]中的内容为索引,到NVRAM中读取optionfields数据 //ReadMultiRecord()。然后把读取的数据保存在LookUpTable[]中。 //包括:传真号码,家庭号码,公司号码。每读取10次,就暂停250ms,然后继续读取。 //全部读完之后,进入:mmi_phb_lookup_table_sort() //Allentriespopulated,begintosortit。 //因为在装载电话号码的时候,LookUpTable[]中的内容是按照字母顺装载的, //但是在装载NVRAM中的传真,家庭,公司号码时,是按照存储顺序装载的。 //而这里的排序,是根据电话号码的大小来排序的。 //即:按照电话号码的大小,从小到大排列。 //当来电的时候,采取对半查找效率就很高了。 小结:到这里,就完成了电话簿的初始化。即:
(1)从NVRAM,SIM卡中读取了数据,并保存在L4中了;
(2)MMI中的全局变量PhoneBook[]与L4中的电话簿已经同步了;
(3)g_phb_name_index[]中按照字母的大小顺序,存储了每一个entry在PhoneBook[]中的存储位置;
(4)所有的号码,包括SIM卡,NVRAM,移动电话,家庭,公司,传真号码,都按照大小顺序,存储在LookUpTable[]中了,并且存储了PhoneBook中的存储位置索引。
MTK-Phonebookbootup开机流程
一、开机流程
开机之后,初始化时,在InitializeAll()中callmmi_phb_init_protocol(),设置如下几个PS消息CBack函数:
SetProtocolEventHandler(mmi_phb_ind_startup_finish,PRT_PHB_STARTUP_FINISH_IND);
SetProtocolEventHandler(mmi_phb_ind_startup_begin,PRT_PHB_STARTUP_BEGIN_IND);
SetProtocolEventHandler(mmi_phb_ind_startup_read,PRT_PHB_STARTUP_READ_IND);
1.L4在到NVRAM读取data之前,发送消息到MMI:PRT_PHB_STARTUP_BEGIN_IND,进入:
mmi_phb_ind_startup_begin() 初始化一些变量,准备重新reloadentries.
2.L4每读取一个ANDentry,都有发送消息到MMI:PRT_PHB_STARTUP_READ_IND,进入: L4返回消息的结构: typedefstruct { LOCAL_PARA_HDR l4c_phb_entries_structphb_entries[1]; kal_uint8 access_id; }mmi_phb_startup_read_ind_struct; typedefstruct { kal_uint16num_of_entry; l4c_phb_bcd_entry_struct phb_entry[2000/NVRAM_PHB_SIZE]; }l4c_phb_entries_struct; typedefstruct{ kal_uint8storage; kal_uint8type; kal_uint16index; kal_uint16record_index; l4_addr_bcd_structtel; l4_name_structalpha_id; }l4c_phb_bcd_entry_struct; MMI中,保存电话entries的全局变量PhoneBook结构如下: MMI_PHB_ENTRY_BCD_STRUCTPhoneBook[MAX_PB_ENTRIES];
typedefstruct { //U8 storage; //U8 type; //U16 index; //U16 record_index; MMI_PHB_NUMBER_BCD_STRUCTtel; MMI_PHB_NAME_STRUCTalpha_id; U8field; /*Indicateifanentryhasthefield*/ U8dummy; /*Makesureeachphbstructureistwo-bytesaligned.*/ }MMI_PHB_ENTRY_BCD_STRUCT; typedefstruct { U8type; /*129-default;145-international,beginwith''+''*/ U8length; U8number[(MAX_PB_NUMBER_LENGTH+1)/2]; /*halfspacetostoreBCDformat.*/ }MMI_PHB_NUMBER_BCD_STRUCT; typedefstruct { U8name_length;/*NameLength*/ U8name_dcs; /*NameDataCodingScheme*/ U8name[(MAX_PB_NAME_LENGTH+1)*ENCODING_LENGTH]; }MMI_PHB_NAME_STRUCT; mmi_phb_ind_startup_read() mmi_phb_ind_startup_read_next_req(LocalPtr->access_id); MMI发消息到PRT_PHB_STARTUP_READ_NEXT_REQL4,请求readnext。 //假定是读取NVRAM中的entry for(i=0;i
} mmi_phb_startup_read_entry() 把消息保存到全局变量PhoneBook中。 信息保存在PhoneBook[store_index]中。可见:PhoneBook[]中的存储顺序就是L4中的存储顺序。 PhoneBook[store_index].tel.number中保存的是ASCII码。 //根据号码的第一个位置来设置是SIMentry还是NVRAMentry. PhoneBook[store_index].field=0; if(PhoneBook[store_index].tel.number[0]!=0xff) { PhoneBook[store_index].field|=MMI_PHB_ENTRY_FIELD_NUMBER; } g_phb_name_index[PhoneBookEntryCount]=store_index; 姓名列表,保存的是PhoneBook中entry的位置 PhoneBookEntryCount++;
3.当L4从NVRAM中读取完之后,发送消息PRT_PHB_STARTUP_FINISH_IND到MMI,表示L4已经读完了。MMI接收到这个消息之后,开始loadallentriesfromL4。 返回的消息结构: typedefstruct { LOCAL_PARA_HDR kal_uint16 sim_max_num; kal_uint16 phb_max_num; kal_uint8 phb_len; kal_uint8 fdn_len; kal_uint8 bdn_len; kal_uint8 owner_len; }mmi_phb_startup_finish_ind_struct; mi_phb_ind_startup_finish() //初始化g_phb_cntx中的结构 g_phb_cntx.sim_name_len=localPtr->phb_len; g_phb_cntx.fdn_name_len=localPtr->fdn_len; g_phb_cntx.bdn_name_len=localPtr->bdn_len; g_phb_cntx.owner_name_len=localPtr->owner_len; g_phb_cntx.sim_total=localPtr->sim_max_num; g_phb_cntx.phone_total=localPtr->phb_max_num; if(!g_phb_cntx.nvram_data_init) { mmi_phb_init_get_data_from_nvram();//从NVRAM中读取电话簿的一些信
息。比如:群组,栏位设置,存储选择等等。 g_phb_cntx.view_field g_phb_cntx.prefer_storage g_phb_cntx.name_list_filter g_phb_cntx.caller_group g_phb_cntx.nvram_data_init=TRUE; } mmi_phb_sort_build_name_index(); //sortnamelistg_phb_name_index。这个函数完成后,PoneBook中所有entries,如果按照g_phb_name_index[]中 //的值作为顺序来排列的话,将是按照姓名中字母从小到大的顺序。 //quicksortandinsertionsortg_phb_name_index[]。
g_phb_name_index[]中存储的是PhoneBook[]中entries的存储索引。这个函数的过程就是通过 //g_phb_name_index[]中的值,找到PhoneBook中相应的entries,然后比较PhoneBook中entries的name,从而来排列g_phb_name_index的值。 mmi_phb_sort_name_fast_quicksort(0,(U16)(PhoneBookEntryCount-1),mmi_phb_sort_compare_name_index_by_pinyin_cache); mmi_phb_sort_name_insertionsort(left,right,compare); //当FDN启动之后,AND就不能从SIM卡中读取出来了。就是为了防止未授权拨号 //当获取到FDNlist之后,一定要获取speeddialnumber。 if(gSecuritySetupContext.FdlStatus) { mmi_phb_fdn_get_list_to_ram(); //把FNDlist拷贝到AND的存储区。 if(g_phb_cntx.sim_used==0) { g_phb_fdn_count=0; mmi_phb_fdn_get_list_to_ram_req(); 发送消息PRT_PHB_GET_ENTRY_BY_INDEX_REQ到L4,去读取FDN。 返回消息PRT_PHB_GET_ENTRY_BY_INDEX_RSP,进入CBack函数: mmi_phb_fdn_get_list_to_ram_rsp() store_index=g_phb_fdn_count+MAX_PB_PHONE_ENTRIES; 把读取的信息保存到PhoneBook[store_index]中。可见:PhoneBook是先保存NVRAM号码,然后是SIM号
码。 /*RetrieveSpeedDialListafterretrieveFDNlist,becausetheyallusesamemessage.*/ PhbGetSpeedDialInfo(); } else { PhbGetSpeedDialInfo(); /*RetrieveSpeedDialListafterretrieveFDNlist,becausetheyallusesamemessage.*/ PhbReadSpeedDialNVRAM(); //从NVRAM中读取速拨信息 g_phb_cntx.phb_ready=TRUE; mmi_phb_init_build_lookup_table();//buildsthelookuptableforcross-referencingduringMO/MTcalls. } } else { if(gInsertSimAppFlag==1) { g_phb_cntx.phb_ready=TRUE; mmi_phb_init_build_lookup_table(); mmi_phb_util_read_compare_length()//获取g_phb_compare_length,即需要比较的号码最后几位 把PhoneBook中以g_phb_name_index[]中的内容为索引的entry的号码,转换成ASCII码,然后转换成32为int型数据,并保存 在全局变量LookUpTable[]中。注意:一并保存的还有store_index也就是该entry在PhoneBook中存储位置。 StartTimer(PHB_READ_OPT_FILED_TIMER,500,mmi_phb_init_populate_lookup_table); } else { PhbGetSpeedDialInfo(); } }
500ms之后,定时器溢出,进入:
mmi_phb_init_populate_lookup_table()
//Thisfunctionpopulatesthelookuptablewithhome/fax/mobile/officenumbersafterconvertingthelast7(or9)charactersofthephonenumberintodigits. 以g_phb_name_index[]中的内容为索引,到NVRAM中读取optionfields数据ReadMultiRecord()。然后把读取的数据保存在LookUpTable[]中。包括: 传真号码,家庭号码,公司号码。每读取10次,就暂停250ms,然后继续读取。 全部读完之后,进入:mmi_phb_lookup_table_sort() Allentriespopulated,begintosortit。因为在装载电话号码的时候,LookUpTable[]中的内容是按照字母顺装载的,但是在装载NVRAM中的传真,家庭,公司号码时,是按照存储顺序装载的。而这里的排序,是根据电话号码的大小来排序的。 即:按照电话号码的大小,从小到大排列。当来电的时候,采取对半查找效率就很高了。
小结:到这里,就完成了电话簿的初始化。即:
(1)从NVRAM,SIM卡中读取了数据,并保存在L4中了;
(2)MMI中的全局变量PhoneBook[]与L4中的电话簿已经同步了;
(3)g_phb_name_index[]中按照字母的大小顺序,存储了每一个entry在PhoneBook[]中的存储位置;
(4)所有的号码,包括SIM卡,NVRAM,移动电话,家庭,公司,传真号码,都按照大小顺序,存储在LookUpTable[]中了,并且存储在PhoneBook中的存储位置索引。 二、增加一个entry
//这是菜单的初始化函数 voidmmi_phb_init(void) { mmi_phb_search_init(); mmi_phb_operate_single_init(); mmi_phb_operate_mass_init(); mmi_phb_caller_group_init(); mmi_phb_extra_number_init(); mmi_phb_setting_init(); PhbInitSpeedDial(); mmi_phb_stubs_to_others_init(); }
mmi_phb_highlight_op_add_entry() memset(pbNumber,0,ENCODING_LENGTH); g_phb_cntx.set_done_flag=0;
按下左软件,进入:
mmi_phb_op_add_pre_entry() 判断是否已经存储满了? mmi_phb_util_clear_buffer()//清除一些全局变量 mmi_phb_entry_op_add_choose_storage()选择存储位置:SIM,phone ShowCategory52Screen()//根据g_phb_cntx.prefer_storage来判断当前应该默认那个高亮
PHONE,高亮:
mmi_phb_highlight_op_add_entry_to_phone() g_phb_cntx.selected_storage=MMI_NVRAM;
SIM高亮:
mmi_phb_highlight_op_add_entry_to_sim() g_phb_cntx.selected_storage=MMI_SIM;
按下左软件,SHOW的画面是(全部栏位): Name 姓名 Number 电话号码 HomeNumber 家庭电话 CompanyName 公司名称 EmailAddress 电子信箱 OfficeNumber 公司号码 FaxNumber 传真号码 None 无(生日) None 无(大头贴)g_phb_cntx.image_name_list(名称),g_phb_cntx.image_id_list(图片的ID) None 无(来电录像)g_phb_cntx.video_name_list(名称),g_phb_cntx.video_id_list(录像ID) None 无(来电铃声)g_phb_cntx.ring_tone_name_list(名称),g_phb_cntx.ring_tone_list(铃声ID) None 无(用户群组)myCallerGrpnames
无论选择了哪个存储,都进入: mmi_phb_entry_op_add_entry() if(g_phb_cntx.selected_storage==MMI_SIM) { g_phbnameLength=g_phb_cntx.sim_name_len; g_phbnumberLength=MAX_PB_SIM_NUMBER_LENGTH;//20 } else { g_phbnameLength=MAX_PB_NAME_LENGTH; g_phbnumberLength=MAX_PB_NUMBER_LENGTH; //40 } 很多的初始化操作mmi_phb_op_fill_inline_item() InitializeCategory57Screen(); ShowCategory57Screen
高亮响应:mmi_phb_op_edit_highlight_hdlr()
按下保存键,进入:
mmi_phb_entry_op_add_entry_confirm() mmi_phb_op_add_pre_save() if(!mmi_phb_op_check_pre_save()) //check输入是否正确:姓名号码是否为空pbName,pbNumber,pbHomeNumber,pbOfficeNumber,pbFaxNumber { return; } mmi_phb_op_add_entry_req() //发送消息到L4保存entry mmi_phb_show_in_progress() //显示消息:正在处理 mmi_phb_op_set_entry_prepare_name_number(&myMsgPtr->list,pbName,pbNumber); //装载姓名和号码,没有装载optionalfieldsandIDs。 发送消息:PRT_PHB_SET_ENTRY_REQ SetProtocolEventHandler(mmi_phb_op_add_entry_rsp,PRT_PHB_SET_ENTRY_RSP);
返回消息后,进入CBACK函数: mmi_phb_op_add_entry_rsp() { if(localPtr->result.flag==0)//存储成功 { store_index=mmi_phb_op_get_store_index_and_increase_counter(localPtr->list[0].storage,localPtr->list[0].record_index); //record_index是entry的物理存储位置,从1开始。 //store_index是entry在数组PhoneBook中的存储位置,从0开始。 if(localPtr->list[0].storage==MMI_NVRAM) //存储在NVRAM { mmi_phb_op_update_optional_field(store_index,MMI_NVRAM,1); //保存optionalfieldtoNVRAM //把用户输入的信息拷贝到中PhoneBookOptionalFields UnicodeToAnsii((PS8)PhoneBookOptionalFields.homeNumber,pbHomeNumber); pfnUnicodeStrcpy((PS8)PhoneBookOptionalFields.companyName,pbCompanyName); UnicodeToAnsii((PS8)PhoneBookOptionalFields.emailAddress,pbEmailAddress); UnicodeToAnsii((PS8)PhoneBookOptionalFields.officeNumber,pbOfficeNumber);
UnicodeToAnsii((PS8)PhoneBookOptionalFields.faxNumber,pbFaxNumber); //写入到NVRAM。可见:在NVRAM中,也是按照store_index的顺序存储的,与PhoneBook一样。不过是从1开始。 WriteRecord(NVRAM_EF_PHB_FIELDS_LID,(U16)(store_index+1),(void*)&PhoneBookOptionalFields, OPTIONAL_FIELDS_RECORD_SIZE, &pError); //根据store_index来读取这个entry的optionalIDS. optid_record=(store_index/OPTIONAL_IDS_RECORD_TOTAL)+1; optid_index=store_index-(optid_record-1)*OPTIONAL_IDS_RECORD_TOTAL; ReadRecord(NVRAM_EF_PHB_IDS_LID,optid_record,(void*)PhbOptIDs,OPTIONAL_IDS_RECORD_SIZE,&pError); 把g_phb_cntx.image_id_list,
g_phb_cntx.selected_grp_index,g_phb_cntx.ring_tone_list信息拷贝到刚刚读取出来的PhbOptIDs中。 然后再写入NVRAM中 WriteRecord(NVRAM_EF_PHB_IDS_LID,optid_record,PhbOptIDs,OPTIONAL_IDS_RECORD_SIZE,&pError); mmi_phb_op_increase_lookup_table(); //把家庭,公司,传真号码加入到数组LookUpTable[]中。 mmi_phb_video_update_by_index(store_index); //保存来电的video到NVRAM中。 UnicodeToAnsii((PS8)num_ascii,(PS8)pbNumber); flag+=mmi_phb_op_increase_lookup_table(store_index,(S8*)num_ascii,NULL,NULL,NULL); //把电话加入LookUpTable[]中。 mmi_phb_lookup_table_sort() ;//对数组LookUpTable[]按照号码大小顺序排序 mmi_phb_op_set_entry_rsp_name_number(&localPtr->list[0],store_index); //把姓名和号码保存在PhoneBook[store_index]中。 mmi_phb_op_update_field_flag();//updatefileterflagofeachentry.
mmi_phb_bday_update_field();//保存生日信息 ReadRecord(NVRAM_EF_PHB_BIRTHDAY_LID,bday_record,(void*)bday_data,NVRAM_EF_PHB_BIRTHDAY_SIZE,&pError); 拷贝pbYear,pbMon,pbDay到bday_data中; WriteRecord(NVRAM_EF_PHB_BIRTHDAY_LID,bday_record,(void*)bday_data,NVRAM_EF_PHB_BIRTHDAY_SIZE,&pError); mmi_phb_util_make_pinyin_cache(store_index); //把
PhoneBook[store_index]中姓名的拼音加入到g_phb_name_pinyin_index[store_index]中。 /*Insertnametonamemappingtable.*/ mmi_phb_sort_insert_name_index(store_index); //如果是从CALLLOG中来保存一个entry,那么就更新这个calllog ReqUpdateCallLogName(PhoneBook[store_index].alpha_id.name_length,PhoneBook[store_index].alpha_id.name_dcs, PhoneBook[store_index].alpha_id.name); mmi_phb_clear_old_add_history(); //删除历史screen } } else //存储失败 { 提示错误信息; 删除历史screen; } g_phb_enter_from=MMI_PHB_ENTER_NONE; g_phb_cntx.current_op=MMI_PHB_OP_NONE; }
三、电话列表 PhoneBook 3.ViewPhonebook 分类查看 1.ViewSIM SIM卡 MITEM111_PBOOK_VIEW_SIM_ENTRY
2.ViewPhone 本机 MITEM111_PBOOK_VIEW_PHONE_ENTRY 1.SIM卡
mmi_phb_highlight_view_sim() mmi_phb_view_sim() g_edit_listview =MMI_PHB_LIST_FOR_SIM;//每次进入phoneentrylistview时,都要设置这个变量。 检查电话簿已经读取完毕,并且此刻没有电话簿的操作,SIM卡有号码 mmi_phb_entry_list2(g_phb_cntx.sim_used,/*TotalEntry*/ STR_PHB_VIEW,/*TitleString*/ IMG_SCR_PBOOK_CAPTION,/*TitleImage*/ STR_GLOBAL_OPTIONS,/*LSK*/ IMG_GLOBAL_OPTIONS,/*LSK*/ #ifdefined(__MMI_INTELLIGENT_CALL_ALERT__) mmi_phb_get_index_speak_name_sim, #else mmi_phb_get_index_sim,//mmi_phb_get_index,/*HighlightCallback*/ #endif mmi_phb_entry_op_option_sim,/*LSKCallback*/ mmi_phb_choose_number_normal,/*SENDKeyCallback*/ mmi_phb_list_get_item_sim,//mmi_phb_list_get_item,/*ListCallback*/ mmi_phb_list_get_hint_sim,//mmi_phb_list_get_hint,/*HintCallback*/ mmi_phb_view_sim,/*Re-EntryCallback*/ TRUE,/*AlphaIndex*/ TRUE); /*RightArrowKey*/ 详细看上面注册的函数: (1)高亮:mmi_phb_get_index_sim() 设置:g_phb_cntx.active_index。注意:g_phb_cntx.active_index是在g_phb_name_index[]数组中的位置。0,1,2,3,4…。即:当前高亮的entry在数组: g_phb_name_index[]中的顺序位置。
(2)左软件响应mmi_phb_entry_op_option_sim() ShowCategory15Screen()每一个entry的选项菜单 (3)SEND键响应mmi_phb_choose_number_normal() mmi_phb_list_pre_choose_number()//当该entry有多个号码时,让用户选择拨哪个 mmi_phb_entry_list_choose_number() (4)获取SIM卡item:mmi_phb_list_get_item_sim() 获取SIM卡中entry的姓名。没有姓名的就获取号码 (5)hintcallback:mmi_phb_list_get_hint_sim() 获取hint信息:号码
mmi_phb_entry_list2() mmi_phb_list_build_alpha_index() //用户快捷方式。按照g_phb_name_index[]中保存的字母顺序,提取PhoneBook中的姓名,按照首字母的顺序以字母(26个)为索 引,把每个entry在电话列表中的listindex保存在g_phb_alpha_index_list[]中。即:g_phb_alpha_index_list[]中保存的是该entry的listindex。这样,当用户输入某个字 母时,如:c,那么就可以直接跳转到g_phb_alpha_index_list[2]的值所指示的位置。 ShowCategory184Screen() ShowCategory185Screen() init_dynamic_item_buffer() dynamic_item_buffer.load_func=get_item_func; dynamic_item_buffer.hint_func=get_hint_func; load_dynamic_item_buffer() for(i=0;i if(alpha_index) //快捷方式所需要的设置。其他地方如果需要这样处理的可以参考。比如:在gap205的区号查询中。 { register_multitap_no_draw_key_handlers(); set_multitap_functions(mmi_phb_list_alpha_index,mmi_phb_list_alpha_index_input_callback); change_multitap_mode(0); } 小结:在show电话号码列表时,也就是SHOW动态的LIST。过程是:从 g_phb_name_index[]中取出每个entry在PhoneBook[]中的store_index,然后获取PhoneBook[]中的姓名,转载subMenuData[],最后拷贝到MMI_fixed_icontext_menuitems[]中。 MTK-callhistoryinitialize 资源加载过程 InitializeAll() PopulateResData() PopulateCallHistoryRes() AddCallLogApplicationRes(); 未接电话,已拨电话,已接电话。 PopulateResetCallRes(); 删除通话记录 AddSMSCounterApplicationRes(); 短信计数器 PopulateCallTimes(); 通话时间 PopulateCallCost(); 通话cost #ifdef__MMI_GPRS_FEATURES__ AddGPRSCounterApplicationRes();GPRS计数器 #endif 系统初始化过程 InitializeAll() InitCallLogs() SetProtocolEventHandler(ReadyLogIndication,PRT_MMI_PHB_LAST_NUMBER_READY_IND); SetHintHandler(….) 设置MENU的hilite和hint响应。注意:这里只设置了前3个MENU:未接电话,已拨电话,已接电话中,涉及到的MENU的响应。 … InitCallHistoryContext(); //初始化全局变量 memset((U8*)chis_p,0,sizeof(call_history_context_struct)); ReadRecord(NVRAM_EF_CALL_TIME_LID,1,(void*)&chis_p->last_call_time,sizeof(MYTIME),&error); ReadRecord(NVRAM_EF_CALL_TIME_LID,2,(void*)&chis_p->total_out_time,sizeof(MYTIME),&error); ReadRecord(NVRAM_EF_CALL_TIME_LID,3,(void*)&chis_p->total_in_time,sizeof(MYTIME),&error); InitAllApplications() InitCallCost(); //设置callcost中MENU的hiliteandhint响应 InitCallHistory(); InitCallsReset(); //[删除通话记录]中MENU的响应 InitSMSCounter(); //[短信计数器]中MENU的响应 InitCallTimes(); //[通话时间]中MENU的响应 InitGPRSCounter(); //[GPRS计数器]中MENU的响应 启动过程: 上电后,当PS的calllog准备好之后,发送消息: PRT_MMI_PHB_LAST_NUMBER_READY_IND给MMI,进入CBack函数: ReadyLogIndication() chis_p->isCallLogReady=TRUE; chis_p->isFirstTime=TRUE; chis_p->sequenceId=0; mmi_chist_init_get_data_from_nvram();读取 missedcallflag:g_chist_have_missed_call(0—nomissedcall,1—yesmissedcall)。NVRAM_CHIST_HAVE_MISSED_CALL。 if(g_chist_have_missed_call==1) IdleSetStatusIcon(STATUS_ICON_MISSED_CALL); else HideStatusIcon(STATUS_ICON_MISSED_CALL); ReqReadDialedNum(); 开始读取calllogs return; ReqReadDialedNum() #ifndef__MMI_CH_MIXED_CALL_LOG__ chis_p->dialedCalls=(LOG_CALL*)chis_p->callsLog; //chis_p->callsLog[]是实际存储的位置,即如果不支持mixedcalllog,那么在分别进入3中类型的calllogs #endif //时,获取的calllog都存储在chis_p->callsLog[]中。然后把3个指针 之一指向这里。 设置消息PRT_MMI_PHB_GET_LAST_NUMBER_REQ的一些参数 SetProtocolEventHandler(RspReadDialedNum,PRT_MMI_PHB_GET_LAST_NUMBER_RSP); OslMsgSendExtQueue(&Message); L4返回消息:PRT_MMI_PHB_GET_LAST_NUMBER_RSP,进入: RspReadDialedNum() rsp=(GET_LAST_NUMBER_RSP*)info; if(chis_p->sequenceId==1) //第一次读取,先清空缓冲区 { chis_p->nDialedCalls=0; memset((PS8)chis_p->dialedCalls,0,sizeof(LOG_CALL)*TOT_SIZE_OF_ONE_LN_LIST); } for(index=0;index AnsiiToUnicodeString((S8*)logCall->pbName,(S8*)phbLastNumber->alpha_id.name); 2.获取号码。PS中保存的号码是ASCII码 if(phbLastNumber->tel.type&0x10) { logCall->number[0]='+'; AnsiiToUnicodeString((PS8)(logCall->number+2),(PS8)phbLastNumber->tel.number); } else { AnsiiToUnicodeString((PS8)logCall->number,(PS8)phbLastNumber->tel.number); } 3.starttime: ConvertRTC2MYTIME(&logCall->startTime,&phbLastNumber->time); 4.duration: mmi_dt_utc_sec_2_mytime(phbLastNumber->call_duration,&logCall->duration,MMI_FALSE); 5.counters:logCall->no_of_times=phbLastNumber->count; } chis_p->nDialedCalls++; } if(rsp->more_data&&rsp->no_list==TOT_SIZE_OF_ONE_LN_LIST) 没有读取完,再次读取 { chis_p->sequenceId++; ASSERT(chis_p->sequenceId<11); ReqReadDialedNum(); return; } chis_p->sequenceId=0; 所有dialedcall全部提取完毕 if(chis_p->isFirstTime==TRUE) //表示这是在初始化时第一次读取,需要把所有的dialed,missed,receivedcalllog全部读取出来。 { ReqReadMissedNum(); return; } //如果不是初始化时读取的,就进入这里,即:dialedcalllist chis_p->isReqSent=FALSE; EntryCHISTViewDialedCallList(); 此时,由于我们是初始化时第一次读取calllog,因此要一次性读取所有的calllog,进入红色部分的if中去,即继续读取missedcalllog: ReqReadMissedNum() chis_p->missedCalls=(LOG_CALL*)chis_p->callsLog; 共用一个存储空间 消息:PRT_MMI_PHB_GET_LAST_NUMBER_REQ SetProtocolEventHandler(RspReadMissedNum,PRT_MMI_PHB_GET_LAST_NUMBER_RSP); OslMsgSendExtQueue(&Message); return; PS返回消息PRT_MMI_PHB_GET_LAST_NUMBER_RSP,进入: RspReadMissedNum() if(chis_p->sequenceId==1) 第一匹读取 { chis_p->nMissedCalls=0; memset((PS8)chis_p->missedCalls,0,sizeof(LOG_CALL)*TOT_SIZE_OF_ONE_LN_LIST); } for(index=0;index { CHISTExtractPSCallLog(&chis_p->missedCalls[chis_p->nMissedCalls],&rsp->list[index]); chis_p->nMissedCalls++; } if(rsp->more_data&&rsp->no_list==TOT_SIZE_OF_ONE_LN_LIST) 判断是否读取完毕 { chis_p->sequenceId++; ASSERT(chis_p->sequenceId<11); ReqReadMissedNum(); return; } chis_p->sequenceId=0; 读取完毕 if(chis_p->isFirstTime==TRUE) 如果是初始化的话,继续读取receivedcalllog { ReqReadRecvdNum(); return; } chis_p->isReqSent=FALSE; 如果不是初始化,就进入missedcallloglist EntryCHISTViewMissedCallList(); 继续读取receivedcalllog ReqReadRecvdNum() chis_p->recvdCalls=(LOG_CALL*)chis_p->callsLog; 共用一个存储空间 SetProtocolEventHandler(RspReadRecvdNum,PRT_MMI_PHB_GET_LAST_NUMBER_RSP); OslMsgSendExtQueue(&Message); return; PS返回消息:PRT_MMI_PHB_GET_LAST_NUMBER_RSP,进入: RspReadRecvdNum() if(chis_p->sequenceId==1) 初始化变量 { chis_p->nRecvdCalls=0; memset((PS8)chis_p->recvdCalls,0,sizeof(LOG_CALL)*TOT_SIZE_OF_ONE_LN_LIST); } for(index=0;index
正在阅读:
MTK平台相关资料05-04
写给医生的感谢信范文02-08
中学教育知识与能力练习题06-13
过新年作文450字07-14
初二物理14.10.3103-18
一级B选择题及答案11-25
关于意识形态领域突出问题“大摸底、大整改、大督查”活动实施方案11-15
12课题申报表06-02
平凉市中考数学试卷06-11
- 高一物理牛顿运动定律全套学习学案
- 水处理一级反渗透加还原剂亚硫酸氢钠后为什么ORP会升高
- 毕业设计(论文)-正文董家口 - 图文
- 荣盛酒店经营管理公司录用通知及入职承诺书II
- 第二讲 大学英语四级快速阅读技巧
- 质量管理体系文件(2015年委托第三方医药物流配送企业专用版本)
- 214071收款办法
- 苏轼对《文选》选文的评价
- 《诊断学基础B》1-8作业
- 广东省东莞市高一数学下学期期末教学质量检查试题
- 海南电网公司VIS推广应用管理办法
- 红星照耀中国习题
- 苏教版小学语文六年级上册期末复习资料之生字词整理
- 局域网组建与应用—王向东
- 税务稽查内部管理文书样式
- 环保社会实践调查表
- 九年级思品第一单元复习
- 2016年全国注册咨询工程师继续教育公路路线设计规范试卷
- 毕业设计-青岛港董家口港区防波堤设计
- 撞背锻炼方法与益处
- 相关
- 资料
- 平台
- MTK
- 2007年度国家精品课程申报表(高职高专) - 图文
- 管理
- 智能医院护理呼叫系统的设计
- 德国留学生回国找工作简历中个人爱好特长有哪些
- 易忘易错易混点梳理
- 教学考核教学设计与教案撰写(教育学部陈本友)
- 超声波测距应用
- 冲压工艺期末试题
- 2011江苏会计从业资格考试会计基础模式试卷试题及答案
- 高中数学课课练5.答案
- 生命科学 ~ 〝世间莫若修行好,天下无如吃饭难〞
- 小学奥数第22讲 数字串问题(含解题思路)
- 塑胶花项目可行性研究报告(发改立项备案+2013年最新案例范文)详
- 妇科腹腔镜手术后护理论文
- 教科版五年级上册综合实践教案
- Oracle数据库管理-实验指导
- 航运业碳排放研究报告 - 图文
- 湖南商学院勤工助学指导中心简介
- 三上劳技教案
- 苏教版语文一年级下册第一单元《识字1》教材分析及教学