8226175 发表于 2006-12-14 13:39:53

ELF 程序开发教程及技术讨论专贴

本贴只允许技术讨论存在,凡是无关回帖,版主保留删贴、扣分及解释的权力。
注:以下文章的内容,节选翻译自http://forum.siemens-club.org/上的 how to make elf 一文。

西门子x65/x75上的 ELF 程序大家已经见识过了,你有没想过写出自己的 ELF 程序呢?如果你有C语言基础,那么加入 ELF 程序开发的队伍吧。
要在西门子x65/x75上使用 ELF 程序,你应该确定自己的机器上正确的刷了适合你机型的3个补丁(如下):
function library
elfloader
swi-hook
查看机型在待机下输入 *#06# 选更多,sW-Version一行就是了
现在的 ELF 程序一般是被刷过以上3个补丁的正确版本的机器所通用的(也有可能会限制机型,看程序怎么写的了8-) )
下面进入正题

目录:
1.IAR SI 安装
2.在手机上运行 ELF 程序
3.如何用 IAR 编写 ELF
4.例1:内存和文件的操作
5.例2:屏幕输出和键盘控制
6.例3:一个后台计时的小程序
7.例4:内存驻留程序
8.FAQ

1.IAR SI 安装
从 www.iar.com 上下载 IAR Embedded WorkbenchFor ARM 的30天试用版,最新版为4.41好象(>100 mb),程序下载是免费的,但是会要你先注册。填写正确的油箱以后,就会把使用序列号发给你。安装没说的了吧,一路下一步,下一步,等等。

2.在手机上运行 ELF 程序
论坛上很多说明了,再扯就远了点:-')

3.如何用 IAR 编写 ELF
开始一个 ELF 程序的编写,还是比较简单 :P
在菜单上选择 “Project->Create New Project”
然后选添加"Project->Add Files"把你用其他IDE写好的C程序添加进来就可以了
工程必须还要有 func.asm (入口点) 和 div.r79 (这个好象莫必要?我也不太清楚,我是业余的:( )
C程序知道怎么写,问题就不大。
你可能会问,怎么使用到手机里面那些需要的功能函数呢?这就需要 swilib.h 这个头文件了(附件提供),这里面定义了n多函数,大家看名字猜吧。。。因为没说明,灭办法,唉。
上面的操作做好以后,就可以编译我们的程序了,在 IAR 环境里左边的 Workspace 下面,把 Debug 选成 Release,然后在工程上点右键,选属性 CPU 可以不用改,下面的 Processor mode 改为 Arm,在 Library Configuration 标签里,把 Library 选成 None,就可以编译了。这里你也可以在 Linker 里面设置相关连接选项。生成完毕后,你就可以在 你的工程\Release\Exe 目录里找到生成的 ELF 文件,放到手机里看看呢?:P

4.例1:内存和文件的操作
创建 main.c 如下后添加到你的工程里:

//main.c
#include "swilib.h"
void ElfKiller(void) { //用于 elf 退出时的相关操作
    extern void *ELF_BEGIN;
    //这里一般使用 mfree(), freeWS() 来释放内存
    ((void (*)(void *))(mfree_adr()))(&ELF_BEGIN); // 懒得解释 :(
}
int main(char *exename, char *fname) { //主函数
//参数 exename 表示被动使用的ELF? 格式 4:\Zbin\xyz.elf
//参数 fname 传递文件名, 格式 0:\Misc\data.txt
//如果 ELF 启动自身则为 0
    char *mem;
    int i, err;
    int handle;
    if (fname) {
      //操作标准文件:
      handle = fopen(fname, A_ReadWrite+A_BIN+A_Append+A_Create, P_READ+P_WRITE, &err);
      //表示按记录文件打开,数据添加到文件末尾,如果文件不存在则创建之
      //如果为 handle=fopen (fname,A_ReadOnly+A_BIN, 0,&err);
      //则表示按只读方式打开文件,具体常数参看 swilib.h
      if (handle != -1) { //-1 = error
            mem = malloc(10000); //分配内存: AllocWS() 按行分配 (2b)
            if (mem != 0) { //0 = error
                i = fread(handle, mem, 10000, &err); //返回读取得字节数,如果错误返回 error。
                //放置你的代码在这里 makesomebody (mem,i);
                fwrite(handle, mem, i, &err);
                mfree(mem); //释放内存: FreeWS() 按行释放
            }
            fclose(handle); //关闭文件
      }
    }
    SUBPROC((void *)ElfKiller); //放这个东西在这里就最好了,不存在也没关系!
    return(0);
}
//PS. 由于 x65 中文件的读取和记录是按 32767 字节的块操作的,
//因此将 fread() 和 fwrite() 改造为 fread32 () 和 fwrite32()
int fread32(int fh, char *buf, int len, unsigned int *err) { // (c) Rst7
    int clen;
    int rlen;
    int total=0;
    while (len) {
      if (len > 16384) clen = 16384; else clen = len;
      total += (rlen = fread(fh, buf, clen, err));
      if (rlen != clen) break;
      buf += rlen;
      len -= clen;
    }
    return(total);
}

最后不要忘了还有 func.asm 这个文件:
;Func.asm
    PUBLIC ELF_BEGIN
    RSEG ELFBEGIN:DATA
ELF_BEGIN
defadr MACRO a,b
   PUBLIC a
a EQU b
   ENDM
   END

5.例2:屏幕输出和键盘控制
通过导航键控制屏幕上的符号移动,长按红键退出。本例子基于 TED- A (c) Of rst7
看本例时最好从下往上看:)

