Qt/Embedded在嵌入式Linux系统中的应用(ARM)

2019-07-12 15:44发布

Qt/Embedded在嵌入式Linux系统中的应用

摘要:分析和讨论Qt/Embedded的主流版本3.x系列的底层实现技术;结合2.x版本系列和3.x版本系列,在两种不同的硬件平台(Intel PXA255开发系统与笔者自行设计的Motorola MC9328 MX1开发系统)上的移植过程,讨论Qt/Embedded的底层设备接口与应用移植技术。 关键词:Qt/嵌入式Linux framebuffer 驱动接口   引言 随着嵌入式Linux应用的不断发展,嵌入式处理器运算能力的不断增强,越来越多的嵌入式设备开始采用较为复杂的GUI系统,手持设备中的GUI系统发展得非常迅速。传统的GUI系统,如Microwindows等,由于项目规模较小、功能较为薄弱,缺乏等三方软件开发的支持等诸多原因,在比较高级的手持或移动终端设备(如PDASmart-Phone、车载导航系统)中应用较少。 Qt/Embedded是著名的Qt库开发商Trolltech公司开发的面向嵌入式系统的Qt版本,开发人员多为KDE项目的核心开发人员。许多基于QtX Window程序可以非常方便地移植到Qt/Embedded上,与X11版本的Qt在最大程度上接口兼容,延续了在X上的强大功能,在底层彻底摒弃了X lib,仅采用framebuffer作为底层图形接口。Qt/Embedded类库完全采用C++封装。丰富的控件资源和较好的可移植性是Qt/Embedded最为优秀的一方面,使用X下的开发工具Qt Designer可以直接开发基于Qt/EmbeddedUI(用户操作接口)界面。越来越多的第三方软件公司也开始采用Qt/Embedded开发嵌入式Linux下的应用软件。其中非常著名的Qt Palmtop EnvironmentQtopia)早期是一个第三方的开源项目,并已经成功应用于多款高档PDATrolltech公司针对Smart-Phone中的应用需求,于20045月底发布了QtopiaPhone版本。 1 Qt/Embedded的实现技术基础分析 横向来看,由于发布的版权问题,Qt/Embedded采用两种方式进行发布:在GPL协议下发布的free版与专门针对商业应用的commercial版本。二者除了发布方式外,在源码上没有任何区别。纵向看来,当前主流的版本为Qtopia2.x系列与最新的3.0x系列。其中2.0版本系统较多地应用于采用Qtopia作为高档PDA主界面的应用中;3.x版本系列则应用于功能相对单一,但需要高级GUI图形支持的场合,如Volvo公司的远程公交信息系统。图1Qt/Embedded的实现结构。   3.x版本系列的Qt/Embedded相对于2.x版本系统增加了许多新的模块,如SQL数据库查询模块等。几乎所有2.x版本中原有的类库,在3.x版本中都得到极大程度的增强。这就极大地缩短了应用软件的开发时间,扩大了Qt/Embedded的应用范围。 在代码设计上,Qt/Embedded巧妙地利用了C++独有的机制,如继承、多态、模板等,具体实现非常灵活。但其底层代码由于追求与多种系统、多种硬件的兼容,代码补丁较多,风格稍显混乱。 11 Qt/Embedded的图形引擎实现基础 Qt/Embedded的底层图形引擎基于framebufferFramebuffer是在Linux内核架构版本2.2以后推出的标准显示设备驱动接口。采用mmap系统调用,可以将framebuffer的显示缓存映射为可连续访问的一段内存储针。由于目前比较高级的ARM体系的嵌入式CPU中大多集成了LCD控制模块,LCD控制模块一般采用双DMA控制器组成的专用DMA通道。其中一个DMA可以自动从一个数据结构队列中取出并装入新的参数,直到整个队列中的DMA操作都已完成为止。另外一个DMA与画面缓冲区相关,这部分由两个DMA控制器交替执行,并每次都自动按照预定的规则改变参数。虽然使用了双DMA,但这两个DMA控制器的交替使用对于CPU来说是不可见的。CPU所获得的只是由两个DMA组成的一个通道而已。 Framebuffer驱动程序的实现分为两个方面:一方面是对LCD及其相关部分的初始化,包括画在缓冲区的创建和对DMA通道的设置;另外一方面是对画面缓冲区的读写,具体到代码为readwritelseek等系统调用接口。至于将画面缓冲区的内容输出到LCD显示屏上,则由硬件自动完成。对于软件来说是透明的。当对于DMA通道和画面缓冲区设置完成后,DMA开始正常工作,并将缓冲区中的内容不断发送到LCD上。这个过程是基于DMA对于LCD的不断刷新的。基于该特性,framebuffer驱动程序必须将画面缓冲区的存储空间(物理空间)重新映射到一个不加高缓存和写缓存的虚拟地址区间中,这样能才保证应用程序通过mmap将该缓存映射到用户空间后,对于该画面缓存的写操作能够实时的体现在LCD上。 Qt/Embedded中,Qscreen类为抽象出的底层显示设备基类,其中声明了对于显示设备的基本描述和操作方式,如打开、关闭、获得显示能力、创建GFX操作对象等。另外一个重要的基类是QGfx类。该类抽象出对于显示设备的具体操作接口(图形设备环境),如选择画刷、画线、画矩形、alpha操作等。以上两个基类是Qt/Embedded图形引擎的底层抽象。其中所有具体函数基本都是虚函数,Qt/Embedded对于具体的显示设备,如LinuxframebufferQt Virtual Framebuffer做的抽象接口类全都由此继承并重载基类中的虚函数实现。图2Qt/Embedded中底层图形引擎实现结构。 在图2中,对于基本的framebuffer设备,Qt/EmbeddedQlinuxFbScreen来处理。针对具体显示硬件(如Mach卡、Voodoo卡)的加速特性,Qt/EmbeddedQlinuxFbScreen和图形设备环境模板类QgfxRaster继承出相应子类,并针对相应硬件重载相关虚函数。   Qt/Embedded在体系上为C/S结构,任何一个Qt/Embedded程序都可以作为系统中唯一的一个GUI Server存在。当应用程序首次以系统GUI Server的方式加载时,将建立QWSServer实体。此时调用QWSServer::openDisplay()函数创建窗体,在QWSServer::openDisplay()中对QWSDisplay::Data中的init()加以调用;根据QgfxDriverFactory实体中的定义(QLinuxFbScreen)设置关键的Qscreen指针qt_screen并调用connect()打开显示设备(dev/fb0)。在QWSServer中所有对于显示设备的调用都由qt_screen发起。至此完成了Qt/EmbeddedQWSServer的图形发生引擎的创建。当系统中建立好GUI Server后,其它需要运行的Qt/Embedded程序在加载后采用共享内存及有名管道的进程通信方式,以同步访问模式获得对共享资源framebuffer设备的访问权。 1.2 Qt/Embedded的事件驱动基础 Qt/Embedded中与用户输入事件相关的信号,是建立在对底层输入设备的接口调用之上的。Qt/Embedded中的输入设备,分为鼠标类与键盘类。以3.x版本系列为例,其中鼠标设备的抽象基类为QWSMouse Handler,从该类又重新派生出一些具体的鼠标类设备的实现类。该版本系列的Qt/Embedded中,鼠标类设备的派生结构如图3所示。 与图形发生引擎加载方式类似的,在系统加载构造QWSServer时,调用QWSServer::openMouseQWSServer::openKeyboard函数。这两个函数分别调用QmouseDriverFactory::create()QkbdDriverFactory::create()函数。这时会根据Linux系统的环境变量QWS_MOUSE_PROTOQWS_KEYBOARD获得鼠标类设备和键盘类设备的设备类型和设备节点。打开相应设备并返回相应设备的基类句柄指针给系统,系统通过将该基类指令强制转换为对应的具体子类设备指针,获得对具体鼠标类设备和键盘类设备的调用操作。 值得注意的是,虽然几乎鼠标类设备的功能上基本一致,但由于触摸屏和鼠标底层接口并不一样,会造成对上层接口的不一致。举例来讲,从鼠标驱动接口中几乎不会得到绝对位置信息,一般只会读到相对移动量。另外,鼠标的移动速度也需要考虑在内,而触摸屏接口则几乎是清一 {MOD}的绝对位置信息和压力信息。针对此类差别,Qt/Embedded将同一类设备的接口部分也给予区别和抽象,具体实现在QmouseDriverInterface类中。键盘类设备也存在类似问题,同样引入了QkbdDriver Inteface来解决。具体实现此处暂不多述。 2 Qt/Embedded的移植与应用 针对Qt/Embedded的实现特点,移植该嵌入式GUI系统一般分为以下几个步骤: 设计硬件开发平台,并移植Linux操作系统; 采用静态链接进Linux内核的方式,根据该平台显示设备的显示能力,开发framebuffer驱动程序; 开发针对该平台的鼠标类设备驱动程序,一般为触摸屏或USB鼠标; 开发针对该平台的键盘类设备驱动程序,一般为板载按钮或USB键盘(该部分可选); 根据framebuffer驱动程序接口,选择并修改Qt/Embedded中的QlinuxFbScreenQgfxRaster类; 根据鼠标类设备驱动程序,实现该类设备在Qt/Embedded中的操作接口; 根据键盘类设备驱动程序,实现该类设备在Qt/Embedded中的操作接口(该部分可选); 根据需要选择Qt/Embedded的配置选项,交叉编译Qt/Embedded的动态库; 交叉编译Qt/Embedded中的Example测试程序,在目标平台上运行测试。 Framebuffer设备驱动程序提供出的接口是标准的,除了注意endian问题外,配置Qt/Embedded时选择相应的 {MOD}彩深度支持即可,因此该部分的移植难点就在于framebuffer驱动程序的实现。Qt/Embedded部分的QWSServer打开/dev/中的framebuffer设备后读出相应的显示能力(屏幕尺寸、显示 {MOD}彩深度),模板QgfxRaster将根据 {MOD}彩深度在用户空间设备创建出与显示缓存同样大小的缓冲作为双缓冲,并采用正确方式进行显示。     2.1 PXA255平台上移植和应用 在笔者参与设计的某Smart-Phone开发平台中,GUI系统实现方案采用了Qt/Embedded 2.3.7Qtopia 1.7.0(基于Qt/Embedded 2.x系列的手持套件),硬件平台采用了基于Intel XScale PXA255处理器的嵌入式开发系统。该开发系统采用640×480分辨率的TFT LCDPXA255内部LCD