摘要:本文研究了基于Framebuffer的嵌入式GUI的系统实现,包括其体系结构层次的建立、驱动机制的分析、微型客户端/服务器模式的实现,以及基于Framebuffer的GAL与GDI的设计等关键内容。
关键词:嵌入式;GUI;Linux;Framebuffer
0 前言
当前流行的商业化的GUI 系统包括Palm OS、Windows CE和Symbian OS 等。这些GUI 性能出众,一般都提供完整的解决方案,对Java、多媒体的支持较好,使用它们可以很方便地构建自己的嵌入式系统,缩短开发周期。但这些都是商业化产品,使用它们不可避免地要付出昂贵的授权费用,没有公开源代码,用户也不能很自由地定制自己的产品。
Linux 的出现给嵌入式产品的开发带来了新的活力,它拥有很多的优良特性非常适合于嵌入式开发。目前国内外基于Linux的GUI产品比较流行的包括MiniGUI、MicroWindows、QT/Embedded 等,其中QT/Embedded 属于商业化的产品,其他属于开源软件。从性能、功能各个方面来说QT/Embedded 比较优秀,但是使用它需要支付高昂的授权费用,一般应用在高端的PDA 和SmartPhone 等产品上。MiniGUI和MicroWindows均为自由软件,只是前者遵循LGPL条款,后者遵循MPL条款,这两个系统的技术路线也有所不同,MiniGUI的策略是首先建立在比较成熟的图形引擎之上,比如Svgalib和LibGGI,开发的重点在于窗口系统、图形接口之上,而MicroWindows目前的开发重点则在底层的图形引擎之上,窗口系统和图形接口方面的功能还比较欠缺,而且MiniGUI在1.6版本以后也不再提供免费的完整功能版本下载。
FrameBuffer是Linux控制台下的一个通用的图形接口,它拥有良好的平台无关性,可以支持绝大多数的硬件,因而得到愈来愈多厂家的支持,一些流行的图形库如QT、GTK便是基于FrameBuffer的。它的接口非常简单,通过它可以十分方便地构建一个图形系统。而对GUI的实现做一个系统深入的分析和研究也是嵌入式系统研究必不可少的一个步骤。本项目在开发嵌入式数字控制系统的过程中对现有的嵌入式GUI系统做了深入的研究,包括嵌入式GUI的体系结构层次、驱动机制,并实现了对自身量身定做的GAL和GDL,实现了满足自身需求的嵌入式GUI系统。
1嵌入式GUI需求分析
与运行在PC 机上的GUI相比,作为运行在嵌入式设备上的程序,不可避免的要受到设备环境的限制,其实这也是所有嵌入式编程都要遇到的问题。嵌入式设备对GUI 的限制主要体现在:(1) CPU速度相对来说较慢,一般不具备浮点运算功能或浮点运算功能较弱;(2)内存、外存容量小;(3)电量有限需要考虑节电因素。
同时,嵌入式平台具有多样性,不同的平台之间性能、功能部件千差万别,很难设计出一个GUI产品能够适合任何平台,因此就必需对GUI产品进行准确的定位,包括所要运行的平台、最终用户的需求等等,它是产品成功的关键,也决定了我们的设计方针和思想,比如实时和非实时产品的设计是完全不同的。这里我们设计的GUI 系统是为中低端嵌入式系统提供图形界面能力的中间件产品,它应该能满足以Linux OS 作为产品系统平台的中低端客户对图形用户界面开发的要求,并易于第三方应用程序的移植。具体来说,其运行在CPU 主频不高于400MHz(实际使用200MHz),内存容量在64MB(实际使用16M)以下的中低端嵌入式系统,兼容POSIX标准的操作系统,拥有完整或经过裁减的C库。
在设计的时候要充分考虑到这些因素,在编程时也要注意一些原则:尽量让CPU少做事,尽量不进行浮点运算,尽量减少文件操作,尽量减少内存分配。
2 基于Linux的嵌入式GUI构建
2.1 嵌入式GUI的体系结构层次
嵌入式GUI的实现一般要划分成四大功能模块:GUI用户接口模块、GUI对象模块、GUI基本图形模块和GUI消息驱动模块。具体功能定义如下:
1)GUI用户接口模块 该模块为上层应用软件开发人员提供方便、易用的API接口函数,对上层开发人员屏蔽了GUI的设备实现细节,让开发人员很简单的就可以编写出良好的图形用户界面的应用程序。
2)GUI对象模块 GUI对象模块对窗口环境中的逻辑对象进行组织管理。其中包括对象的添加、删除引发的对象链表的更新,以及GUI窗口显示的维护,如窗口切换、焦点切换、对象的隐藏和恢复等操作引发的对象属性的更新,还有对不同控件的各种事件的响应。
3)GUI基本图形模块 在该模块中实现了对显示输出设备的操作,如画点、画线、画矩形等基本功能,还有对于字符的解析输出,以及对图形的解析输出。一般它独立于具体的设备驱动程序,与物理设备之间形成“设备抽象层”。
4)GUI消息驱动模块 该模块是GUI系统的通讯模块,负责GUI的消息接收和与其它任务的通讯以及消息队列的维护。
我们在自我裁减的Linux操作系统基础上具体实现了一个轻量级的嵌入式GUI系统,在C语言中,采用了类似于面向对象的技术,同时将GUI系统的核心模块设计的尽量小巧,便于测试。GUI系统内核对GUI特性和使用环境进行了高度抽象,为了增加GUI系统的可移植性和可扩展性,本系统将与特定设备相关的功能全部分装到了独立的函数之中,如果要移植到其它不同的设备上去,只需要把这些与特点设备相关的函数部分重写即可达到目的。本GUI系统采用的垂直分层的系统结构图如下:
图1、嵌入式GUI系统结构图
用户和嵌入式系统交互的过程即是用户通过输入设备操作GUI的应用程序,GUI系统在接到用户对该输入事件的处理消息之后,将处理后的结果显示在输出设备上。因此GUI系统涉及的主要技术有事件驱动、输出显示、资源管理。其中事件驱动是GUI系统的核心,输出显示是GUI的关键,资源管理是GUI系统的基础。
2.2 嵌入式GUI的驱动机制分析
GUI系统的事件驱动机制主要是消息驱动机制。从消息机制方面来说,本GUI系统可以划分为三个子系统:图形处理子系统,输入设备子系统和输出设备子系统,各子系统以图形处理子系统为核心,既相对独立又彼此联系。
所谓消息有两层含义:1、消息发生的时间(事件,动态概念):2、消息内容(信息,静态概念)。消息发生触发一个事件,用以主动通知信息的到来。系统中消息发生时间是随机的,由操作系统异步捕获此事件,再分发给对应的处理程序。程序起着信息处理的作用,而消息则代表到达的信息。对于可以事先判定信息的种类范围,而不能事先预测信息到达时间的情况,有两种处理方法:被动轮询和主动通知。消息属于主动通知一类。利用消息驱动计算机输入的机制,显得自然、简洁。
消息处理机制包括消息的产生、传递(发送和接收)和处理等过程。消息作为一种任务、程序、系统等应用之间的信息和数据联系,它可以由硬件事件产生,也可以由其它任务、程序、系统等应用中产生,并将它们发到其它应用中,以控制应用的行为。
本GUI系统的消息处理机制如图2所示。
图2、系统的消息处理机制图
采用这种消息机制后,模块之间形成完全松散的耦合关系,增加了整个连接和集成的灵活性,这是通过消息和响应的非直接、隐式调用实现的。
选用这种消息机制作为嵌入式GUI系统的设计,正好适合了嵌入式系统本身要求可以配置、裁剪的特点。嵌入式GUI本身只需要维持一个消息处理机即可,可以大大增加系统的可移植性。采用这种消息机制,只需要重新定义消息和响应处理,GUI系统中的任何控件都可以简单地替换为另一个控件,这一特点可以满足GUI系统本身要求的可扩展性,用户可以根据自己的要求对控件进行修改、定制和扩展GUI系统的界面风格。
对于激励和响应之间没有严格的时间逻辑关系的系统,消息是一种非常好的控制机制。消息机制完全可以满足嵌入式GUI的调度要求。
2.3 微型客户端/服务器模式的实现
从系统整体角度看,根据是否采用多进程C/S 机制和服务程序的具体功能,基本可以将Linux 下的嵌入式GUI 划分为类X GUI 和非X GUI 两大类。
图3、类X GUI的系统C/S交互机制示意图
是否采用C/S客户服务机制,决定于用户的设计需求和实时性考虑。当实时能力能够得到满足时,类X的GUI在系统健壮性和功能完备性上要大大超过非X的GUI。非X GUI往往采用单进程多线程,所有数据和操作共享同一内存区域,当某个线程出现错误时容易造成整个进程瘫痪,因此用于复杂场合的成熟的GUI大多数都采用类X GUI多进程多客户单服务的机制。由于类X的嵌入式GUI具有应用普遍性,我们采用了类X GUI客户服务结构模式。
X GUI的原理是借鉴X Window的客户服务机制,采用了事件驱动的设计方法。应用程序在客户端,输入接口在服务器端,应用程序通过和服务器通讯间接和输入输出硬件设备交互。如图3是系统的类X GUI的系统C/S交互机制示意图
客户程序向服务器程序提交感兴趣的事件或要阻止的事件请求,服务器主程序启动循环收集事件(包括输入设备上的事件),由输入引擎接口上的系统调用来接收输入设备事件。将客户感兴趣的事件发送给客户程序,客户程序处理后再向服务器程序提交图形绘制和其它操作请求。两者之间通过IPC或socket连接的办法来传送事件和请求。
3 基于Framebuffer的GAL与GDI的设计
FrameBuffer是出现在2.2.xx内核当中的一种驱动程序接口。这种接口将显示设备抽象为帧缓冲区。用户可以将它看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。该驱动程序的设备文件一般是/dev/fb0,/dev/fbl等等。在应用程序中,一般通过将FrameBuffer设备映射到进程地址空间的方式使用。FrameBuffer设备还提供了若干ioctl命令,通过这些命令,可以获得显示设备的一些固定信息(比如显示内存大小)、与显示模式相关的可变信息(比如分辨率、象素结构、每扫描线的字节宽度),以及伪彩色模式下的调色板信息等等。通过FrameBuffer设备,还可以获得当前内核所支持的加速显示卡的类型(通过固定信息得到),这种类型通常是和特定显示芯片相关的
研究中我们发现,虽然己有的几种嵌入式GUI库在窗口管理、消息机制等应用层的实现各不相同;但为了便于移植的特性,都有相似的设备驱动层设计。
一个能够移植到多种硬件平台上的嵌入式GUI库,应用至少抽象出两类设备:基于图形显示设备(如VGA卡)的图形抽象层GAL ( Graphic Abstract Layer );基于输入设备(如键盘,触摸层等)的输入抽象层IAL ( Input Abstract Layer )。GAL层完成系统对具体的显示硬件设备的操作,极大程度上隐蔽各种不同硬件的技术实现细节,为程序开发人员提供统一的图形编程接口。先进的嵌入式GUI,比如MicroWindows和MiniGUI,都支持Framebuffer。
因为MicroWindows的GAL层代码量小,结构清晰而且模块性好,非常方便修改和扩充。因此我们借鉴MicroWindows的设备抽象层构建,实现需要在文件中包含src/include/device.h和src/include/mwtypes.h头文件。前者包含对MicroWindows底层调用函数接口的声明,后者包含MicroWindows中特定结构的定义和一些宏定义。
GDI对象对于GUI系统来说是一个很重要的概念,它可以提供给用户更加灵活的操作方式,所以本GUI系统实现了类似于Windows下的GDI系统,不像有些GUI系统,放弃了GDI对象概念,窗口层直接跟绘图层交互,导致用户操作起来不灵活,这样设计也容易在遵循嵌入式软件平台API标准的前提下与Windows的图形用户接口相兼容。系统GDI提供了设备上下文(Device Context)操作、基本GDI对象操作〔包括画笔、画刷、字体、位图、区域、填充等),还有映射模式、背景模式和光栅操作。尽管系统GDI吸取了Windows GDI的一些概念和设计方法,但其作为嵌入式GUI系统的一部分,特别针对嵌入式环境的特点,取消了一些不常用的、影响效率的功能,充分挖掘GDI层的性能。由于硬件抽象层提供的图形操作接口只有一个Surface,所以所有的基本图形绘制及操作都需要GDI实现,所以提高GDI性能的重点是好的图形学算法。本系统GDI对原有的组成元素做了一些取舍,其组成元素如表1所示:
表1、系统GDI组成元素表
设备上下文 |
GDI对象 |
绘图属性 |
位图操作 |
字体 |
DC |
画笔、画刷 |
光栅、背景模式、坐标模式 |
DIB、DDB |
点阵、True Type |
4 结束语
本文研究了基于Framebuffer的嵌入式GUI的系统实现,包括其体系结构层次的建立、驱动机制的分析、微型客户端/服务器模式的实现,以及基于Framebuffer的GAL与GDI的设计等关键内容,提供了除现行流行方案外的嵌入式GUI的解决方案,并可根据自己系统需求量身定做,在实际项目实施中获得了很好的效果。
作者简介:赵霞 (1968-)女(汉族),河北人,高级讲师,硕士,新侨职业技术学院计算机信息系.主要研究领域:计算机应用与软件研究.
Biography:Zhao Xia(1968-), Female(Han), Senior instructor, Master, Department of computer, Xinqiao Professional Technological Institute. Research area: Research on computer application and software development.
参考文献:
[1]王田苗.嵌入式系统设计与实例分析.清华大学出版社,2003年10月第二版.
[2]王同洋,熊伟,嵌入式Linux中图形用户界面的研究与设计.微计算机信息,2006, (08),90-92
[3]张娟,张雪兰.基于嵌入式Linux的GUI应用程序的实现.计算机应用,2003 (04):116-117