创建 main.c 如下后添加到你的工程里:

//main.c
//屏幕和键盘处理
#include "swilib.h"
typedef struct {
    GUI gui;
    //WSHDR *ws1;
    //WSHDR *ws2;
    //int i1;
} MAIN_GUI;
typedef struct {
    CSM_RAM csm;
    int gui_id;
} MAIN_CSM;
const int minus11 = -11;
const unsigned int INK = 0;
const unsigned int PAPER = 1;
volatile int xx = 0, yy = 0; //绘图坐标
const char bmp = {0xFC, 0x86, 0xB3, 0xA9, 0xB1, 0xA9, 0x81, 0xFF, 0, 0, 0, 0};
const IMGHDR img = {8, 12, 0x1, 0, (char *)bmp};
//============
//屏幕输出
//============
void DrwImg(IMGHDR *img, int x, int y, int *pen, int *brush){
    RECT rc;
    DRWOBJ drwobj;
    StoreXYWHtoRECT(&rc, x, y, img->w, img->h);
    SetPropTo_Obj5(&drwobj, &rc, 0, img);
    SetColor(&drwobj, pen, brush);
    DrawObject(&drwobj);
}
void DrawScreen(void) {
    int *ink = GetPaletteAdrByColorIndex(INK);
    int *paper = GetPaletteAdrByColorIndex(PAPER);
    int x = xx;
    DrwImg((IMGHDR *)&img, x, yy, ink, paper);
}
//绘制屏幕
void method0(MAIN_GUI *data) {
    DrawScreen();
}
void method1(MAIN_GUI *data, void *(*malloc_adr)(int)) {}
void method2(MAIN_GUI *data, void (*mfree_adr)(void *)) {}
void method3(MAIN_GUI *data, void *(*malloc_adr)(int), void (*mfree_adr)(void *)) {}
void method4(MAIN_GUI *data, void (*mfree_adr)(void *)) {}
void method7(MAIN_GUI *data, void (*mfree_adr)(void *)) {}
int method8(void) {return(0);}
int method9(void) {return(0);}
//============
//按键控制
//============
int method5 (MAIN_GUI *data, GUI_MSG *msg) {
    //if (msg->gbsmsg->msg==KEY_UP) //释放按键时
    if ((msg->gbsmsg->msg == KEY_DOWN) || (msg->gbsmsg->msg == LONG_PRESS)) //按下键或者长按键时
      switch(msg->gbsmsg->submess) {
      case RED_BUTTON:
            return(1); //发生 generalFunc 流调用 GUI - > 关闭 GUI
      case UP_BUTTON:
            if (yy > 0) --yy; break;
      case LEFT_BUTTON:
            if (xx > 0) --xx; break;
      case DOWN_BUTTON:
            if (yy < 130) ++yy; break;
      case RIGHT_BUTTON:
            if ( xx < 120) ++xx; break;
      //case GREEN_BUTTON:
      //case RIGHT_SOFT:
      //case ENTER_BUTTON:
      //case LEFT_SOFT:
      //case VOL_UP_BUTTON:
      //case VOL_DOWN_BUTTON:
      //case '0':
      //case '9':
      //case '#':
      //SUBPROC((void *)DoDiskAccess,1);
      //降低其他处理的优先级以绘制窗口
      }
    DrawScreen();
    return(0);
}
const void *const gui_methods = {
    (void *)method0, //Redraw
    (void *)method1, //Create
    (void *)method2, //Close
    (void *)method3, //Focus
    (void *)method4, //Unfocus
    (void *)method5, //OnKey
    0,
    (void *)method7, //Destroy
    (void *)method8,
    (void *)method9,
    0
};
const RECT Canvas={0,0,131,175};
void maincsm_oncreate(CSM_RAM *data) {
    MAIN_GUI *main_gui = malloc(sizeof (MAIN_GUI));
    MAIN_CSM *csm = (MAIN_CSM *)data;
    zeromem(main_gui, sizeof (MAIN_GUI));
    //ustk=malloc(STKSZ); //为程序分配内存
    //info_ws=AllocWS(512);
    main_gui->gui.canvas = (void *)(&Canvas);
    main_gui->gui.flag30 = 2;
    main_gui->gui.methods = (void *)gui_methods; //基本方法(见上面)
    main_gui->gui.item_ll.data_mfree = (void (*)(void *))mfree_adr(); //我也不清楚:(
    csm->csm.state = 0;
    csm->csm.unk1 = 0;
    csm->gui_id = CreateGUI(main_gui); //直接创建 GUI
}
void Killer(void) { //退出程序
    extern void *ELF_BEGIN;
    //mfree(ustk); //释放内存
    //FreeWS(info_ws);
    ((void (*)(void *))(mfree_adr()))(&ELF_BEGIN);
}
void maincsm_onclose(CSM_RAM *csm) {
    //GBS_StopTimer(&light_tmr);
    SUBPROC((void *)Killer);
}
int maincsm_onmessage(CSM_RAM *data, GBS_MSG *msg) {
    return(1);
}
unsigned short maincsm_name_body;
const struct {
    CSM_DESC maincsm;
    WSHDR maincsm_name;
} MAINCSM = {
                {
                  maincsm_onmessage, //信息进程
                  maincsm_oncreate, //创建时调用的方法
                  //如果机型为 S75 移除以下4行
                  //并在 swilib.h 里取消对 #define NEWSGOLD 这行的注释
                  //0,
                  //0,
                  //0,
                  //0,
                  maincsm_onclose, //关闭时调用的方法
                  sizeof (MAIN_CSM),
                  1,
                  &minus11
                },
                {
                  maincsm_name_body,
                  NAMECSM_MAGIC1,
                  NAMECSM_MAGIC2,
                  0x0,
                  139
                }
            };
