最近比较闲,就把ucgui移植到vxworks的windml上了。Ucugi本身如果直接移植到硬件的话会更有效率,但移植到windml上也有它的优势,比如移植过程比较简单,可以绕过各种硬件,直接在ugl提供的接口函数上操作,从而省去繁琐的硬件调试,而硬件调试恰恰是最容易出错的地方。还有就是使得ucgui能运行在任何支持windml的硬件环境上面,比如simpc、pentium机等,这对于缩短产品开发周期大有好处。至于效率方面,由于我们只需要使用windml最简单的ugl画图功能,所以只要CPU不是太差(比如桌面PC机就可以),那么多出一层windml导致的效率损失是完全可以忽略不计的。
首先总体介绍一下,我使用的是Tornado2.2+vxworks5.5+windml3.0+ugl3.4,硬件使用风河自带的simpc。色彩转换采用ugl和ucgui都支持的RGB565编码。
下面正式介绍移植过程:
LCD显示屏的移植
Ucgui中,对显示屏的支持只需要填写有限的几个函数即可:
LCD_L0_Init
LCD_L0_ReInit
LCD_L0_Off
LCD_L0_On
LCD_L0_DrawBitmap
LCD_L0_DrawHLine
LCD_L0_DrawVLine
LCD_L0_FillRect
LCD_L0_SetPixelIndex
LCD_L0_XorPixel
LCD_L0_Init中实现的是显示屏的初始化,移植时在这里填入ugl的初始化函数即可,另外我把ugl input的初始化操作也放在里面。
int LCD_L0_Init(void)
{
int x,y;
/* Initialize UGL */
if (uglInitialize() == UGL_STATUS_ERROR)
return;
/* Obtain display device identifier */
g_uglDevId = (UGL_DEVICE_ID)uglRegistryFind (UGL_DISPLAY_TYPE, 0, 0,0)->id;
/* obtain the input service identifier. */
g_uglInputServiceId = (UGL_INPUT_SERVICE_ID)uglRegistryFind (UGL_INPUT_SERVICE_TYPE, 0, 0,0)->id;
g_uglGc = uglGcCreate(g_uglDevId);
for (y = 0; y < LCD_YSIZE; y++)
{
LCD_L0_DrawHLine(0, LCD_XSIZE-1, BKCOLORINDEX);
}
return 0;
}
ReInit我没有用到,所以这里是空的。
On和Off函数同样也没有用到。
DrawBitMap函数中不涉及硬件操作,最终它会调用SetPixelIndex函数,所以直接把demo中的函数实现复制过来即可。
DrawVLine和DrawHLine函数,ugl中与之对应的是uglLine,所以直接映射过去即可。
void LCD_L0_DrawHLine (int x0, int y, int x1)
{
if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR)
{
for (;x0 <= x1; x0++)
{
LCD_L0_XorPixel(x0, y);
}
}
else
{
uglForegroundColorSet(g_uglGc, LCD_GetColorIndex());
uglLine(g_uglGc, x0, y, x1, y);
}
}
FillRect函数最终也是映射到DrawVLine或DrawHLine操作。
SetPixelIndex,这是最基本的绘图函数,这里因为我使用RGB565编码,所以直接把Index值传到ugl函数即可。
void LCD_L0_SetPixelIndex(int x, int y, int Index)
{
uglPixelSet(g_uglGc, x, y, Index&0xffff);
}
XorPixel,对指定点的色彩进行异或操作,我的实现方法是这样:
void LCD_L0_XorPixel(int x, int y)
{
unsigned int Index = COLO2INDEX
(LCD_L0_GetPixelIndex(x,y)
);
LCD_L0_SetPixelIndex(x, y, ~Index);
}
色彩转换
Ucugi本身支持RGB565色彩转换,但它的RGB位图与ugl中RGB位图相反,这有点像Big Endian和Little Endian的区别。所以要将ucugi中rgb565的实现重写一遍,所幸比较简单,没花多长时间。
另外有一点我比较奇怪,ugl中SetPixelIndex使用的参数是RGB565格式,但GetPixelIndex得到的颜色是RGB绝对数值,这一点需要特别注意。
GUI_X.c文件
为了支持多任务,我们需要修改ucgui中的gui_x.c文件,这个文件的修改同样非常简单。
int GUI_X_GetTime(void)
{
return tickGet();
}
void GUI_X_Delay(int Period)
{
taskDelay(Period);
}
void GUI_X_ExecIdle(void) {
taskDelay(1);
}
static SEM_ID g_bOSSem;
U32 GUI_X_GetTaskId(void)
{
return (U32)taskIdSelf();
}
void GUI_X_InitOS(void)
{
g_bOSSem = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
}
void GUI_X_Init(void) {}
void GUI_X_Unlock(void)
{
semGive(g_bOSSem);
}
void GUI_X_Lock(void)
{
semTake(g_bOSSem, WAIT_FOREVER);
}
void GUI_X_Log(const char *s){}
void GUI_X_Warn(const char *s){}
void GUI_X_ErrorOut(const char *s){}
鼠标键盘的支持
Ugl中已经替我们实现了鼠标键盘,只需调用uglInputMsgGet即可,得到ugl提供的鼠标键盘后,再调用GUI_StoreKeyMsg和GUI_PID_StoreState把鼠标键盘值传到ucgui中,最后别忘了调用WM_Exec。
while(1)
{
timer = GUI_GetTime();
status = uglInputMsgGet (g_uglInputServiceId, &msg, 200);
if (status == UGL_STATUS_OK)
{
if (msg.type == MSG_KEYBOARD)
{
if (msg.data.keyboard.modifiers & UGL_KBD_KEYDOWN)
{
key = msg.data.keyboard.key;
GUI_StoreKeyMsg(key, 1);
WM_Exec();
timer = GUI_GetTime();
}
}
else if (msg.type == MSG_POINTER)
{
state.x = msg.data.pointer.position.x;
state.y = msg.data.pointer.position.y;
state.Pressed = msg.data.pointer.buttonState;
GUI_PID_StoreState(&state);
WM_Exec();
timer = GUI_GetTime();
}
}
if (GUI_GetTime() - timer >= 5)
{
WM_Exec();
}
}
附件是我移植时修改的文件,供参考。
http://download.csdn.net/source/346968