为目标嵌入式产品选择适合的嵌入式图形支持系统成为与选择嵌入式操作系统一样颇具挑战性。本土公司开发的MiniGUI是一个高效、可靠、可定制、小巧灵活的图形用户界面支持系统,并具有跨硬件平台、跨操作系统的可移植性,非常适合于实时嵌入式产品开发。本文详细阐述了MiniGUI的特点、运行模式和应用。
随着高端消费类电子产品(PDA、手机等)的广泛应用,原先仅在军工、工业控制等领域中使用的实时嵌入式操作系统,受到越来越多的关注。因为嵌入式产品本身是一种高度定制化的软硬件集成产品,单个操作系统无法满足各类嵌入式产品的多样化需求,因此,业界有许多各具特色的实时嵌入式操作系统产品可供选择。
在嵌入式产品开发中,除操作系统之外,开发人员关注最多的另外一个系统软件组件就是图形支持系统。只要是面向人机交互的嵌入式产品,就涉及到文字或者图形的输出问题。
不过,在嵌入式系统上的GUI应用开发,不像PC平台上的应用开发那么容易和方便。一是因为设备的可用资源有限(CPU运算能力、静态和动态存储空间等),二是因为操作系统提供的底层机制有限。这样,为具有不同硬件配置的嵌入式产品以及各类实时嵌入式操作系统提供功能完备、且又适合嵌入式产品特点的GUI支持系统,存在着诸多技术挑战。
嵌入式操作系统的选择
“内核接口+ANSI C库”的模式,是大多数嵌入式操作系统开发采用的编程模式。但是,这种模式还存在一些问题。如果我们要使用ANIS C库中的标准I/O接口,则需要操作系统提供文件系统及字符输出的支持;如果我们要使用ANSI C库中的内存管理函数(malloc/free函数族),就需要提供针对具体硬件的堆管理方案及实现代码。因此,RTOS通常都设计为模块化的软件系统,需要什么样的功能,可向RTOS产品厂商购买对应的模块来实现。
图 1 RTOS 的一般软件结构。
实际上,不同RTOS之间的区别,除了在任务管理上的核心区别之外,其他的主要区别就在外围模块上。图1给出了RTOS的一般软件结构。
RTOS可划分为如下几个种类:
1.传统实时嵌入式操作系统。主要包括:VxWorks、pSOS、Nucleus、WinCE等。VxWorks和pSOS的用户主要集中在军工、工业控制及电信领域,Nucleus和WinCE在消费类产品中应用较为广泛。
2.开放源码的嵌入式操作系统。典型代表有Linux/uClinux、eCos。因为传统实时嵌入式操作系统价格比较昂贵,所以许多用户开始使用免授权费的Linux/uClinux等操作系统开发自己的嵌入式产品。Linux操作系统从本质上属于通用操作系统,缺少强实时支持,因此嵌入式Linux在某些不需要强实时性的嵌入式产品中得到了较多应用,典型的产品有智能手机(这类产品中的实时性主要通过专用硬件芯片保证)、查询终端等。uClinux是Linux的一个变种,主要运行在没有内存管理单元(MMU)的CPU架构上。因为没有内存管理单元,uClinux无法实现现代操作系统能够提供的进程地址空间保护等高级特性,但它最大程度地保留了Linux的系统调用功能,而且资源消耗低,因此在一些中低端的32位嵌入式产品中得到了应用。eCos也是一种开源、免授权费的RTOS产品。和Linux/uClinux相比,它更类似传统的实时嵌入式操作系统,而且提供了丰富的外围模块,如文件系统、TCP/IP接口模块、POSIX兼容接口模块等。根据笔者的实际应用经验,eCos操作系统在一定程度上可以用来替代传统实时嵌入式操作系统。
3.新型实时嵌入式操作系统。主要包括uC/OS-II、ThreadX等操作系统,它们的出现,填补了RTOS操作系统市场的中低端市场,给广大嵌入式产品开发者提供了性价比较高的选择。
4.本地实时嵌入式操作系统。近几年,中国也有厂商开始提供自主研发的实时嵌入式操作系统,典型的有Hopen和Delta操作系统。这些产品已经在消费类电子产品和军工领域中得到了一些应用。
通过上面的介绍可以看到,嵌入式操作系统市场中存在各种产品可供选择。嵌入式产品的种类丰富,需求多样,不太可能出现类似PC那样由一个操作系统独霸天下的状况。
嵌入式产品开发中常用的图形解决方案
在嵌入式产品的开发过程中,软件开发人员通常采取如下几种方法来解决产品的图形需求:
1.针对特定图形输出设备的接口,自行开发图形相关的功能函数。利用这种手段编写的程序,无法将显示逻辑和数据处理逻辑划分开来,从而导致程序结构不好,不便于调试,并导致大量的代码重复。这种方案的缺点很明显,即可移植性差,维护成本高。
2.购买针对特定嵌入式操作系统的图形中间件软件包。一些嵌入式操作系统厂商,也为自己的操作系统专门开发了对应的GUI中间件产品。如uC/OS-II上的uC/GUI、Nucleus上的GRAFIX包、VxWorks上的WindML包等等。这种方案为嵌入式产品开发提供了直接可用的方案,并且能够和原有操作系统良好配合;但缺点是这类软件包的功能通常比较简单,且价格高昂。另外,基于这些软件包开发的 GUI 应用软件不具备跨操作系统的可移植性。
3.采用开放源码的嵌入式GUI支持系统。随着嵌入式Linux操作系统的应用,开源社区也在不断为嵌入式系统提供不同的开放源码嵌入式图形解决方案,如MicroWindows、OpenGUI,以及新近出现的picoGUI等。这些开放源码的嵌入式GUI软件提供免授权费的解决方案。然而,由于缺少商业公司的支持,这些软件一般存在较多的软件缺陷,加上缺乏有担保的技术支持,因此,存在着很大的开发风险。
图 2 MiniGUI 和嵌入式操作系统的关系。
4.使用由独立软件开发商提供的嵌入式GUI产品。这类产品有北京飞漫软件技术有限公司开发的MiniGUI、挪威TrollTech公司的Qt/Embedded等。这两种产品都是开源(遵循GNU的GPL条款发布)的嵌入式GUI软件产品,但均采用双授权模式,即针对商业使用收取软件许可费用。MiniGUI属于中低端产品,具有跨操作系统特性,以及适合嵌入式产品的小巧、高效的特点。Qt/Embedded属于高端产品,只支持嵌入式Linux操作系统,需要16MB以上的静态存储空间及64MB以上的动态存储空间。
MiniGUI的特点及应用
MiniGUI为实时嵌入式操作系统提供了非常完善的图形及图形用户界面支持。MiniGUI本身的可移植性设计,使得不论在哪个硬件平台、哪种操作系统上运行,MiniGUI均能为上层应用程序提供一致的应用程序编程接口(API)。
作为操作系统和应用程序之间的中间件,MiniGUI将底层操作系统及硬件平台差别隐藏了起来,并对上层应用程序提供了一致的功能特性,这些功能特性包括:
1.完备的多窗口机制和消息传递机制。
2.常用的控件类,包括静态文本框、按钮、单行和多行编辑框、列表框、组合框、进度条、属性页、工具栏、拖动条、树型控件、月历控件等。
3.对话框和消息框支持以及其它GUI元素,包括菜单、加速键、插入符、定时器等。
4.界面皮肤支持。用户可通过皮肤支持获得外观非常华丽的图形界面。
5.通过两种不同的内部软件结构支持低端显示设备(如单色 LCD)和高端显示设备(如彩色显示器),前者小巧灵活,而后者在前者的基础上提供了更加强大的图形功能。
6.Windows的资源文件支持,如位图、图标、光标等。
7.各种流行图像文件的支持,包括JPEG、GIF、PNG、TGA、BMP等等。
8.多字符集和多字体支持,目前支持ISO8859-1~ISO8859-15、GB2312、GBK、GB18030、BIG5、EUC-JP、Shift-JIS、EUC-KR、UNICODE等字符集,支持等宽点阵字体、变宽点阵字体、Qt/Embedded 使用的嵌入式字QPF、TrueType以及Adobe Type1等矢量字体。
9.多种键盘布局的支持。MiniGUI除支持常见的美式PC键盘布局之外,还支持法语、德语等语种的键盘布局。
10.简体中文(GB2312)输入法支持,包括内码、全拼、智能拼音等。用户还可以从飞漫软件获得五笔、自然码等输入法支持。
11.针对嵌入式系统的特殊支持,包括一般性的I/O流操作,字节序相关函数等。
与其它针对嵌入式产品的图形系统相比,MiniGUI具有以下一些技术优势:
1).轻型、占用资源少
MiniGUI本身的占用空间非常小,以嵌入式Linux操作系统为例,MiniGUI的典型存储空间占用情况如下:
1.Linux内核: 300K~500K(由系统需求决定);
2.文件系统:500K~2MB(由系统需求决定);
3.MiniGUI支持库:500K~700K(由编译选项确定);
4.MiniGUI字体、位图等资源:400K(由应用程序确定,可缩小到200K以内);
5.GB2312输入法码表:200K(不是必需的,由应用程序确定);
6.应用程序:1M~2M(由系统决定)。
总体的系统占有空间应该在 2MB到4MB左右。在某些系统上,功能完备的MiniGUI系统本身所占用的空间可进一步缩小到1MB以内。
最新的研发成果表明,MiniGUI能够在CPU主频为30MHz,仅有4M RAM的系统上正常运行(使用uClinux 操作系统),这是其它图形系统,如MicroWindows或者Qt/Embedded所无法达到的。
2)高性能、高可靠性
MiniGUI良好的体系结构及优化的图形接口,可确保最快的图形绘制速度。在设计之初就充分考虑到了实时嵌入式系统的特点,针对多窗口环境下的图形绘制开展了大量的研究及开发,优化了MiniGUI的图形绘制性能及资源占有。MiniGUI在大量实际系统中的应用,尤其在工业控制系统的应用,证明 MiniGUI具有非常好的性能。
3) 可配置性
为满足嵌入式系统千变万化的需求,必须要求GUI系统是可配置的。和Linux内核类似,MiniGUI也实现了大量的编译配置选项,通过这些选项可指定MiniGUI库中包括哪些功能而同时不包括哪些功能。大体说来,可以在如下几个方面对MiniGUI进行定制配置:
1.指定MiniGUI要运行的操作系统;
2.指定生成基于线程的MiniGUI-Threads运行模式还是基于进程的MiniGUI-Lite运行模式,或者只是最简单的MiniGUI-Standalone运行模式;
3.指定要采用老的GAL/GDI接口(低端显示设备)还是新的GAL/GDI接口(高端显示设备);
4.指定需要支持的GAL引擎和IAL引擎,以及引擎相关选项;
5.指定需要支持的字体类型;
6.指定需要支持的字符集;
7.指定需要支持的图像文件格式;
8.指定需要支持的控件类;
9.指定控件的整体风格,是三维风格、平面风格还是手持终端风格。
4) 可伸缩性强
MiniGUI丰富的功能和可配置特性,使得它既可运行于基于龙珠的低端产品中,亦可运行于基于ARM9的高端产品中,并使用MiniGUI的高级控件风格及皮肤界面等技术,创建华丽的用户界面。
5) 跨操作系统支持
理论上,MiniGUI可支持任意一个多任务嵌入式操作系统;实际已支持Linux/uClinux、eCos、uC/OS-II、VxWorks、pSOS、ThreadX等嵌入式操作系统,也可以在Win32平台上运行。同时,在不同操作系统上的MiniGUI,提供完全兼容的API接口。
从最初的数控系统到目前流行的智能手持终端设备,MiniGUI已经在大量产品中得到了应用。MiniGUI最主要的应用领域大致可分为三类:高端手机、PDA类产品;数字媒体及机顶盒类产品;工业仪表及控制系统。
基于MiniGUI的嵌入式系统软件结构
为什么MiniGUI能够在如此众多的嵌入式操作系统上运行?这是因为MiniGUI具有良好的软件架构,通过抽象层将MiniGUI上层和底层操作系统隔离开来。如图2所示,基于MiniGUI的应用程序一般通过 ANSI C库以及MiniGUI自身提供的API来实现自己的功能;MiniGUI中的“可移植层”可将特定操作系统及底层硬件的细节隐藏起来,而上层应用程序则无需关心底层的硬件平台输出和输入设备。
另外,MiniGUI特有的运行模式概念,也为跨操作系统的支持提供了便利。
与Linux这样的类UNIX操作系统相比,一般意义上的传统嵌入式操作系统具有一些特殊性。举例而言,诸如uClinux、uC/OS-II、eCos、VxWorks等操作系统,通常运行在没有内存管理单元的CPU上;这时,往往就没有进程的概念,而只有线程或者任务的概念,这样,GUI系统的运行环境也就大相径庭。因此,为了适合不同的操作系统环境,我们可将MiniGUI配置成三种运行模式:
1.MiniGUI-Threads。运行在MiniGUI-Threads上的程序可以在不同的线程中建立多个窗口,但所有的窗口在一个进程或者地址空间中运行。这种运行模式非常适合于大多数传统意义上的嵌入式操作系统,如uC/OS-II、eCos、VxWorks、pSOS等等。当然,在Linux和uClinux上,MiniGUI也能以MiniGUI-Threads的模式运行。
2. MiniGUI-Lite。与MiniGUI-Threads相反,MiniGUI-Lite上的每个程序是单独的进程,每个进程也可以建立多个窗口。MiniGUI-Lite适合于具有完整UNIX特性的嵌入式操作系统,比如嵌入式Linux。
3. MiniGUI-Standalone。这种运行模式下,MiniGUI能以独立进程的方式运行,既不需要多线程也不需要多进程的支持,这种运行模式适合功能单一的应用场合。例如在一些使用uClinux的嵌入式产品中,因为各种原因而缺少线程支持,这时,就可以使用MiniGUI-Standalone来开发应用软件。
一般而言,MiniGUI-Standalone模式的适应面最广,可以支持几乎所有的操作系统,甚至包括类似DOS这样的操作系统;MiniGUI-Threads模式的适用面次之,可运行在支持多任务的实时嵌入式操作系统,或者具备完整UNIX特性的普通操作系统;MiniGUI-Lite模式的适用面较小,它仅适合于具备完整UNIX特性的普通操作系统。
不论采用哪种运行模式,MiniGUI为上层应用软件提供了最大程度上的一致性;只有少数几个涉及初始化的接口在不同运行模式上有所不同。
MiniGUI在uC/OS-II操作系统上的移植
下面以uC/OS-II操作系统为例,简单介绍MiniGUI到该操作系统上的移植。
uC/OS-II非常简单,只要有一个普通的C编译器,就能完成编译并运行该操作系统,因此,uC/OS-II首先在教学中得到了广泛应用。因为其简单及实时性好的特点,现在也有一些用户开始使用uC/OS-II操作系统开发正式的嵌入式产品。
将MiniGUI移植到uC/OS-II是相对复杂的一项工作。因为uC/OS-II中缺乏象malloc/free甚至是printf/fprintf/sprintf这样的接口,不过,最重要的还是缺乏与POSIX-Threads兼容的接口。为此,我们编写了POSIX-Threads的绕转接口,这些绕转接口兼容于POSIX-Threads。同时,我们还实现了 malloc/free,以及printf/sprintf/fprintf等接口。
因涉及到如此多底层特性的增强和修改,整个系统的调试将是非常困难的。为解决调试问题,我们首先在SkyEye(清华大学陈渝主持的自由软件项目,http://www.skyeye.org)模拟器上运行uC/OS-II操作系统及MiniGUI for uC/OS-II。我们首先使用了MiniGUI内部的Dummy GAL引擎和Dummy/Auto IAL 引擎(这两个引擎分别通过软件方法来模拟实际的输出和输入设备,如LCD显示屏及键盘)来运行MiniGUI的应用程序。尽管我们看不到真实的屏幕输出,但从应用程序在运行过程中打印的输出信息,我们可以看到MiniGUI for uC/OS-II已经正常工作了。接下来的工作就是将MiniGUI for uC/OS-II移植到正式的硬件产品中。
我们在S3C2410开发板上用ADS的armcc编译并测试了MiniGUI的uC/OS-II版本。这次,我们针对这个开发板编写了正式的图形和输入引擎。MiniGUI的所有示例程序都可以在这块开发板上正常运行。