int main(char *exename, char *fname) {
    char dummy;
    //strcpy(filename,fname); //保存数据到文件
    CreateCSM(&MAINCSM.maincsm, dummy, 0);
    return 0;
}


6.例3:一个后台计时的小程序
创建 siemens.c如下后添加到你的工程里:

//Siemens.c 0.1
//外部函数:
extern int onstart(char *exename, char *fname); //程序启动事件, 返回 0 或 1
extern void oncreate(); //创建窗口事件
extern void onclose(); //关闭窗口事件
extern void onexit(); //退出程序事件
extern void onredraw(void); //屏幕重绘事件
extern int onkey(unsigned char keycode, int pressed); //按键事件, 返回 0 或 1
//如果机型不是 S75 在 swilib.h 中注释 #define NEWSGOLD 这行
#include "swilib.h"
//下面这行分配 16 位的颜色代码(RGB 565 屏幕上每个点占用 2 个字节的颜色数据)
//获取 8 位的颜色代码(RGB 232 每个点占用 1 个字节)
#define HIGHCOLOR
#ifdef HIGHCOLOR
    short screen;
    const int screensize = 132 * 176 * sizeof (short);
    const IMGHDR img = {(unsigned) 132, (unsigned) 176, 8, 0, (char *)screen};
#else
    char screen;
    const int screensize = 132 * 176 * sizeof (char);
    const IMGHDR img = {(unsigned) 132, (unsigned) 176, 5, 0, (char *)screen};
