2015年(4)
分类: LINUX
2015-06-10 19:53:40
原文地址:嵌入式Linux的MiniGUI研究 作者:cbqcgq
1 嵌入式Linux下的GUI概况
1.1 GUI在嵌入式系统中的地位
随着嵌入式系统的广泛应用,PDA、机顶盒、DVD/VCD播放机及WAP手机已经迅速普及。图形用户界面(GUI)的广泛流行,是当今计算机技术的重大成就之一。它极大地方便了非专业用户的使用,因此实时嵌入式系统对GUI的需求越来越明显,而这一切均要求有一个高性能、高可靠的GUI 的支持。由于嵌入式系统实时性要求非常高,对GUI的要求也更高。这些系统一般不希望建立在庞大累赘的、非常消耗系统资源的操作系统和GUI之上,比如Windows或X Window,太过庞大和臃肿。这样,这些系统对轻型GUI的需求更加突出。
另外嵌入式系统往往是一种定制设备,它们对GUI的需求也各不相同。有些系统只要求一些图形功能,而有些系统要求完备的GUI支持,因此,GUI也必须是可定制的。嵌入式系统对GUI的基本要求包括轻型、占用资源少、高性能、高可靠性及可配置。
1.2 目前嵌入式系统中GUI的实现。
尽管实时嵌入式系统对GUI的需求越来越明显,但目前GUI的实现方法各有不同,主要有以下几点:
① 某些大型厂商有能力自己开发满足自身需要的GUI系统。
② 某些厂商没有将GUI作为一个软件层从应用程序中剥离,GUI的支持逻辑由应用程序自己来负责。
③ 采用某些比较成熟的GUI系统,比如 MiniGUI、MicroWindows 或者其它GUI系统。
比较常用的有如下几种GUI系统:精简的X Window 系统、MiniGUI、MicroWindows、OpenGUI及QT/Embedded 等。下面简单介绍这些系统。
(1)MiniGUI
MiniGUI由原清华大学教师魏永明先生开发,是一种面向嵌入式系统或者实时系统的图形用户界面支持系统。它主要运行于Linux控制台,实际可以运行在任何一种具有POSIX线程支持的 POSIX兼容系统上。MiniGUI同时也是国内最早出现的几个自由软件项目之一。稍后将对它作详细的介绍。
(2)MicroWindows
MicroWindows是一个著名的开放源码的嵌入式GUI软件。MicroWindows提供了现代图形窗口系统的一些特性。MicroWindows API接口支持类Win32 API,接口试图和Win32完全兼容。它还实现了一些Win32用户模块功能。MicroWindows采用分层设计方法,以便不同的层面能够在需要的时候改写,基本上用 C 语言实现。MicroWindows已经支持 Intel 16位和32位CPU、MIPS R4000 以及 ARM 芯片;但作为一个窗口系统,该项目提供的窗口处理功能还需要进一步完善,比如控件或构件的实现还很不完备,键盘和鼠标等的驱动还很不完善。
(3)OpenGUI
OpenGUI在Linux系统上存在已经很长时间了。这个库是用C++编写的,只提供C++接口。OpenGUI基于一个用汇编实现的x86图形内核,提供了一个高层的C/C++图形/窗口接口。OpenGUI提供了二维绘图原语、消息驱动的API及BMP文件格式支持。OpenGUI功能强大,使用方便。OpenGUI 支持鼠标和键盘的事件,在Linux上基于Framebuffer或者SVGALib实现绘图。由于其基于汇编实现的内核并利用MMX指令进行了优化,OpenGUI运行速度非常快。正由于其内核用汇编实现,可移植性受到了影响。通常在驱动程序一级,性能和可移植性是矛盾的,必须找到一个折衷。
(4)QT/Embedded
QT/Embedded是著名的QT库开发商Trolltech 的面向嵌入式系统的QT版本。这个版本的主要特点是可移植性较好,许多基于QT的X Window程序可以非常方便地移植到嵌入式系统;但是该系统不是开放源码的,如果使用这个库,可能需要支付昂贵的授权费用。
(5)Pure X架构
Tiny X Server是XFree86 Project的一部分,由Keith Pachard先生所发展,而他本身就是XFree86专案的核心成员之一。一般的X Server都太过于庞大,因此Keith Packard就以XFree86为基础,精简了不少东西而成Tiny X Server,它的体积可以小到几百Kb而已,非常适合应用于嵌入式环境。
以纯X Window System搭配Tiny X Server架构来说,最大的优点就是弹性与开发速度,因为与桌面的X架构相同,因此相对于很多以Qt、GTK+、FLTK等开发的软件可以很容易地移植上来。
虽然移植方便,但是却有体积大的缺点,由于很多软件本来是针对桌面环境开发的,因此无形之中具备了桌面环境中很多复杂的功能。因此“调校”变成采用此架构最大的课题,有时候重新改写都可能比调校所需的时间还短。表1.1为这几种嵌入式GUI的特点比较。
表1.1 嵌入式GUI的特点比较
属性GUI |
MiniGUI |
MicroWindows |
OpenGUI |
QT/Embedded |
Pure X架构 |
代码量 |
小巧(300K) |
|
|
大(最简800K) |
稍大 |
性能 |
好 |
有待完善 |
好 |
非常好 |
|
移植性 |
好 |
|
较差 |
好 |
非常好 |
库函数 |
C语言 |
基本C语言 |
C++ |
C++ |
|
经济性 |
自由软件 |
自由软件 |
|
商业/源码公开 |
|
内核实现 |
C语言 |
|
汇编 |
|
|
汉字编辑 |
多字符集 |
无统一接口 |
|
|
|
2 MiniGUI的特点、优势和体系结构
2.1 MiniGUI的特点
MiniGUI的主要特点有:
◇ 遵循GPL条款的纯自由软件。
◇ 提供了完备的多窗口机制,包括:
1)多个单独线程中运行的多窗口;
2)单个线程中主窗口的附属;
3)对话框和预定义的控件类(按钮、单行和多行编辑框、列表框、进度条及工具栏等);
4)消息传递机制。
◇ 多字符集和多字体支持,目前支持 ISO8859-1、GB2312及Big5 等字符集,并且支持各种光栅字体和 TrueType、Type 1 等矢量字体。
◇ 全拼和五笔等汉字输入法支持。
◇ BMP、GIF、JPEG及PCX 等常见图像文件的支持。
◇ Windows的资源文件支持,如位图、图标、光标、插入符、定时器及加速键等。
◇ 插入符、定时器、加速键等。
2.2 MiniGUI优势
◇ 小巧。包含全部功能的库文件大小为300 KB左右。
◇ 可配置。可根据项目需求进行定制配置和编译。
◇ 高稳定性和高性能。MiniGUI已经在Linux发行版安装程序、CNC系统及蓝点嵌入式系统等关键应用程序中得到了实际应用。
◇ 可移植性好。目前,MiniGUI可以在X Window 和Linux控制台上运行。中科院EEOS开发组已经成功地将MiniGUI移植到了他们的POSIX兼容系统上。蓝点软件(北京)研发中心也已经成功地将 MiniGUI移植到了两款基于StrongARM的嵌入式系统上。
MiniGUI本身的占用空间非常小,以嵌入式Linux操作系统为例,一个典型的MiniGUI系统存储空间占用情况如表1.2所示。
表1.2 典型MiniGUI系统空间占用情况
组成部分 |
容 量 |
说 明 |
Linux内核 |
300k~1M |
由系统决定 |
MiniGUI支持库 |
500k~700k |
由编译选项决定 |
MiniGUI字体、位图等资源 |
400k |
由应用程序确定,可缩小到200k以内 |
GB输入法码表 |
200k |
不是必需的,由应用程序确定 |
应用程序 |
1M~2M |
由应用程序确定 |
从上表可以看出,系统总体的占有空间应该在2M~5M左右。在某些系统上,功能完备的MiniGUI系统本身所占用的空间可进一步缩小到1MB以内,所以比较适合嵌入式系统。
2.3 MiniGUI的体系结构
一个能够移植到多种硬件平台上的嵌入式GUI系统,应用至少抽象出两类设备:基于图形显示设备(如VGA卡)的图形抽象层GAL(Graphic Abstract Layer),基于输入设备(如键盘,触摸层等)的输入抽象层IAL(Input Abstract Layer)。GAL层完成系统对具体的显示硬件设备的操作,极大程度上隐蔽各种不同硬件的技术实现细节,为程序开发人员提供统一的图形编程接口。 IAL层则需要实现对于各类不同输入设备的控制操作,提供统一的调用接口。GAL层与IAL层的设计概念,可以极大程序地提高嵌入式GUI的可移植性,如图2.1所示。
目前应用于嵌入式Linux系统中比较成熟,功能也比较强大的GUI系统底层支持库有SVGA lib、LibGGI、Xwindow、framebuffer等。
从整体结构上看,MiniGUI是分层设计的,层次结构如图2.2所示。在最底层,GAL和IAL提供底层图形接口以及鼠标和键盘的驱动;中间层是MiniGUI 的核心层,包括窗口系统必不可少的各个模块;最顶层是API,即编程接口。GAL和IAL为 MiniGUI提供了底层的Linux控制台或者X Window 上的图形接口以及输入接口,而Pthread用于提供内核级线程支持的C函数库。
利用GAL和IAL,大大提高了MiniGUI的可移植性,并且使程序的开发和调试变得更加容易。可以在X Window上开发和调试自己的MiniGUI程序,通过重新编译就可以让MiniGUI应用程序运行在特殊的嵌入式硬件平台上。
由于MiniGUI较好地将硬件设备抽象为GAL层和IAL层,移植时只需要针对自身的硬件特点按照GAL层调用接口和IAL层调用接口来做内部实现即可。图2.3为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 MiniGUI的移植与编程
3.1 MiniGUI的移植
要运行MiniGUI系统需要满足一些前提条件:
1) 支持POSIX.X的Linux系统,包括Linux2.0、Linux2.4,也包括uClinux等非标准的Linux系统;
2) Linux的Framebuffer驱动程序功能正常添加,对于没有Framebuffer支持的Linux系统,需要编写特定的图形引擎才能运行MiniGUI;
3) 运行MiniGUI-Threads版本需要POSIX兼容线程库的支持;
4) 运行MiniGUI-Lite版本需要UNIX Domain套接字机制的支持。
下面简单介绍一下MiniGUI移植过程的整个编译过程:
1) 搭建开发环境
2) 编译MiniGUI
3) 安装资源文件
4) 编译MDE,其中MDE是MiniGUI的综合演示程序。
3.2 MiniGUI编程实现
MiniGUI是一个典型的消息驱动的GUI系统,每个MiniGUI程序都是从MiniGUIMain函数开始的。应用程序先以CreateMainWindow函数创建一个主窗口,由于窗口创建的时候缺省是不可见的,我们通过ShowWindow函数显示该窗口,最后通过GetMessage(&MsgvhMainWnm)进入消息循环。
下例编写了一个简单的Hello,world!程序,程序清单如下。
#endif /*消息处理函数*/ Static int HelloWinproc(HWND hWnd,int nessage,WPARAM wParam,LPARAM lparam) { HDC hdc; Switch(message){ Case MSG_PAINT: /*显示*/ Hdc = BeginPaint(hWnd); TextOut(hdc,100,100,”Hello world!”); EndPaint(hWnd,hdc); Return 0; Case MSG_CLOSE: DestroyMainWindow(hWnd); /*注销掉*/ PostQuitMessage(hWnd); Return 0; } /*主函数*/ int MiniGUIMain(int argc,const char* argv[]) { MSG Msg; HWND hMainWnd; MAINWINCREATE CreateInfo; #ifdef _LITE_VERSION SetDesktopRect(0,0,800,600); #endif CreateInfo.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION;/*窗口风格*/ CreateInfo.dwExStyle = WS_EX_NONE; /*窗口的附加风格*/ CreateInfo.spCaption = “HelloWorld”; /*窗口的标题*/ CreateInfo.hMenu = 0; /*附加到窗口上的菜单句柄*/ CreateInfo.hCursor = GetSystemCursor(0); /*窗口中所使用鼠标光标句柄*/ CreateInfo.hIcon = 0; /*程序图标*/ CreateInfo.MainWindowProc = HelloWinProc; /*消息处理函数指针*/ CreateInfo.lx = 0; /*窗口在屏幕上的位置及大小*/ CreateInfo.ty = 0; CreateInfo.rx = 320; CreateInfo.by = 240; CreateInfo.iBkColor = CORLOR_lightwhite; /*窗口背景颜色*/ CreateInfo.dwAddData = 0; /*附带给窗口的一个32位值*/ CreateInfo.hHosting = HWND_DESKTOP; /*消息队列所属窗口*/ /*建立主窗口*/ hMainWnd = CreateMainWindow(&CreateInfo); if(hMainWnd == HWND_INVALID) return -1; /*显示主窗口*/ ShowWindow(hMainWnd,SW_SHOWNORMAL); /*进入消息循环*/ While(GetMessate(&Mag,hMainWnd)){ TranslateMessage(&Msg); DispatchMessage(&Msg); } MainWindowThreadCleanup(hMainWnd); Return 0; } |
4 总结与展望
到目前为止,已经有多家嵌入式系统开发商采用MiniGUI开发嵌入式系统,并且已经开发出了许多重要的应用程序。我们期望能够有更多的人加入MiniGUI的开发,共同促成MiniGUI成为嵌入式 Linux系统上的标准GUI。
随着MiniGUI不断推广和功能的加强,它也将在实际应用中不断走向成熟。实时嵌入式系统上的GUI开发正处于开始阶段。在这个领域,有许多技术难题等待自由软件程序员去解决。