嵌入式GUI为嵌入式系统提供了一种应用于特殊场合的人们交互接口。
其特点:
体积小;
运行时耗用系统资源小;
上层接口与硬件无关,高度可移植;
高可靠性;
在某些应用场合应具备实时性。
1 基于嵌入式Linux的GUI系统底层实现基础
一个能够移植到多种硬件平台上的嵌入式
GUI系统,应用至少抽象出两类设备:基于图形显示设备(如
VGA卡)的图形抽象层
GAL(
Graphic
Abstract Layer),基于输入设备(如键盘,触摸层等)的输入抽象层
IAL(
Input Abstract Layer)。
GAL层完成系统对具体的显示硬件设备的操作,极大程度上隐蔽各种不同硬件的技术实现细节,为诮程序开发人员提供统一的图形编程接口。
IAL层则需要实现对于各类不同输入设备的控制操作,提供统一的调用接口。
GAL层与
IAL层的设计概念,可以极大程序地提高嵌入式
GUI的可移植性,如图
1所示。
目前应用于嵌入式
Linux系统中比较成熟,功能也比较强大的
GUI系统底层支持库有
SVGA lib、
LibGGI、
Xwindow、
framebuffer等。
2 三种嵌入式GUI系统的分析与比较
2.
1 Microwindows
Microwindows是一个典型的基于
Server/Clinent体系结构的
GUI系统,基本分为三层,如图
2所示。
最底层是面向图形显示和键盘、鼠标或触摸屏的驱动程序;中间层提供底层硬件的抽象接口,并进行窗口管理;最高层分别提供兼容于
X Window和
ECMA APIW(
Win32子集)的
API。其中使用
Nano-X接口的
API与
X接口兼容,但是该接口没有提供窗口管理,如窗口移动和窗口剪切等高级功能,系统中需要首先启动
nano-X的
Server程序
nanoxserver和窗口管理程序
nanowm。用户程序连接
nano-X的
Server获得自身的窗口绘制操作。使用
ECMA
APIW编写的应用程序无需
nanox-server和
nanowm,可直接运行。
Microwindows提供了相对完善的图形功能和一些高级的特性,如
Alpha混合、三维支持和
TrueType字体支持等。该系统为了提高运行速度,也改进了基于
Socket套接字的
X实现模式,采用了基于消息机制的
Server/Client传输机制。
Microwindows也有一些通用的窗口控件,但其图形引擎存在许多问题,可以归纳如下:
*无任何硬件加速能力;
*图形引擎中存在许多低效算法,如在圆弧图函数的逐点判断剪切的问题。由于该项目缺乏一个强有力的核心代码维护人员,
2003年
Microwindows推出版本
0.90后,该项目的发展开始陷于停滞状态。
2.2 MiniGUI
MiniGUI是由国内自由软件开发人员设计开发的,目标是为基于
Linux的实时嵌入式系统提供一个轻量级的图形用户界面支持系统。
MiniGUI的体系架构如图
3所示。
MiniGUI分为最底层的
GAL层和
IAL层,向上为基于标准
POSIX接口中
pthread库的
Mini-thread架构和基于
Server/Client的
Mini-Lite架构。其中前者受限于
thread模式对于整个系统的可靠性影响
——进程中某个
thread的意外错误可能导致整个进程的崩溃,该架构应用于系统功能较为单一的场合。
Mini-Lite应用于多进程的应用场合,采用多进程运行方式设计的
Server/Client架构能够较好地解决各个进程之间的窗口管理、
Z序剪切等问题。
MiniGUI还有一种从
Mini-Lite衍生出的
standalone运行模式。与
Lite架构不同的是,
standalone模式一次只能以窗口最大化的方式显示一个窗口。这在显示屏尺寸较小的应用场合具有一定的应用意义。
MiniGUI的
GAL层技术
SVGA lib、
LibGGI、基于
framebuffer的
native图形引擎以及哑图形引擎等,对于
Trolltech公司的
QVFB在
X
Window下也有较好的支持。
IAL层则支持
Linux标准控制台下的
GPM鼠标服务、触摸屏、标准键盘等。
MiniGUI下丰富的控件资源也是
MiniGUI的特点之一。当前
MiniGUI的最新版本是
1.3.3.该版本的控件中已经添加了窗口皮肤、工具条等桌面GUI中的高级控件支持。
2.
3 QT/Embedded
Qt/Embedded是著名的
Qt库开发商
Trolltech公司开发的面向嵌入式系统的
Qt版本。因为
Qt是
KDE等项目使用的
GUI支持库,许多基于
Qt的
X
Window程序因此可以非常方便地移植到
Qt/Embedded上。
Qt/Embedded同样是
Server/Client结构。
Qt/Embedded延续了
Qt在
X上的强大功能,在底层摒弃了
X lib,仅采用
framebuffer作为底层图形接口。同时,将外部输入设备抽象为
keyboard和
mouse输入事件,底层接口支持键盘、
GPM鼠标、触摸屏以及用户自定义的设备等。
Qt/Embedded类库完全采用
C++封装。丰富的控件资源和较好的可移植性是
Qt/Embedded最为优秀的一方面。它的类库接口完全兼容于同版本的
Qt-X11,使用
X下的开发工具可以直接开发基于
Qt/Embedded的应用程序
QUI界面。
与前两种
GUI系统不同的是,
Qt/Embedded的底层图形引擎只能采用
framebuffer.这就注定了它是针对高端嵌入式图形领域的应用而设计的。由于该库的代码追求面面俱到,以增加它对多种硬件设备的支持,造成了其底层代码比较凌乱,各种补丁较多的问题。
Qt/Embedded的结构也过于复杂臃肿,很难进行底层的扩充、定制和移植,尤其是用来实现
signal/slot机制的
moc文件。
Qt/Embedded当前的最新版本为
3.3.2,能够支持Trolltech的手持应用套件Qtopia的Qt/Embedded最高版本为2.3.8.Trolltech公司将于2004年末推出的Qt/Embedded
3为基础的Qtopia 2应用套件。
3 三种
嵌入式GUI的移植与中文化
在进行以上三种嵌入式
GUI的研究和移植过程中,硬件平台采用自行设计的以
Motorola MC9328 MX1为核心的开发系统。该系统采用
CPU内部
LCD控制器和
320×
240分辨率的
16bpp
TFT LCD作为显示设备,使用
I2C总线扩展出
16按键的键盘,同时配置了
9位
A/D量化精度的电阻触摸屏作为鼠标类输入设备;同时移植了
arm
Linux作为操作系统。以下分别讨论这三种嵌入式
GUI的底层移植和中文化技术。
移植以上三种嵌入式
GUI系统,需要首先实现
Linux内核中的
framebuffer驱动。对应于开发系统为
MC9328中的
LCD控制器,该部分驱动程序必须以静态方式编译进内核,在系统启动时由传递进内核的启动参数激活该设备。
I2C键盘的驱动程序和触摸屏的驱动程序实现后,作为
Linux内核模块在使用时动态加载。
3.
1 Microwindows的移植
Microwindows驱动层相应的源码目录为
src/drivers/.其中以
scr*开头的源码是针对显示设备的驱动接口,以
mou*开头的源码文件为鼠标设备(包括触摸屏)的驱动接口,以
kbd*开头的源码文件针对键盘设备的驱动接口。移植过程中需要实现自己的设备驱动接口提供给
Microwindows使用,就必须按照指定的接口格式编写相应的
scr、
mou、
kbd的底层支持。这种方式实现简单,条理也很清晰。
显示设备驱动接口:
Microwindows的图形发生引擎支持
framebuffer,修改
src/中的
config文件指定使用
framebuffer作为底层图形支持引擎;但需要注意嵌入式
Linux的
framebuffer较少支持控制台字符模式,需要修改
Microwindows中对
framebuffer的操作部分以关闭显示模式的转换
在应用程序开发移植中需要注意的是:使用
ECMAAPIW接口设计的程序无需
nano-X 的
Server程序和
nanowm,如图
2所示。系统中可以直接启动使用该接口编写的用户程序;但需要注意的是,一个系统中如同时存在使用两种不同的
API接口编写的进程,会造成
nano-X的
Server与
ECMA APIW的进程对系统硬件资源的使用竞争,双方的程序将无法正常显示或响应应用户输入。
在为
Microwindows增加中文显示的支持时,主要工作包括两个部分。一部分是系统字体的中文支持。此处使用等宽光栅字体,主要负责窗口标题和内置控件的中文绘制,将字体编译进
Microwindows内核中,光栅信息作为一维数组,显示时按照字符偏移量从该数组中调出相应的光栅信息显示即可。除此之外,当程序调用
CreateFont时,需要在内部实现为打开文件系统中的字体文件。通过修改
src/engine/devfont.c中的
GdCreateFont部分,添加相应的
hzk(汉字库)支持,便可以实现在
CreateFont
时创建出一个支持
GB2312字符集的逻辑字体,并使用外部字体进行显示。在应用程序设计时,如果没有调用
SelectObjectu将外部字体选入,中文显示时将默认使用系统字体。
3.2 MiniGUI
由于
MiniGUI较好地将硬件设备抽象为
GAL层和
IAL层,移植时只需要针对自身的硬件特点按照
GAL层调用接口和
IAL层调用接口来做内部实现即可。图
4为
MiniGUI的
GAL层结构示意,
IAL层结构类似。
实现了
framebuffer的
Linux驱动后,配置
MiniGUI选择
Native的
GAL引擎,便可以使用
framebuffer作为
MiniGUI的图形发生引擎。
MiniGUI的
IAL层将输入设备的输入事件最终映射为
GUI系统
API层的消息事件。
IAL层默认处理两种设备的输入操作:键盘设备和鼠标设备。键盘设备向上层提供不同的按键输入信息,鼠标设备提供点击、抬起和落笔坐标等的信息。在实现
MiniGUI与输入设备驱动的接口时,采用
Select的方式获得输入设备的动作,并转换为消息队列中的消息。消息参数按照
Win32接口定义为点击键编号或鼠标当前的坐标(其中触摸屏事件与鼠标事件类似)。通过编写针对硬件开发系统的
IAL支持代码,实现了
IAL层的移植。
MiniGUI中多字体和字符集支持是通过设备上下文(
DC)的逻辑字体(
LOGFONT)实现的,创建逻辑字体时指定相应的字符集,其内部实现为对于所需显示字符的所属字符集的识别处理,最终调用相应字符集的处理函数族。应用程序在启动时,可切换系统字符集,如
GB2312、
BIG5、
EUCKR、
UJIS.MiniGUI的这种字符集支持方式不同于采用
UNICODE的解决方案。在节省系统资源的意义上讲,这种实现更加适合于嵌入式系统应用,是
MiniGUI的一大创新点。
MiniGUI同时支持包括
ttf、
bdf、
type 1、
vbf等多种字体格式,可以根据需要配置
MiniGUI来支持相应字体的显示。
3.
3 Qt/Embedded的移植
Qt/Embedded的底层图形引擎完全依赖于
framebuffer,因此在移植时需考虑目标平台的
Linux内核版本和
framebuffer驱动程序的实现情况,包括分辨率和颜 {MOD}深度等在内的信息。当前嵌入式
CPU大多内部集成
LCD
控制器,并支持多种配置方式。除少数
CPU低 {MOD}彩配置时的
endian问题外,
Qt/Embedded能够较好地根据系统已有的
framebuffer驱动接口构建上层的图形引擎。
Qt/Embedded图形发生引擎中的图形绘制操作函数都是由源泉码目录
src/kernel/中的
src/kernel/qgfxreaster_qws.cpp中所定义的
QgfxRasterBase类发起声明的。对于设备更加底层的抽象描述,则在
src/kernel目录中的
qgfx_qws.cpp中的
Qscreen类中给予相应定义。这些是对
framebuffer
设备直接操作的基础,包括点、线、区域填充、
alpha混合、屏幕绘制等函数均在其中定义实现。在
framebuffer驱动程序调试通过后,配置
Qt/Embedded的编译选项,可以保证
Qt/Embedded的图形引擎正常工作。
Qt/Embedded中的输入设备,同样分为鼠标类与键盘类。其中鼠标设备在源泉码目录中的
src/kernel/qwsmouse_qws.cpp中实现,从该类又重新派生出一些特殊鼠标类设备的实现类,其派生结构如图
5所示。
根据具体的硬件驱动程序实现的接口,可以实现类似的接口函数。
Qt/Embedded中对于键盘响应的实际函数位于
src/kernel/qkeyboard_qws.cpp中,在
qkeyboard_qws.h中,定义了键盘类设备接口的基类
QWSKeyboardHandler。具体的键盘硬件接口依然要建立在键盘驱动程序基础上,移植时需要根据键盘驱动程序从该类派生出实现类,实现键盘事件处理函数
processKeyEvent()即可。
Qt/Embedded内部对于字符集的处理采用了
UNICODE编码标准。
Qt/Embedded内部对于字符集的处理采用了
UNICODE编码标准。
Qt/Embedded同时支持两种对于其它编码标准(如
GB2312和
GBK)的支持方式:静态编译和动态插件装载。通过配置
config.h文件添加相应的编码支持宏定义,可以获得其它编码标准向
UNICODE的转换支持,从而在
Qfont类中得以转换与显示。由于
UNICODE涵盖了中文部分,
Qt/Embedded对中文支持也非常好。
Qt/Embedded能够支持
TTF、
PFA/PFB、
BDF 和
QPF字体格式。由于自身采用
UNICODE编码方式对字符进行处理,在一定程序上导致了能够使用的字体文件体积的增大。为了解决这一问题,
Qt/Embedded采用了
QPF格式,使用
makeqpf等工具可以将
TTF等格式的字体转换至
QPF格式。图
6为笔者在自行设计的
MC9328系统上移植
Qt/Embedded和
Qtopia套件后,增加中文支持后的显示截图。
Qt/Embedded版本为
2.3.7,Qtopia版本为
1.7.0。
4 结论
综上所述,一个具备良好移植性的
嵌入式GUI系统,其底层接口应该在很大程度上隐藏具体硬件的实现细节,抽象出GAL与IAL层。对于字符集的支持,也可以从MiniGUI的字符集支持方式和Qt/Embedded的UNICODE支持方式上获得启发。