#endif
//不用先看后面的内容了! :)
typedef struct {
    GUI gui;
    WSHDR *ws1;
    WSHDR *ws2;
    int i1;
} MAIN_GUI;
typedef struct {
    CSM_RAM csm;
    int gui_id;
} MAIN_CSM;
void DrawScreen() {
    RECT rc; DRWOBJ drwobj;
    StoreXYWHtoRECT(&rc, 0, 0, img.w, img.h);
    SetPropTo_Obj5(&drwobj, &rc, 0, (IMGHDR*)&img);
    SetColor(&drwobj, GetPaletteAdrByColorIndex(0), GetPaletteAdrByColorIndex(1));
    DrawObject(&drwobj);
}
void method0(MAIN_GUI *data) {onredraw(); DrawScreen();}
void method1(MAIN_GUI *data, void *(*malloc_adr)(int)) {oncreate(); data->gui.state = 1;}
void method2(MAIN_GUI *data, void (*mfree_adr)(void *)) { data->gui.state = 0;}
void method3(MAIN_GUI *data, void *(*malloc_adr)(int), void (*mfree_adr)(void *)) {data->gui.state = 2;}
void method4(MAIN_GUI *data, void (*mfree_adr)(void *)) {if (data->gui.state != 2) return; data->gui.state = 1;}
int method5(MAIN_GUI *data, GUI_MSG *msg) {
    return onkey(msg->gbsmsg->submess, msg->gbsmsg->msg);}
void method7(MAIN_GUI *data, void (*mfree_adr)(void *)) {}// mfree_adr(data);
int method8(void) {return(0);} // Empty f-th
int method9(void) {return(0);} // Empty f-th
const void * const gui_methods = {
    (void *)method0, //重绘
    (void *)method1, //创建
    (void *)method2, //关闭
    (void *)method3, //获取焦点
    (void *)method4, //失去焦点
    (void *)method5, //按键
    0,
    (void *)method7, //析构
    (void *)method8,
    (void *)method9,
    0
};
const RECT Canvas = {0, 0, 131, 175};
void maincsm_oncreate(CSM_RAM *data) {
    MAIN_GUI *main_gui=malloc(sizeof (MAIN_GUI));
    MAIN_CSM *csm = (MAIN_CSM *)data;
    zeromem(main_gui, sizeof (MAIN_GUI));
    //ustk=malloc(STKSZ); //分配内存
    //info_ws=AllocWS(512);
    main_gui->gui.canvas = (void *)(&Canvas);
    main_gui->gui.flag30 = 2;
    main_gui->gui.methods = (void *)gui_methods;
    main_gui->gui.item_ll.data_mfree = (void (*)(void *))mfree_adr();
    csm->csm.state = 0;
    csm->csm.unk1 = 0;
    csm->gui_id = CreateGUI(main_gui);
}
void Killer(void) {
    extern void *ELF_BEGIN;
    extern void kill_data(void *p, void (*func_p)(void *));
    onexit();
    kill_data(&ELF_BEGIN, (void (*)(void *))mfree_adr());
    //((void (*)(void *))(mfree_adr()))(&ELF_BEGIN);
}
void maincsm_onclose(CSM_RAM *csm) {
    onclose();
    SUBPROC((void *)Killer);
}
int maincsm_onmessage(CSM_RAM *data, GBS_MSG *msg) {
    MAIN_CSM *csm = (MAIN_CSM *)data;
    if ((msg->msg == MSG_GUI_DESTROYED) && ((int) msg->data0 == csm->gui_id))
      csm->csm.state = -3;
    return(1);
}
const int minus11 = -11;
unsigned short maincsm_name_body;
const struct {
    CSM_DESC maincsm;
    WSHDR maincsm_name;
} MAINCSM = {
                {
                  maincsm_onmessage,
                  maincsm_oncreate,
                  #ifdef NEWSGOLD
                        0,
                        0,
                        0,
                        0,
                  #endif
                  maincsm_onclose,
                  sizeof(MAIN_CSM),
                  1,
                  &minus11
                },
                {
                  maincsm_name_body,
                  NAMECSM_MAGIC1,
                  NAMECSM_MAGIC2,
                  0x0,
                  139
                }
            };
int main(char *exename, char *fname) {
    char dummy;
    if (onstart(exename, fname)) SUBPROC((void *)Killer);
    else CreateCSM(&MAINCSM.maincsm, dummy, 0);
    return 0;
}

然后是 main.c 文件:

//Main.c 0.1
//例 3: 一个后台计时的小程序
#include "swilib.h"
extern short screen; //分辨率 132*176*2
extern void DrawScreen(); //屏幕绘制函数
void onredraw(void);
//#define RGB8(R,G,B) (B + (G << 2) + (R << 5))
#define RGB16(R,G,B) ((B > 31 ? 31 : B) + ((G > 63 ? 63 : G) << 5) + ((R > 31 ? 31 : R) << 11))
char *buf = 0; //缓存(这里顺便作为分配内存的演示)
int bufsize = 10000; //缓存大小
volatile int started = 0; //程序结束标志, 为 0 时退出
int color = 0;
GBSTMR timer;
void timer_proc(void) { //每秒运行10次
    if (started) {
      REDRAW(); //重绘屏幕
    }
    GBS_StartTimerProc(&timer, 262 / 10, timer_proc); //开启计时器,计时频率为每秒10次
    //执行一次后就会按频率持续执行
}
void execute() { //后台处理
    started = 1;
    while (started) { //本例中没有设置停止控制,但在实际应用时,应该设置
      onredraw(); //程序启动事件, 返回 0 或 1
    }
}
int onstart(char *exename, char *fname) { //程序启动事件, 返回 0 或 1
    //if (!fname) return 1; //分配文件失败时退出
    buf = (char *)malloc(bufsize); //分配内存
    if (!buf) return 1; //分配内存失败时退出
    //这里写你的处理代码
    return 0;
}
void oncreate() { //创建窗口事件
    SUBPROC((void *)execute); //开始后台运行
    GBS_StartTimerProc(&timer, 262/10, timer_proc); //开启计时器,计时频率为每秒10次
}
void onclose() { //关闭窗口事件
    started = 0; //停止后台运行
    GBS_StopTimer(&timer); //停止计时器
    //如有需要这里保存配置信息
}
void onexit() { //退出程序事件
    if(buf) mfree(buf); //释放内存
}
void onredraw(void) { //屏幕重绘事件, 重绘屏幕
    int i, j;
    for (i = 0, j = color++; i < 132 * 176; i++) {
      screen = j++;
    }
}
//keycode - 按键代码, pressed - 按键状态 按下/释放/长按
int onkey(unsigned char keycode, int pressed) { //按键事件, 返回 0 或 1
    switch(pressed) {
    case KEY_UP: break; //释放按键
    case LONG_PRESS: //长按键
    case KEY_DOWN: //按下键
    switch(keycode) { //按键代码
    case RED_BUTTON: return 1; //返回
    case LEFT_SOFT: case RIGHT_BUTTON: case UP_BUTTON: case ENTER_BUTTON:
      //这里想写什么就写什么
    case '0': case '9': case '#': case '*': break;
    default: return 0;
    }
    onredraw(); DrawScreen(); //绘制屏幕
    }
    return 0;
}
//#define MSG_GUI_DESTROYED 152 //for not s75 if you do not have any into swilib.h

7.例4:内存驻留程序
原文省略了:-')

8. FAQ
-如何使用 SUBPROC? REDRAW?
SUBPROC - 以低优先级调用其他的过程(相当于多线程吧, 我想), 这样需要运行很长时间的过程就不会干扰 GUI 的处理, (例如 TED 中读取文本, MegaDial 中搜索电话本)
REDRAW - 触发 GUI 的 onRedraw 事件(possible from the context of process- assistant)

-如何获取时间?
TDate date;
TTime time;
GetDateTime (&date,&time);
sprintf(s,“%d:%02d ",time.hour,time.min);
sprintf(ss,“%02d-%02d-%04d”,date.day, date.month,date.year);
- IAR 输出: div_32a 未知函数(或地址 ELF_BEGIN)
工程必须设置文件 div.r79 和 func.asm
示例: 在 func.asm 中增加自定义函数 myfunc (a,b,c,d)
在 ELF_BEGIN 的代码前
    PUBLIC myfunc
myfunc: PUSH {OF R4-R6,LR}
    ;保存寄存器 R4-R6 (最多到 R12)以及 LR 的内容
    POP {OF R4-R6,PC}; 恢复
    ;或者不保存直接使用 BX LR 跳转
SI 中调用:
extern of int myfunc (int a,int b,int c, int d);
myfunc (a,b,c,d);
前 4 个参数会传递给相应的寄存器R0-R3.
运算结果返回到寄存器 R0.
ARM 指令集, 网上能找到

不会排版,程序真难排


注:IAR for ARM 4.41A和汉化补丁在论坛SPGC区可以下。

[ 本帖最后由 jpg001 于 2007-4-21 18:46 编辑 ]

swat_lc 发表于 2007-2-17 16:14:37

Elf配置部分的编写(欢迎在此交流ELF编写经验)

编译一个带配置的程序,需要增加三个文件:config_data.c,conf_loader.c,conf_loader.h。其中
config_data.c是用来编写此程序所需的配置项,而另外两个文件是用来加载配置文件的程序和头文件,
这两个文件是已经写好的,不用动。

我们先看看怎样编写配置项,打开cfg_items.h,可以看到我们主要有
UINT,STR_UTF8,INT,STR_WIN1251,CBOX,STR_PASS这几种数据类型(如果没有这些,请下载附件所带的cfg_item.h),一般常用的也就是UINT,INT,CBOX了,
每一个配置项需要有两三条语句组成,第一条语句是声明一个CFG_HDR型的结构,如我们要添加一个显示
内容"Blink display?"的yes,no项,则可以写成
__root const CFG_HDR cfghdr1={CFG_CBOX,"Blink display",0,2};
CFG_CBOX是它的类型(一个选择框),"Blink display"是描述,0,2分别是最小最大值。
下一句就应该确定配置项的变量名了,这个变量名作为extern值在main里面声明,从而使用它,形如
__root const int bl_dis=1;
当然,这里把它作为int型变量,等号后是它的初始值,即在新建配置文件时使用的值。
当使用CBOX型的配置项时,需要指出各个之所对应的选项,如0-"No",1-"Yes"。
__root const CFG_CBOX_ITEM cfgcbox1={"No","Yes"};

再举一个例子,如果想添加一个轮寻周期,可以这样写:
__root const CFG_HDR cfghdr6={CFG_UINT,"Check each",0,104800};
__root const unsigned int check_each=1310;
这里自然就没有CFG_COBX_ITEM,在CfgEdit中就是那种输入数字的样式。
写好配置项后,便可以在主程序中调用conf_loader来进行初始化(调用InitConfig()),别忘了声明全局
的extern const来得到配置项。
还有一个问题,必须在工程属性中-Linker-Config-Link Command File中指定一个.xcl的文件,否则会出现"段config为定义"的错误,这个文件也是通用的,可以从别的已经有配置功能的工程中获得,我这里也提供一个。

07-02-20:补充:还需要将config_data.c这个文件的编译选项修改一下,选中Override inherited settings,然后在output标签下的Segment base name中,将Data和Code的name都修改为CONFIG。

[ 本帖最后由 swat_lc 于 2007-2-21 01:30 编辑 ]

swat_lc 发表于 2007-2-19 22:05:23

早上没事就写了。
顺便想问一下有人知道怎么创建带图标的菜单么?MENUITEM_DESC这个里面有个int* icon,可是不知道怎么用,反正直接用(int*)ID号不对。
已解决,暂时留着,改天写感想。

[ 本帖最后由 swat_lc 于 2007-2-28 14:10 编辑 ]

swat_lc 发表于 2007-2-22 14:31:35

写个帖子记录这几天的ELF学习过程。
编译环境就不说了,有时可能发现某些源代码中使用的函数未在swilib.h定义,这时可以参考补丁biglib,一般这都比swilib新多了,可以在biglib中找着个函数,记录下它的号,如我现在没有GetFontYSize这个函数,但在我的M6C的biglib里有这个:
0714: 0xA00DDB07   ; 1C5:__thumb int GetFontYSIZE(int font)
所以可以确定1C5(十六进制)是这个函数的序号,__thumb是它的代码类型,还可能是__arm,然后在swilib中照猫画虎添加进去,注意进制别搞错了。
再说说字符串吧,以前接触的大部分是大部分是C的字符串,以\0结尾的字符串,但在手机上用的区主要是WString,是一种数组,第一个元素保存字符串长度,接着才是字符串,手机里的函数大部分用的都是这种字符串,如DrawString等,系统已经提供了函数对这两种字符串进行转换,分别为ws_2str和str_2ws,对WString处理的函数会加上w,如wstrcpy,可以在swilib.h中找。
然后是图片,想在窗口画图,一般可以直接用DrawImg,如果是用菜单什么的GUI,还可以设置相应的图标属性,即可直接显示出来。例如在创建菜单时,菜单都有一个标题,标题上就可以使用图标,我们先看看菜单标题的定义:

typedef struct
{
RECT rc;
int *icon;
int lgp_id;
int lgp_null; //0x7FFFFFFF

}HEADER_DESC;
这里有个int*型的icon,但怎么还是指针呢?当时我也搞不懂,直接用图片序号加个强制转换,然后手机以死机告诉我,不对!后来突然想到可能是为了能够显示大小图表,所以用了个数组,第一个保存小图标,第二个保存大图表(这个还未验证),不过一般用个int型的保存图表序号,直接引用就行了。顺便再说说后面的lgp_id和lgp_null吧!本来咋都想不来lgp什么意思,于是把lgp_null随便换了个数,发现竟然显示的是一段话,突然就想到可能是语言包里的,用Smelter一查,印证了我的猜测,原来lgp是language package的缩写。但当我用同样方法使用MENUITEM_DESC,却发现显示不正常,可能数组定义还不太正确
typedef struct
{
int *icon;
int lgp_id_small;
int lgp_id_large;
int zero;
int *softkeys; //{6,0x22,0x1D}
int flag1; //0
int flag2; //0x59D
}MENUITEM_DESC;
上面我说的实验,都是用megdial的源代码修改试的。
有空再写吧!

wc3mf 发表于 2007-2-22 15:00:32

很有研究精神啊,支持

我考虑过在MegaDail上直接选号发送短信,但是不知道是那个函数,而且也不懂用,看了swilib.h,猜测可能是:

#pragma swi_number=0x0100
__swi __arm void GBS_SendMessage(int cepid_to, int msg, ...); //int submess, void *data1, void *data2

又或者是???
#pragma swi_number=0x0104
__swi __arm void GBS_PendMessage(GBS_MSG *);

结果函数的各变量不知道是什么意思,你看看,

swat_lc 发表于 2007-2-22 15:16:02

回复 #4 wc3mf 的帖子

这个Message不是短消息的Message,是消息驱动操作系统的发送系统消息函数,cepid_to是接受消息的进程ID(我也不太清楚在这个系统应该叫什么),msg是主消息,如按键消息,后面的data是子消息,如按的键值,这要看msg。
SendMessage和PendMessage区别是前者调用后不立即返回,而是等消息处理完,后者调用后立即返回。
这些你要参考GUI编程了,我是从Windows编程里照搬的。

[ 本帖最后由 swat_lc 于 2007-2-22 22:11 编辑 ]

wc3mf 发表于 2007-2-22 23:52:41

原帖由 swat_lc 于 2007-2-22 15:16 发表
这个Message不是短消息的Message,是消息驱动操作系统的发送系统消息函数,cepid_to是接受消息的进程ID(我也不太清楚在这个系统应该叫什么),msg是主消息,如按键消息,后面的data是子消息,如按的键值,这要看 ...


我原来是乱猜的,望文生义。
原来如此啊,受益匪浅呢!
差点就白忙活了……

binghelingxi 发表于 2007-2-23 11:45:17

这个到1D4的swilib...目前最新了。。。

这里下载

wc3mf 发表于 2007-2-24 10:31:50

你能试试怎么使用ELF的关闭函数吗,没有这个函数,测试的时候很麻烦啊,要退出还要关机重来。
在 func.asm 中好像有这些相关的东西,还有在main.c中的这个函数也有莫大关系:

extern void kill_data(void *p, void (*func_p)(void *));
void ElfKiller(void)
{
extern void *ELF_BEGIN;
kill_data(&ELF_BEGIN,(void (*)(void *))mfree_adr());
}

swat_lc 发表于 2007-2-24 12:37:00

原帖由 wc3mf 于 2007-2-24 10:31 发表
你能试试怎么使用ELF的关闭函数吗,没有这个函数,测试的时候很麻烦啊,要退出还要关机重来。
在 func.asm 中好像有这些相关的东西,还有在main.c中的这个函数也有莫大关系:

extern void kill_data(void * ...
大概就是这样子,还要改回icsm中的内容,现在我还不太清楚ELF的详细运行过程,所以我也没办法给你个十分准确的做法。你可以看看老外那个计算器的源代码,它肯定有退出部分。

wc3mf 发表于 2007-2-24 14:12:30

原帖由 swat_lc 于 2007-2-24 12:37 发表

大概就是这样子,还要改回icsm中的内容,现在我还不太清楚ELF的详细运行过程,所以我也没办法给你个十分准确的做法。你可以看看老外那个计算器的源代码,它肯定有退出部分。

我看过了,XTASK、TextInputTester、MailViewer这三个都有这部分的内容,不过,看不懂它是如何退出的。

你有兴趣的可以看看。
附上这三个ELF的源码。

nameX 发表于 2007-2-24 17:11:37

原帖由 swat_lc 于 2007-2-17 16:14 发表
编译一个带配置的程序,需要增加三个文件:config_data.c,conf_loader.c,conf_loader.h。其中
config_data.c是用来编写此程序所需的配置项,而另外两个文件是用来加载配置文件的程序和头文件,
这两个文件是 ...

怪不得前段时间搞不定配置文件,原来是你的教程不全.
而且好像还不全,是不是还要把List中的Output Assembler file下的两个选项勾上才行啊.(我对照你的源程序看来的)

swat_lc 发表于 2007-2-24 17:49:14

原帖由 nameX 于 2007-2-24 17:11 发表


怪不得前段时间搞不定配置文件,原来是你的教程不全.
而且好像还不全,是不是还要把List中的Output Assembler file下的两个选项勾上才行啊.(我对照你的源程序看来的)

不用吧,那两个是输出编译后的汇编代码的,如果不想要,可以取,我不勾也能通过啊!

wc3mf 发表于 2007-2-24 22:47:06

原帖由 nameX 于 2007-2-24 17:11 发表


怪不得前段时间搞不定配置文件,原来是你的教程不全.
而且好像还不全,是不是还要把List中的Output Assembler file下的两个选项勾上才行啊.(我对照你的源程序看来的)

你的是不是在下面的地方写有东东,以前我使用你的工程,编译的时候老有错误,说是找不到 obexcopy.exe

[ 本帖最后由 wc3mf 于 2007-2-24 22:48 编辑 ]

swat_lc 发表于 2007-2-24 23:01:51

楼上说的不是nameX改的,俄国人写的时候就有,是方便传送文件的,编译后自动将生成的文件传到记忆卡里。那个错误不影响文件生成。

wc3mf 发表于 2007-2-25 13:52:25

你能看看这几个函数吗?应该和读写短信有关系。

0118: 0xA0975C21   ;46: HasNewSMS
011C: 0xA092E835   ;47: HasFlashSMS
0120: 0xA1603A63   ;48: ReadNewSMS
0124: 0xA0974C87   ;49: ReadFlashSMS

这些是在BigLib中的,swilib.h中还未定义,我手动添加进去,并在MegaDail中使用,发现:
ReadNewSMS 这个的确是读新信息列表。
HasNewSMS 和 HasFlashSMS 使用后直接显示待机界面,可能是我使用的参数不对,但有不知道是怎样使用。
有兴趣的话试试,要是能实现直接发新信息就牛了

刚刚又试了,了解到 HasNewSMS 是判断是否有新短信,不是写新的短信,失望……

[ 本帖最后由 wc3mf 于 2007-2-25 14:53 编辑 ]

swat_lc 发表于 2007-2-28 14:07:56

对于发送短信,一直不太清楚该用什么样的方法执行,你说的通过入口函数来执行,那就需要改biglib,增加一个sendsms之类的函数,但就咱们几个人的力量,恐怕很难实现。这两天一直在看系统处理的内容,昨天终于看明白了一点,觉得似乎可以按照XTask的思路来实现,系统里有个CSM_RAM的结构,存的都是些系统里的进程,XTask就是通过改变这个结构里的顺序来执行的(具体怎么样执行还有待研究),像NewSMS可以在CSMList.txt这个文件里找到,我们是不是可以通过这个值来实现写短消息。

wc3mf 发表于 2007-2-28 16:36:12

原帖由 swat_lc 于 2007-2-28 14:07 发表
对于发送短信,一直不太清楚该用什么样的方法执行,你说的通过入口函数来执行,那就需要改biglib,增加一个sendsms之类的函数,但就咱们几个人的力量,恐怕很难实现。这两天一直在看系统处理的内容,昨天终于看 ...


那个 XTask的CSmenu.list里面的功能都是现成的函数(其实就是手机各功能的入口地址),可以直接调用,你可以试试
给你一个获取功能地址的软件,以及CX65的功能地址、函数列表

swat_lc 发表于 2007-2-28 17:34:14

原帖由 wc3mf 于 2007-2-28 16:36 发表



那个 XTask的CSmenu.list里面的功能都是现成的函数(其实就是手机各功能的入口地址),可以直接调用,你可以试试
给你一个获取功能地址的软件,以及CX65的功能地址、函数列表

你指的是CSMList?反正我看源代码似乎不像是函数入口函数,从我的flash算出来的函数地址也和论坛上提供的M6C的不一样,另外一个问题就是怎么传递号码?

wc3mf 发表于 2007-2-28 17:46:36

原帖由 swat_lc 于 2007-2-28 17:34 发表


你指的是CSMList?反正我看源代码似乎不像是函数入口函数,从我的flash算出来的函数地址也和论坛上提供的M6C的不一样,另外一个问题就是怎么传递号码?

对,就是CSMList,那个软件弄出来的绝对是正确有效的功能入口地址,不信你试试。用自定义×#的MP补丁。或者把CSMList的函数直接改成入口地址(偏移量)。
页: [1] 2 3
查看完整版本: ELF 程序开发教程及技术讨论专贴