Linux嵌入式技术
Linux嵌入式技术(精选10篇)
Linux嵌入式技术 第1篇
这种解决问题所需时间呈上升的趋势固然有软件问题,但缺乏必要的手段以辅助解决问题才是主要的原因。通过对故障的统计跟踪发现,难以解决的软件错误和从发现到解决耗时较长的软件错误都集中在操作系统的核心部分,这其中又有很大比例集中在驱动程序部分[2]。因此,错误跟踪技术被看成是提高系统安全完整性等级的一个重要措施[1],大多数现代操作系统均为发展提供了操作系统内核“崩溃转储”机制,即在软件系统宕机时,将内存内容保存到磁盘[3],或者通过网络发送到故障服务器[3],或者直接启动内核调试器[4]等,以供事后分析改进。
基于Linux操作系统内核的崩溃转储机制近年来有以下几种:
(1) LKCD (Linux Kernel Crash Dump)机制[3];
(2)KDUMP(Linux Kernel Dump)机制[4];
(3)KDB机制[5];
(4)KGDB机制[6]。
综合上述几种机制可以发现,这四种机制之间有以下三个共同点:
(1)适用于为运算资源丰富、存储空间充足的应用场合;
(2)发生系统崩溃后恢复时间无严格要求;
(3)主要针对较通用的硬件平台,如X86平台。
在嵌入式应用场合想要直接使用上列机制中的某一种,却遇到以下三个难点无法解决:
(1)存储空间不足
嵌入式系统一般采用Flash作为存储器,而Flash容量有限,且可能远远小于嵌入式系统中的内存容量。因此将全部内存内容保存到Flash不可行。
(2)记录时间要求尽量短
嵌入式系统一般有复位响应时间尽量短的要求,有的嵌入式操作系统复位重启时间不超过2s,而上述几种可用于Linux系统的内核崩溃转储机制耗时均不可能在30s内。写Flash的操作也很耗时间,实验显示,写2MB数据到Flash耗时达到400ms之多。
(3)要求能够支持特定的硬件平台
嵌入式系统的硬件多种多样,上面提到的四种机制均是针对X86平台提供了较好的支持,而对于其他体系的硬件支持均不成熟。
由于这些难点的存在,要将上述四种内核崩溃转储机制中的一种移植到特定的嵌入式应用平台是十分困难的。因此,针对上述嵌入式系统的三个特点,本文介绍一种基于特定平台的嵌入式Linux内核崩溃信息记录机制LCRT (Linux Crash Record and Trace),为定位嵌入式Linux系统中软件故障和解决软件故障提供辅助手段。
1 Linux内核崩溃的分析
分析Linux内核对于运行期间各种“陷阱”的处理可以得知,Linux内核对于应用程序导致的错误可以予以监控,在应用程序发生除零、内存访问越界、缓冲区溢出等错误时,Linux内核的异常处理例程可以对这些由应用程序引起的异常情况予以处理。当应用程序产生不可恢复的错误时,Linux内核可以仅仅终止产生错误的应用程序,其他应用程序仍然可以正常运行。
如果Linux内核本身或者新开发的Linux内核模块存在bug,产生了“除零”,“内存访问越界”、“缓冲区溢出”等错误,同样会由Linux内核的异常处理例程来处理。Linux内核通过在异常处理程序中判断,如果发现是“严重的不可恢复”的内核异常,则会导致“内核恐慌”(kernel panic),即Linux内核崩溃。图1所示为Linux内核对异常情况的处理流程。
2 LCRT机制的设计与实现
通过对Linux内核代码的分析可知,Linux内核本身提供了一种“内核通知机制”[7,8],并预定义了“内核事件通知链”,使得Linux内核扩展开发人员可以通过这些预定义的内核事件通知链在特定的内核事件发生时执行附加的处理流程。通过对Linux内核源代码的研究发现,对于上文中提到的“严重不可恢复的内核异常”,预定义了一个通知链和通知点,使得在发生Linux内核崩溃之后,可以在Linux内核的panic函数中预定义的一个“内核崩溃通知链”[7]上挂接LCRT机制来获得Linux内核崩溃现场的一些信息并记录到非易失性存储器中,以便分析引起Linux内核崩溃的原因。
2.1 设计要点
LCRT机制的设计和实现基于如下特定的机制:
(1)编译器选项与内核依赖
Linux内核及相应的驱动程序都采用GNU[9]的开源编译器GCC[9]编译,为了结合LCRT机制方便地提取信息和记录信息,需要采用特定的GCC编译器选项来编译Linux内核和相关的驱动程序以及应用程序。用到的选项为:-mpoke-function-name[9]。使用这个选项编译出的二进制程序中可以包含C语言函数名称的信息,以方便函数调用链回溯时记录信息的可读性。
(2) Linux内核notify_chain机制[8]
Linux内核提供“通知链”功能,并预定义了一个内核崩溃通知链,在Linux内核的异常处理例程中判断出系统进入“不可恢复”状态时,会沿预定义的通知链顺序调用注册到相应链中的通知函数。
(3)函数调用的栈布局
Linux内核的绝大部分由C语言实现,而且C语言也多用来进行Linux内核开发。Linux内核及使用LKM扩展而加入Linux内核执行环境的代码是有规律可循的,这些代码在执行过程中产生的栈布局和这些规律的代码相关联。例如,这些函数在执行函数之前会保存本函数调用后的返回地址、本函数被调用时传递过来的参数及调用本函数的函数所拥有的栈帧的栈底。
2.2 LCRT机制的设计思想
LCRT机制分为Linux内核模块[8]部分和Linux用户程序部分。内核模块部分的设计采用了Linux内核模块的模式而不是直接修改Linux内核。这样的设计降低了Linux内核和LCRT机制之间的耦合度,同时满足了Linux内核和LCRT机制独立升级完善的便利性。用户程序部分完成从非易失性存储器中读取、清除LCRT机制保存的信息等相关功能。
在LC RT机制的设计中,针对嵌入式系统的特点,其设计决策有:
(1)将对于解决和定位问题最具辅助意义的函数调用关系链记录下来。
(2)为了不占用过多的存储空间,有选择性地将函数调用序列上的函数各自用到的栈内容保存起来,而不是保存全部内容。
(3)将记录的信息保存到非易失性存储器中,这样既达到了掉电保存的目的、又缩短了写入时间。
LCRT机制的设计包括以下五个方面。
(1)设计Linux内核模块、动态地加载LCRT机制、尽量少地修改Linux内核代码。
(2)在相应、预定义的Linux内核通知链上挂接LCRT的通知函数。
(3)在LCRT机制的通知处理函数中进行堆栈回溯得到函数调用信息。
(4)记录回溯到的函数调用信息和堆栈空间内容到非易失性存储器。
(5)开发用户空间的工具,可以从非易失性存储器中读取保存的信息。
2.3 LCRT机制的实现
LCRT机制的实现可参照2.2节的设计思想,分步予以实现。限于篇幅,本文不过多涉及Linux内核模块的原理和实现相关的细节,仅仅给出LCRT机制的内核模块实现伪代码。用伪代码描述LCRT机制的加载函数如下:
LCRT机制的通知处理函数完成函数调用关系回溯、得到函数名称、函数栈内容等工作,限于篇幅,在这里用下面伪代码说明:
3 验证评估LCRT机制
3.1 部署LCRT机制
部署LCRT机制,使LCRT机制发挥作用前需要做的相关工作有:
(1)针对目标Linux内核编译LCRT机制的Linux内核模块部分;
(2)将LCRT机制的内核模块部分载入Linux内核。
3.2 实验结果
为了实验LCRT机制的作用效果,构造一个会造成Linux内核崩溃的设备驱动模块,记这个内核驱动模块为bugguy.ko,列出如下所示的bugguy.ko中会引起Linux内核崩溃的代码如下所示:
说明:用黑体标出的代码即为产生bug的代码
从上面的代码可以看出,这个错误是对空指针进行解析而造成的。在一个中断处理函数中如果发生对空指针的解析,将会引起Linux内核的崩溃。在部署完成LCRT机制的嵌入式linux系统上将这个bugguy.ko载入Linux内核,使得会引起Linux内核崩溃的中断处理程序得以运行,LCRT机制可以将相关的信息保存到非易失性存储器中,在系统复位后,通过LCRT机制的用户空间工具,可以将保存的信息读取出来。实验结果显示,可以得到如图2所示的函数调用链信息。
图2标注即为会引起Linux内核崩溃的错误代码的中断处理函数即真正引起系统宕机的“罪魁祸首”。而记录下的所有信息仅仅占用了不到1KB的存储空间,写入非易失性存储器所耗用的时间控制在50ms以内。在使用少量空间和少量时间的情况下,所记录下的信息对于查找问题和解决问题都有较大的帮助。
实验结果表明,在LCRT机制的作用下,可以快速地定位到嵌入式Linux系统中隐藏的可能会导致系统宕机的软件缺陷。这就为后续的故障解决和软件完善提供了关键的辅助信息。对嵌入式Linux内核而言,即是为提高Linux内核的稳定性和可靠性提供了帮助。
在基于ARM的嵌入式Linux应用中,开发LCRT机制来记录系统内核发生崩溃时引起崩溃的函数调用链和栈信息到非易失性存储器中,截至目前为止,LCRT机制可以记录基于ARM的嵌入式Linux内核发生崩溃时的函数调用链信息,可直接得到函数名称、函数调用链中单个函数被调用时的参数信息以及函数调用链中的函数各自的栈帧信息。这些记录下来的信息对于完善和发展基于ARM的嵌入式Linux应用具有重要的辅助意义。
摘要:介绍了一种精简的内核崩溃信息记录技术,该技术保存函数调用链并有选择地记录函数栈内容。记录下的内容可有效地分析定位问题,精简的记录存储可满足复位后快速重启的要求。
关键词:Linux内核,崩溃转储,嵌入式系统
参考文献
[1] IEC international 61508-1 standard functional safety of electrical/electronic/programmable electronic safety-related systems-Part 1:General requirements,1998.
[2] SWIFT M M,BERSHAD B N,LEVY H M.Improving the reliability of commodity operating systems[OL].http://nooks.cs.washington.edu/nooks-tocs.pdf,2005.
[3] IBM Global Services,Linux education.LKCD installation and configuration[OL].http:/lkcd.sourceforge.net/doc/lkcd_tutorial.pdf,2006.
[4] GOYAL V,BIEDERMAN E W,KDUMP H N.A kexecbased kernel crash dumping mechanism [OL].http://lse.sourceforge.net/kdump/documentation/ols2oo5-kdump-paper.pdf,2005.
[5] CORBET J,RUBINI A,HARTMAN G K.Linux device drivers,Third Edition[M].魏永明译.北京:中国电力出版社,2005.
[6] LinSysSoft Technologies Pvt.Ltd.KGDB Documentation[OL].http://kgdb.linsyssoft.com/downloads/kgdb-2/kgdb_docu_full-2. 4. pdf,2006.
[7] YAGBMOUR K.构建嵌入式 Linux 系统[M].北京:中国电力出版社,2004.
[8] RODRIGUEZ C S,FISCHER G,SMOLSKI S.Linux 内核编程必读(英文版)[M].北京:机械工业出版社,2006.
Linux嵌入式技术 第2篇
摘要:分析了Linux的实时性,针对其在实时应用中的技术障碍,在参考了与此相关研究基础上,从三方面提出了改善Linux实时性能的改进措施。为提高嵌入式应用响应时间精度,提出两种细化Linux时钟粒度方法;为增强系统内核对实时任务的响应能力,采用插入抢占点和修改内核法增强Linux内核的可抢占性;为保证硬实时任务的时限要求,把原Linux的单运行队列改为双运行队列,硬实时任务单独被放在一个队列中,并采用MLF调度算法代替原内核的FIFO调度算法。
关键词:Linux;实时性;调度策略;抢占 1 引言
目前,无论是在日常生活,还是在工业控制,航空航天,军事等方面,嵌入式系统都有着非常广泛的应用。嵌入式系统目前主要有:Windows CE、VxWorks、QNX等,它们都具有较好的实时性、系统可靠性、任务处理随机性等优点,但是它们的价格普遍偏高。而嵌入式Linux以其非常低廉的价格,可以大大的降低成本,逐渐成为嵌入式操作系统的首选。但是,作为通用操作系统的Linux,由于其在实时应用领域的技术障碍,要应用在嵌入式领域,还必须对Linux内核作必要的改进。许多嵌入式设备都要求与外部环境有硬实时的交互能力,将最初按照分时系统目标设计的Linux 改造成能支持硬实时性的操作系统显得十分重要。幸运的是, Linux 及其相关项目的开放源码特征为深入研究其内核并加以改造提供了可行性, 可以修改Linux 内核中的各个模块以达到满足嵌入式应用的需求,提高软件方面的开发速度。目前,改善Linux内核的设计与实现,使其适用于实时领域吸引了许多研究和开发人员的注意力[1-4]。常用的实时性改造方法是采用双核方法,这种方法的弊端在于实时任务的开发是直接面向提供精确实时服务的小实时核心的,而不是功能强大的常规Linux核心。基于此,近年来修改核的方法越来越受到科研人员的重视,这种方法是基于已有Linux系统对于软件开发的支持,进行源代码级修改而使Linux变成一个真正的实时操作系统。本文分析了标准Linux在实时应用中的技术障碍,参考了修改核方法的思想,从内核时钟管理、内核的抢占性、内核调度算法三方面论述了改善标准Linux实时性能的方法。2 Linux 在实时应用中的技术障碍 2.1 Linux的实时性分析
Linux作为一个通用操作系统,主要考虑的是调度的公平性和吞吐量等指标。然而,在实时方面它还不能很好地满足实时系统方面的需要,其本身仅仅提供了一些实时处理的支持,这包括支持大部分POSIX标准中的实时功能,支持多任务、多线程,具有丰富的通信机制等;同时也提供了符合POSIX标准的调度策略,包括FIFO调度策略、时间片轮转调度策略和静态优先级抢占式调度策略。Linux区分实时进程和普通进程,并采用不同的调度策略。为了同时支持实时和非实时两种进程,Linux的调度策略简单讲就是优先级加上时间片。当系统中有实时进程到来时,系统赋予它最高的优先级。体现在实时性上,Linux采用了两种简单的调度策略,即先来先服务调度(SCHED-FIFO)和时间片轮转调度(SCHED-RR)。具体是将所有处于运行状态的任务挂接在一个run-queue 队列中,并将任务分成实时和非实时
用心
爱心
专心 任务,对不同的任务,在其任务控制块task-struct中用一个policy属性来确定其调度策略。对实时性要求较严的硬实时任务采用SCHED-FIFO调度,使之在一次调度后运行完毕。对普通非实时进程,Linux采用基于优先级的轮转策略。2.2 Linux在实时应用中的技术障碍
尽管Linux本身提供了一些支持实时性的机制,然而,由于Linux系统是以高的吞吐量和公平性为追求目标,基本上没有考虑实时应用所要满足的时间约束,它只是提供了一些相对简单的任务调度策略。因此,实时性问题是将Linux应用于嵌入式系统开发的一大障碍,无法在硬实时系统中得到应用。Linux在实时应用中的技术障碍具体表现在:(1)Linux系统时钟精度太过粗糙,时钟中断周期为10ms,使得其时间粒度过大,加大了任务响应延迟。
(2)Linux的内核是不可抢占的, 当一个任务通过系统调用进入内核态运行时,一个具有更高优先级的进程,只有等待处于核心态的系统调用返回后方能执行,这将导致优先级逆转。实时任务执行时间的不确定性,显然不能满足硬实时应用的要求。
(3)Linux采用对临界区操作时屏蔽中断的方式,在中断处理中是不允许进行任务调度的,从而抑制了系统及时响应外部操作的能力。(4)缺乏有效的实时任务调度机制和调度算法。
针对这些问题,利用Linux作为底层操作系统,必须增强其内核的实时性能,从而构建出一个具有实时处理能力的嵌入式系统,适应嵌入式领域应用的需要。2.3 当前增强Linux内核实时性的主流技术
近年来,人们对于Linux内核实时性改造提出了一些方法和设想,它们采用了不同的思路和技术方案。归纳总结,支持Linux的硬实时性一般有两种策略:一种是直接修改Linux内核,重新编写一个由优先级驱动的实时调度器(Real-time Scheduler),替换原有内核中的进程调度器sched.c,KURT是采用这一方案较为成功的实时Linux操作系统;另外一种是在Linux内核之外, 以可加载内核模块(Loadable Kernel Module)的形式添加实时内核,确保其高响应特性,实时内核接管来自硬件的所有中断,并依据是否是实时任务决定是否直接响应。新墨西哥科技大学的RT-Linux,就是基于这种策略而开发的。以上两种策略有其借鉴之处,但如果综合考虑任务响应、内核抢占性、实时调度策略等几个影响操作系统实时性能的重要方面,它们还不能很好的满足实时性问题。为了增强嵌入式Linux实时性能,下文将就内核时钟精度、内核的抢占性以及内核调度算法等相关问题重点研究相应的解决方法。3 改善嵌入式Linux实时性能的方法
针对Linux在实时应用中的技术障碍,将Linux改造成为支持实时任务的嵌入式操作系统, 主要从下面三个方面进行着手。
[5]
用心
爱心
Linux嵌入式技术 第3篇
关键词:嵌入式系统工作任务学习情境一体化教学
嵌入式linux系统由于具有开源、网络功能强大、内核稳定高效等特性,在产品开发周期、产品的功能可扩展性、开发时的人力投入等方面都具有显著的优势,因此广泛应用于中低端智能电子设备中。随着物联网的发展,嵌入式智能技术将具有具大的市场前景。
在高职类院校,嵌入式linux课程特别强调实践性,著重培养学生的实际操作能力和解决问题的能力是至关重要的。本文针对高职嵌入式linux课程,理论性强、难学难懂,学生学习效果不佳的问题,提出了具体的教学设计方案。
1.嵌入式linux课程分析
本课程的先修课是电子技术、C语言程度设计,它的后续课程是智能终端开发、毕业设计等。本课程对学习智能型设备原理,进行智能型系统的运行、维护、管理与技术改造,掌握自动控制技术,起着关键作用。
本课程是一门技能训练课,适合采用项目教学法。课程设计为要求学生通过本课程的学习,完成本课程要求的全部实验实训内容。
2.嵌入式linux课程设计
2.1 设计思路
打破传统的按照知识体系教授课程的方式,以学生将要从事的嵌入式软件设计工程师岗位所需的职业能力为目标,与行业企业合作,进行基于工作过程的课程开发与设计,既保证满足职业岗位所需技能、相关知识、素质的需要,又保持原有面向应用的嵌入式技术知识体系相对完整性。
2.2 内容选取
在课程教学内容的选取时,以项目为导向,以够用为原则,选取教学内容;从简单到复杂,按照学生认知规律安排教学内容。将课程中所需要的先修课程的知识,融入教学中,起到了承前启后的作用。
2.3 实施方法
2.3.1 课程教学模式
采用“基于工作过程的项目导向、任务驱动”教学模式,把教学和工作过程结合在一起,建设“教、学、做”三位一体的教学情景。这种教学模式是把教学内容以完整的项目为载体,按照工作流程划分为学习情境,每个学习情境的教学由项目任务导入,引导学生学习解决问题的方法,并通过学习关键技术,然后再讲解各知识点,再利用所学知识解决问题。
本课程通过综合运用任务驱动,工学交替,学做融合的教学过程,在课程教学过程中,将企业的真实项目、技术人员、嵌入式开发模式,组织管理方法、企业文化和开发环境引入教学,实现课堂内外工学交替,同步实施。课堂之外,依据课程所学知识技能点,完成校企合作中心真实项目,达到学用结合。
2.3.2 教学方法
以从企业精选的项目为载体,再现嵌入式软件开发经典案例,课程的教学过程中,把遇到的各种经典的案例集中进行剖析,引导学生通过实际练习,养成良好的IT职业素养,在实际工作中能够及时发现问题和解决问题。
分组教学,增强学生团队协作、沟通交流能力。合理安排学生在学习中扮演不同角色,从事不同工作,完成一个项目中各类工作任务,通过多个项目的轮流实践,分别体会工作过程中的不同岗位职责,为今后走上工作岗位,与其他同事良好合作,迅速融入公司的团队中,快速进入工作角色,奠定了良好的基础。
在教学过程中,根据项目实施的具体需要,因人而异,分层教学,为不同类型的同学制订针对性较强的学习目标,从而挖掘学生多元化的发展潜质。
在课程的实施过程中,通过互动研讨、专题讲座的方式,选择在课程与就业,技术与发展等具有典型代表意义的主题进行教育,扩大了学生看待问题的视野,开阔了思路,积极引导学生全面提升职业发展能力。
2.3.3 教学手段
为了倡导“开放式自主学习”的新观念,更好的培养学生自主学习的能力,本课程建立了一个学生自主学习平台,本课程的教学资源全部可在网上浏览和下载,任何学生在任何时候、任何地方都能获取知识,训练技能,保证学生按需学习和自主学习。
2.3.4 课程考核
以过程考核为重点,突出多元化标准评价。考核的项目包括:过程考核、最终考核、纪律、创新、团队、文档等项目实施的各个方面,他们分别占有不同的比重,突出了企业多元化的评价标准。
课程的考核评价围绕岗位能力,通过企业参与对学生完成的项目进行评价考核。除此之外,根据学生所选择的岗位进行个体评价,和企业联合实施岗位答辩。兼顾实施和培训相关要求,创建真实的实施情境。
3.嵌入式linux课程实施效果
通过精心选择教学项目、严格规范教学过程、引导学生积极参与,切实培养了学生认真做事、主动学习、注重细节的综合素质;实现了学生由厌学到好学、由校园人向职业人的转变。
4.结语
嵌入式系统教学是复杂的,应用到软件设计与分析、操作系统、计算机组成原理、计算机体系结构等课程的内容,要求学生对这些知识理解非常深入,同时更要求学生有探究问题的兴趣、解决问题的能力与方法。通过课程实践,初步探索了高职嵌入式系统课程实施的有效方案。课程实施中,教师要进行非常充分的准备,不仅能优化学生的知识结构,而对学生求解问题的能力、甚至是元认知策略、协同学习能力都有不同程度的提高。与传统的按部就班式的教学相比,学生的收获是很大的。
参考文献:
[1]王永生.高水平特色大学卓越工程人才培养模式的研究与实践[J].中国高等教育,2011(6):15-18.
[2]王现君.基于一体化课程考核方案的研究[J].才智,2011(9):279-280.
[3]罗怡桂.嵌入式linux实践教程[M].北京:清华大学出版社,2011:89-156.
[4]陈刚,朱晓波.论科学课程问题解决的教学[J].教育科学研究,2011(5):57-60.
[5]冯利美.从实践中学嵌入式linux应用程序开发[M]电子工业出版社,2013.5.
[6]李岩,王小玉,孙永春.嵌入式系统教学研究[J].电气电子教学学报,2006,28(3):45-47.
Linux嵌入式技术 第4篇
关键词:嵌入式GIS,MapInfo地图数据,GIS算法,GIS数据结构
0 引 言
近年来,随着嵌入式系统和GIS技术快速发展,以及在社会需求的强力推动下,嵌入式GIS呈现出前所未有的发展势头,其应用领域也越来越广,如车辆导航、土地调查、军事指挥、旅游导游等。纵观国内外嵌入式GIS发展现状,基本都是基于WinCE平台的商用嵌入式GIS,如MapInfo公司的MapX Mobile、ERIS公司的ArcPad、超图公司的eSuperMap等[1]。
Linux操作系统是非常优秀的系统,尤其是具有稳定性、健壮性、可裁减性、开源性等特性而广受欢迎,其在嵌入式行业也占巨大份额,但基于Linux平台的嵌入式GIS相当缺乏[2]。本文研究ARM平台下,基于ARM-Linux的嵌入式GIS系统,并在西湖景区电子导游系统中成功应用。
1 嵌入式GIS数据格式分析及算法实现
1.1 MapInfo数据格式分析
嵌入式GIS地图数据采用桌面MapInfo数据,通过MapInfo可生成空间数据和属性数据。MapInfo电子地图,没有拓扑关系的定义,而是通过提供新的地理运行符和面向对象的图形结构,使传统的GIS中的地图分析和图形处理功能得以实现[3]。MapInfo地图由图层组成,每个图层通过MIF和MID两种ASCII格式的数据文件供外部用户使用,其中MIF文件保存GIS空间数据,MID文件保存属性数据[4,5]。MIF文件由文件头和数据段组成,图层的空间信息记录在数据段中,数据段包括点(point)、线(line)、多义线(polyline)、区域(region)、圆弧(arc)、文本(text)、矩形(rectangle)、圆角矩形(rounded rectangle)和椭圆(ellipse)等实体。MID文件为对应实体的属性信息。MapInfo地图数据组织结构如图1所示。
1.2 嵌入式GIS数据模型建立
1.2.1 图形实体对象结构建立
矢量地图是通过软件绘画各种图形实现,图形的形状、位置、颜色等都以结构体来记录。根据MapInfo数据特点,为MIF文件中的9种实体对象建立相应数据结构。每个对象有位置(x,y)、颜色(pen)、填充色(brush)等组成,建立结构体,如表1所示。数据存储时,把同一图层的相同实体链在同一个链表中。
1.2.2 地图图层结构建立
电子地图由多个图层组成,每个图层链在图层链表上。每一个图层由9种实体对象组成,每一种对象也链在相同类型的链表上,9种对象都链在图层节点上,每个实体对象的属性信息连在相应的属性数据中,结构如图2所示。电子地图显示时,把视图内的所有图层的9种实体根据指针链表连续显示,即可完成。
1.3 嵌入式GIS算法实现
由于嵌入式系统硬件结构与桌面计算机系统存在较大差异,必须考虑CPU运算速度慢、存储空间小、内存共用、可视范围小等特点,所以在构建嵌入式GIS数据模型时,不能简单套用桌面GIS的数据结构与实现方法。综合分析常用的GIS数据模型,提出改进网格索引双缓冲存储显示模式。
本文设计了双线程,即定位线程与显示线程,同时利用子母缓存加载网格数据,如图3所示。子缓存根据视图范围,从母缓存中加载显示数据,母缓存根据预判机制加载将要显示的数据。并采用并行技术更新子母缓存,充分利用CPU资源。当处理器空闲时,启动定位线程,确定当前视点周围一定范围内所包含的网格,通过网格索引从数据库中加载地图数据,并更新母缓存;当处理器收到显示命令时,启动显示线程,根据母缓存更新子缓存,并将屏幕数据绘制在屏幕上。如果地图数据都不在子母缓存中,则说明更新缓存失败,重新启动定位线程更新母缓存。
2 基于QT/E嵌入式GIS界面实现
2.1 基于QT/E的GIS设计
QT是采用C++设计的,具有跨平台性,有QPaint强大的画图功能[6],非常适合嵌入式GIS开发。通过画直线(drawLine)、画圆弦(drawArc)、画区域(drawPolygon)、画椭圆(drawEllipse)、画矩形(drawRect)、画圆角矩形(drawRoundRect)、写字(drawText)等功能,可绘制GIS中所有实体对象;采用画笔、画刷(setPen,setBrush),可以调配色彩,绘制任意彩色图。本文以Qpaint类完成所有实体对象绘制。
基本GIS界面设计菜单、工具栏、地图显示模块。菜单栏包括实体对象选择、图层操作。工具栏包括放大、缩小、漫游、信息显示功能。地图显示界面显示电子地图和一些属性功能。对象选择和信息显示,主要完成对实体对像的定位,把屏幕坐标转换为地图坐标,然后根据坐标对子母缓存中的数据进行搜索遍历,利用射线算法确定选择点所属的实体对象,实现定位;放大、缩小、漫游是对地图类的设置完成,采用scale属性控制放大缩小倍数,通过deltX和deltY属性控制移动方向;图层操作定位机制选定操作图层,启动编辑功能,对本图层的实体操作。
2.2 电子地图在QT/E中显示
根据1.2节的数据模型,绘制每个图层的实体,即实现电子地图显示。先打开首图层,根据存储结构,建立网格索引模型,获取每种实体对象的空间位置,更新子母缓存,对子缓存中每个图层中的9种实体对象进行绘制,处理完毕后,绘制下一图层,直到所有图层的实体都绘制结束,如图4所示。
3 嵌入式GIS应用与测试分析
3.1 嵌入式GIS在电子导游中应用
采用自主设计的ARM S3C2440为核心的电路板,配备3.5英寸的触摸屏,移植Linux2.6.14操作系统和QT/Embedded3.3.6图形库,集成掌上电子导游系统。在PC机上用MapInfo对西湖景区栅格地图进行数字化分层,然后把图层数据和景点数据导入电子导游系统中,实现西湖景区电子导游。图5和图6是西湖景区电子导游系统和景点放大图。
3.2 嵌入式GIS测试
嵌入式GIS在西湖景区电子导游中应用效果非常好。为了进一步测试,选择大规模节点显示地图素材。素材节点有2000、5000、8000、10000,分别对其进行漫游、放大、缩小操作,运算时间见表2。
从表中可看出,相同节点地图上作漫游、放大、缩小操作,所花时间基本相近,运算时间比较稳定,鲁棒性较好。随着显示节点数量增多,所花时间明显增加,这符合实际:硬件性能不变,运算数量越大所花时间越多。并且时间没有与节点数量成比例增加,因为嵌入式GIS中应用了双缓存,可提高一定的显示速度。
4 结 论
在ARM-Linux系统中设计具有自主知识产权的嵌入式GIS,可充分发挥Linux的稳定性、健壮性和高效性,又是中国软件业发展要求。嵌入式GIS模块具有桌面GIS的基本功能,可实现放大、缩小、漫游、信息提取、图层操作等功能,并且在西湖景区电子导游系统中成功应用,取得良好效果。经大量数据测试,系统性能稳定,鲁棒性较好。
参考文献
[1]沈文裕,方钰,蒋昌俊,等.跨平台嵌入式GIS数据模型的研究与应用[J].计算机应用,2007,27(9):2298-2301.
[2]王坤,陈飞.基于Linux平台下地理信息系统软件开发[J].测绘科学,2005,30(2):87-89.
[3]徐建辉,胥兵.MAPINFO数据格式和中国地球空间数据格式的转换实现[J].工程地球物理学报,2005,2(1):44-49.
[4]Joutsiniemi Anssi,Edwards Robert.MapInfo Native Table Format[M].New York:MapInfo Corporation,2000:1-12.
[5]付梦印,李杰,张长江,等.用MapInfo数据生成导航电子地图道路网络[J].计算机辅助设计与图形学学报,2004,16(10):1463-1465.
嵌入式linux学习步骤 第5篇
作者:phantom 时间:2009-8-6 文章来源:来自网络
1、Linux 基础
安装Linux操作系统 Linux文件系统 Linux常用命令 Linux启动过程详解 熟悉Linux服务能够独立安装Linux操作系统 能够熟练使用Linux系统的基本命令 认识Linux系统的常用服务安装Linux操作系统 Linux基本命令实践 设置Linux环境变量 定制Linux的服务 Shell 编程基础使用vi编辑文件 使用Emacs编辑文件 使用其他编辑器
2、Shell 编程基础
Shell简介 认识后台程序Bash编程熟悉Linux系统下的编辑环境 熟悉Linux下的各种Shell 熟练进行shell编程熟悉vi基本操作 熟悉Emacs的基本操作 比较不同shell的区别 编写一个测试服务器是否连通的shell脚本程序 编写一个查看进程是否存在的shell脚本程序 编写一个带有循环语句的shell脚本程序
3、Linux 下的 C 编程基础
linux C语言环境概述 Gcc使用方法 Gdb调试技术 Autoconf Automake Makefile 代码优化 熟悉Linux系统下的开发环境 熟悉Gcc编译器 熟悉Makefile规则编写Hello,World程序 使用 make命令编译程序 编写带有一个循环的程序 调试一个有问题的程序
4、嵌入式系统开发基础
嵌入式系统概述 交叉编译 配置TFTP服务 配置NFS服务 下载Bootloader和内核 嵌入式Linux应用软件开发流程熟悉嵌入式系统概念以及开发流程 建立嵌入式系统开发环境制作cross_gcc工具链 编译并下载U-boot 编译并下载Linux内核 编译并下载Linux应用程序
4、嵌入式系统移植
Linux内核代码平台相关代码分析 ARM平台介绍平台移植的关键技术 移植Linux内核到 ARM平台 了解移植的概念 能够移植Linux内核移植Linux2.6内核到 ARM9开发板
5、嵌入式 Linux 下串口通信
串行I/O的基本概念 嵌入式Linux应用软件开发流程 Linux系统的文件和设备 与文件相关的系统调用 配
置超级终端和MiniCOM 能够熟悉进行串口通信 熟悉文件I/O 编写串口通信程序 编写多串口通信程序
6、嵌入式系统中多进程程序设计
Linux系统进程概述 嵌入式系统的进程特点 进程操作 守护进程 相关的系统调用了解Linux系统中进程的概念 能够编写多进程程序编写多进程程序 编写一个守护进程程序 sleep系统调用任务管理、同步与通信 Linux任务概述任务调度 管道 信号 共享内存 任务管理 API 了解Linux系统任务管理机制 熟悉进程间通信的几种方式 熟悉嵌入式Linux中的任务间同步与通信编写一个简单的管道程序实现文件传输 编写一个使用共享内存的程序
7、嵌入式系统中多线程程序设计
线程的基础知识 多线程编程方法 线程应用中的同步问题了解线程的概念 能够编写简单的多线程程序编写一个多线程程序
8、嵌入式 Linux 网络编程
网络基础知识 嵌入式Linux中TCP/IP网络结构 socket 编程 常用 API函数 分析Ping命令的实现 基本UDP套接口编程 许可证管理 PPP协议 GPRS 了解嵌入式Linux网络体系结构 能够进行嵌入式Linux环境下的socket 编程 熟悉UDP协议、PPP协议 熟悉GPRS 使用socket 编写代理服务器 使用socket 编写路由器 编写许可证服务器 指出TCP和UDP的优缺点 编写一个web服务器 编写一个运行在 ARM平台的网络播放器
9、GUI 程序开发
GUI基础 嵌入式系统GUI类型 编译QT 进行QT开发熟悉嵌入式系统常用的GUI 能够进行QT编程使用QT编写“Hello,World”程序 调试一个加入信号/槽的实例 通过重载QWidget 类方法处理事件
10、Linux 字符设备驱动程序
设备驱动程序基础知识 Linux系统的模块 字符设备驱动分析 fs_operation结构 加载驱动程序了解设备驱动程序的概念 了解Linux字符设备驱动程序结构 能够编写字符设备驱动程序编写Skull驱动 编写键盘驱动 编写I/O驱动 分析一个看门狗驱动程序 对比Linux2.6内核与2.4内核中字符设备驱动的不同Linux 块设备驱动程序块设备驱动程序工作原理 典型的块设备驱动程序分析 块设备的读写请求队列了解Linux块设备驱动程序结构 能够编写简单的块设备驱动程序比较字符设备与块设备的异同 编写MMC卡驱动程序 分析一个文件系统 对比Linux2.6内核与2.4内核中块设备驱动的不同
11、文件系统
Linux嵌入式技术 第6篇
1 指纹识别算法的实现
指纹识别算法的实现从整体上来说 可以分为3大阶段 : (1) 图像预处 理 , 在这一阶段中主 要是通过特殊 算法对人 事指纹图像进行处理, 使原始图像更加容易提取特征点;(2) 指纹特征提取, 该阶段的主要工作是将预处理之后的图像特征点提取出来;(3) 图像比对, 这一阶段主要是完成两幅指纹图像特征的比对。 3个阶段中最为重要的就是第一个阶段, 通过图像的归一化、 分割、 方向图提取、 获取纹线频率、 增强、 二值化等手段使指纹图像的特征点更加突出。
设计过程中需要重点关注的环节包括指纹图像处理效果及所需要的时间。 但是不同的处理器对图像增强算法产生不一样的 作用 , 比对X86、 S3C2440、 S3C6410、 JZ4775以及JZ4780处理器 , 发现在不同 处理器上 用指纹增 强算法的时 间和主频率并没有明显的正比例关系, 主要原因是处理器的内部结构差异较大, 导致其运行的任务数量不同 , 主频越低 , 对指纹图像处理算法的影响越明显, 因此选择合适的处理器对于指纹算法实现非常重要。
2 搭建指纹识别系统平台
基于操作系统设计嵌入式指纹识别系统的设计主要包含硬件电路的设计和系统软件的设计。 前者包含有对硬件平台需要的器件、 电路原理图进行设计, 做好制版、 焊接和调试工作, 硬件工程师能够完成这一阶段的任务。 系统设计又分为底层的驱动开发和上层的应用软件开发。 前者是根据系统需要选择嵌入式操作系统、 移植操作系统等, 当平台搭建完毕之后软件工程师根据实际需要开发和调试应用软件。
2.1 硬件平台
文中选择S3C2440作为系统应用的处理器, 用户可以通过触摸屏, 对系统进行操作。 应用R305指纹识别模块对图像进行采集和处理, 以64m字节的SDRAM作为系统运行的基础条件, 用户操作反馈则使用LCD显示屏, 将USB作为系统处理器的通信途径。 此外, 应用RTC作为维持系统运行的时钟, 通过电源管理模块为系统运行提供电源。 其关键步骤有: (1) 处理器的 选择 , 处理器是 嵌入式应用系统 中至关重要的元素, 当前, ARM架构阵营处理器应用较多, 在移动网络、 医疗与消费类电子、 工业控制等领域都能够看到其身影。 此外MIPS架构的市场也非常广阔。 选择ARM920T内核的处理器, 其成本较低、 功耗较小, 适合开发的需求。(2) 指纹识别模块的选择, 应用的指纹识别模块应用光学指纹传感器进行采集, 通过DSP处理器实现指纹识别相关算法, 并能够与主机进行通信。
2.2 软件平台
硬件平台设计调试完毕后就需要为系 统搭建软 件平台 , 主要内容有系统的选择、 移植、 开发、 搭建调试环境、 开发和调试新的驱动等, 关键环节有:(1) 嵌入式操作系统的选择, 应用的是Linux操作系统, 该系统的应用非常广泛且发展速度快, 是嵌入式应用系统的首选。 其最大的特点就是自由与免费, 任何使用者都能够对其进行修改, 此外, Linux操作系统能够获取更多的内核支持, 相对于其他操作系统更加方便。(2) 搭建开发环境, 首先通过关闭PC中的Linux操作系统的防火墙, 然后对/etc/exports文件进行编辑, 将权限、 地址等加入文件中, 保存之后将NFS服务开启后就能够实现文件传输; 建立交叉编译环境、 调试环境和烧录环境即实现开发环境的搭建。(3) 移植Linux内核, 步骤为: 内核移植准备; 获取内核源码, 下载到本地准备移植; 根据设计中的嵌入式开发板选择板级代码; 基于实际设计需求, 对驱动代码进行修改和添加; 最后对内核源码进行配置和编译, 并将其烧录到开发板中确认。
3 指纹识别系统的软件设计
3.1 系统的设计思路
提出的嵌入式指纹识别系统软件设 计思路为 分层处理 , 也就是软件与硬件的设计, 为了改善代码的重用性和可移植性, 基于指纹识别系统的传输方向对其进行抽象分层, 主要有6层: (1) 硬件层。 也就是指纹模块, 其功能是获取指纹像素信息, 完成指纹识别中的图像采集、 上传、 特征点的生成、 保存和删除等;(2) 驱动层。 即指纹识别模块在Linu操作系统中的驱动程序, 选择USB通信方式需要根据具体的USB协议开发合 适的驱动 系统 ; (3) 通信层 。 功能在于实 现指令和数据在处理器与指纹模块之间的传输;(4) 指纹识别算法层。 将采集得到的图像像素信息根据算法提取出指纹特征点, 并进行对比, 其工作质量与整个指纹识别系统效果息息相关;(5) 指纹识别功能层 。 实现算法 层与通信 层的封装, 方便系统的移植;(6) 指纹识别控制显示层。 用于用户对指纹识别系统的控制和反馈。
3.2 系统串口通信程序的开发
Linux操作系统 内核驱动 能够很好 地对系统 操作进行 封装, 提供结构体设置串口通信属性, 设计的系统在软件开发过程中对UART通信方式的操作以 文件的方 式进行 。 例如 , 在对某一个设备进行操作之前, 需要调用open() 函数将设备对应的节点打开, 一般在/dev的目录下, 随后基于设备的特点选择特定的函数进行配置, 然后使用read() 函数对数据进行读取、 应用write () 函数进行写入, 当操作完成之后调用close() 将设备关闭, 实现对整个设备的控制过程。 对于串口而言操作是一样的, 系统对串口实现以下的分配: 第一个串口, 对应设备节点为/dev/tty S0; 第二个串口为/dev/tty S1, 以此实现对指纹识别模块指令数据输出。
3.3 用户操作界面的开发
利用Qt designer建立图形框架, 然后基于框架生成源代码, 对其进行修改后实现初步设计。 主要比周为: 建立Qt文件; 根据文件生成源代码; 加入main.cpp文件, 并生成pro文件与Makefile文件; 对源代码进行修改以及编译仿真。 期间可能遇到的主要难题有编写C++代码期间调用C函数库, 要实现串口通信程序、 指纹数据库的管理, 需要应用C代码封装, 因此需要在C++包含C函数的头文件之间加上代码, 才能够实现C语言源码的调用。
4 结语
以往的指纹识别系统通常以计算机作为平台, 将采集的指纹信息在计算机平台中进行处理和匹配, 需要较高的成本来实现; 而当前应用的嵌入式指纹识别系统则无需以PC作为平台, 但是运算速度和系统扩展受到一系列的限制, 其可维护性与交互性不强。 ARM是非常先进的32位RISC处理器架构, 具有显著的高性能、 低能耗的特点, 在对ARM与Linux嵌入式技术以及指纹识别技术进行研究的基础上设计基于嵌入式Lin ux的指纹识别系统, 具有安全、 可靠、 扩展性好等优点。
摘要:计算机技术的发展促进了生物特征识别技术的进步,无论是脸部识别、虹膜识别,还是指纹识别都得到非常广泛的应用。尤其是指纹识别在生活和工作中非常多见,如工作单位的指纹签到系统、指纹门禁系统、手机上的指纹解锁系统等,对人类生活和发展产生巨大的意义。基于ARM和Linux嵌入式技术探讨指纹识别系统的开发与设计,具有较好的应用前景。
嵌入式Linux裁剪研究 第7篇
关键词:嵌入式,Linux,裁剪
随着计算机技术的发展,近年来,嵌入式系统的应用研究也逐步被研究从人员重视。而嵌入式的操作系统的研究更是嵌入式研究的重中之中。目前,商业中的嵌入式操作系统很多,但都是非开发源代码的。而Linux操作系统是完全开发源代码,受到广大研究人员的青睐。Linux操作系统设计的本意是用于桌面,它是一个通用的操作系统。但由于嵌入式系统使用环境的限制,嵌入式系统自身的一些特殊性能要求,包括不同程序的实时性、系统的体积、功能、可移植性、可裁剪性等方面的要求,使得在开发嵌入式的Linux系统要做许多工作。
1 嵌入式Linux面临的问题
1.1 嵌入式Linux系统的裁剪
这个问题也是Linux应用到嵌入式系统首要解决的问题。一个Linux系统包括各种应用程序和函数库的RedHat Linux大约要占用2G左右的硬盘空间,一个通用的Linux也有1M多,根本无法将Linux固化到FLASH中。因此,必须要对Linux系统进行裁剪,以适应嵌入式系统的要求。
1.2 嵌入式Linux系统的实时性问题
Linux系统是分时系统,这一点与UNIX没有本质上的区别。而就嵌入式系统而言,则要求系统具有实时性。
而Linux分为用户态和内核态两种模式,进程运行在用户态时,如果实时进程具有高的优先级,则能抢占进程,这时可较好完成任务;但进行运行在内核时,实时进程不能抢占进程。在定时器方面,也有一些缺陷,一是,Linux的周期模式定时器频率仅为100Hz,远不能满足多种实时应用的要求。二是,软定时由时钟定时器完成,当软定时器较多时,势必引起共享时钟定时器的冲突。还有Linux进程采用多级轮转调度算法,该调度算法,仅能获得秒级响应时间,一个实时进程在一个时间片内未完成,其优先级将降低,从而可能造成到截止时间无法完成。Linux虽然给实时进程提供了较高的优先级,但是,并没有加入时间限制。例如完成的最后期限、应在多长时间内完成、执行周期等等。同时,其它大量的非实时进程也可能对实时进程造成阻塞,无法确保实时进程的响应时间。另外,当有多个实时进程互斥请求共享资源时,由于其使用的同步原语不支持优先级继承协议(PIP),易产生优先级倒置。[Linux嵌入式技术研究]
1.3 嵌入式Linux系统的GUI支持问题
在嵌入式系统中经常需要提供图形用户接口,如在本项目中的PDA中,就需要提供图形用户界面,以让用户进行操作,这需要用到嵌入式GUI。嵌入式GUI就是在嵌入式系统中为特定的硬件设备或环境而设计的图形用户界面系统。
由于嵌入式Linux系统应用的特点,在其上运行的嵌入式GUI应具有轻型、占用资源少、高性能,可配置的特点。目前已经有一些比较成熟的嵌入式GUI,如Microwindows、MiniGUI、OpenGUI等。
当然在实际的具体应用中还存在其它问题,由于本文只侧重对Linux裁剪的研究,其他在这不做过多说明。
2 嵌入式Linux系统的裁剪
嵌入式的系统应用非常专业化,所以功能相对单一,对操作系统的需要比较简单。因此要对Linux操作系统进行裁剪到合适程度。裁剪Linux,最容易想到的方法是以一个已经安装好的系统为基础,删除掉不需要的文件,以减小整个系统的尺寸。而事实上这个方法几乎是行不通的,因为通过光盘安装的一个Redhat 9 Linux系统,即便是只选择了比较少的软件包,其所占空间也可以轻松达到300~500MB,想在这个基础上裁剪到30MB左右是比较困难的。更困难的是确定哪些东西是可以删除的?如果删除了系统必须的文件,可能导致系统不能引导。
另一个途径是从零开始根据需要构建整个系统,一个个安装需要的软件包。类似的,更简单的方法是,安装一个完整的Linux系统,然后将必要的软件(可执行程序)、配置文件、库文件、内核等复制出来构建一个小系统即嵌入式Linux操作系统(Linux Powered Storage,LPS)。一般采取后一种方式。
2.1 系统的结构
复制的小系统包括3部分:Linux内核,根文件系统和引导器。
内核(Kernel)提供了一个操作系统的基本功能,如内存管理、进程调度、文件系统、网络等,以及设备驱动程序。
根文件系统(Root filesystem)是存放运行、维护系统所必须的各种工具软件、库文件、脚本、配置文件和其他特殊文件(比如设备节点)的地方,也可以安装各种软件包。通常根文件系统位于某个磁盘分区,而在LPS中应用了initrd(初始RAM盘)机制,将根文件系统放在RAM Disk中。
引导器(Boot Loader)的任务是从引导设备装载内核,引导系统运行。Linux系统常见的引导器包括早期的LILO和近期的GRUB。
2.2 内核的创建方法
Linux的内核完成进程调度,内存管理,虚拟文件系统,网络接口,进程通信等操作系统的基本功能。Linux开放源代码,提供了一套编译内核的工具,很容易完成配置和编译内核的工作。编译内核的基本命令如下:
2.3 根文件系统
将要创建的根文件系统与通常Linux主机的根文件系统类似,只是它应该仅仅包括系统运行所必须的应用程序、库和相关文件的最小集合。根文件系统的尺寸大小是一个重要的指标。
2.4 引导器
初始化RAM盘(initrd)提供了引导器加载RAM盘的能力。这个RAM盘可以被挂载(mount)成根文件系统,并执行其上的程序。然后,可以从另一个设备挂载一个新的根文件系统,而原来的根文件系统(也就是initrd)会被移到一个目录里并卸载。initrd技术主要设计用来让系统启动过程可以分两个阶段进行,首先让内核以一组最小的、被编译进内核里的驱动程序来启动,然后从initrd中加载其他的模块。
3 结束语
Linux是一个功能强大的操作系统,同时有大量的应用程序。利用已有的内容可以提高开发的效率。本文在研究了Linux系统之后,给出了嵌入式Linux系统进行裁剪时所要注意的问题,并给出了具体实现的方法。根据此方法,可以在实际的应用过程具体需要,进行必要的选择,以创建出适合的嵌入式Linux系统。
参考文献
[1]顾咏枫,陈章龙.嵌入式Linux裁剪方法[J].小型微型计算机系统,2003,24(09):1697-1700.
[2]滕艳平.嵌入式Linux操作系统实时性的研究与实现[J].微计算机信息,2007,23(82):59-61.
Linux嵌入式技术 第8篇
随着微电子技术的高速发展,由价格低廉和功能齐全的微处理器构成的各种嵌入式系统得到了广泛的应用,伴随其发展涌现出了一些商用化的嵌入式操作系统,比较著名的有Vxwork和WindowsCE等,但高昂的价格、封闭的源代码以及产品版税等限制了普及和广泛应用。而相对于以上的商业操作系统,Linux有着广泛的适用硬件平台、高效稳定的内核代码、良好的网络接口等特点,已经成为嵌入式系统领域中的研究热点。在嵌入式系统中,对底层硬件的管理是通过内核中的驱动程序来实现的,因此在嵌入式系统开发中,主要工作是对各种设备进行驱动程序的开发。中断管理是嵌入式操作系统的核心任务之一,设备驱动程序中使用中断可以提高整个嵌入式系统的效率。
嵌入式Linux的中断处理实现依赖于移植的硬件平台的类型、体系结构的设计及机器本身。Linux中断移植不仅需要充分了解使用芯片的中断设计,同时还需要对Linux内核中断系统的结构与运作有较深入的理解。Linux内核代码极为庞大和复杂,内核提供的API众多,这给Linux的中断移植造成了很大的困难。因此,本文以三星公司的S3C2440芯片为例,对嵌入式Linux(版本2.6.32)的中断系统进行分析,介绍嵌入式中断设计的要点与优化细节。
2. Linux内核的中断体系分析
2.1 中断在内核的实现
Linux2.6的内核设计采用了面向对象思想,同时采用C语言来实现,Linux这种设计理念在保持代码高效运行的同时又不失可移植性和可扩展性。整个Linux内核分为5个大的模块,它们分别是:进程调度,内存管理,虚拟文件系统,网络接口,进程通信。而本文所介绍的中断系统是进程调度子系统中的重要组成部分。
从微电子学的角度看,中断是一种电信号,由硬件设备生成,并直接送入中断控制器的输入引脚上,然后再由中断控制器向处理器发送相应的信号。当处理器引脚接收到中断信号,便中断自己的当前工作转而处理中断。此后,处理器会通知操作系统已经产生中断,这样,操作系统就可以对这个中断进行适当的处理了。
图1是中断在Linux内核中的调用结构图,对于每个IRQ中断线,Linux都用一个irq_desc_t数据结构来描述。irq_desc主要由irq_chip、irq_flow_handler和irqaction3个结构体构成。
2.1.1 中断控制器描述符irq_chip
对于嵌入式系统来说,由于CPU的种类有很多,且每个处理器对于中断的处理方式不一样。Linux为了实现统一的中断处理,提供了底层的中断处理抽象接口,对于每个平台都需要实现底层的接口函数。这样对于内核上层的中断通用处理程序就无需任何改动,isq_chip结构体内有几个重要的成员:
(1)Name用于/proc/interrupts记录中断信息的;
(2)Enable用于允许中断;
(3)Disable用于禁止中断。
2.1.2 中断服务例程描述符irqaction
在IRQ描述符中我们看到指针action的结构为irqaction,它是为多个设备能共享一条中断线而设置的一个数据结构。结构体成员Handle是指向一个具体I/O设备的中断服务例程的指针。这是允许多个设备共享同一中断线的关键一点,中断线可以相同,但处理函数可以不一样。
2.1.3 中断方式设置符irq_flow_handler
irq_flow_handler主要明确了内核中各种类型的中断处理方式,用户可以根据自己需要的形式制定不同的中断处理方式。
3. linux中断的处理机制
3.1 中断处理的分析
对于嵌入式linux系统来说,在一个中断发生时,并不是所有的操作都具有很高的急迫性。事实上,把所有的操作都放进中断处理程序本身并不合适。需要时间长的、非紧急的操作应该推后,因为当一个中断处理程序正在运行时,相应的IRQ中断线上再发出的信号就会被屏蔽。为了更好地利用CPU资源,Linux把一个中断要执行的操作分为下面的三类:
(1)紧急的
这样的操作诸如:中断到来时CPU做出应答,对中断控制器或设备控制器重新编程,来自外部芯片采集传送过来的数据信息。这些紧急操作应该在一个中断处理程序内立即执行,而且是在禁用中断的状态下,即不可嵌套中断。
(2)非紧急的
这样的操作诸如:修改那些CPU外部传送过来的数据结构(如本文后面提到的按键程序)。这类操作虽然不是最紧急的,也是必须要在中断处理程序中完成,但可以开启中断使能,即可以嵌套中断。
(3)非紧急可延迟的
这样的操作诸如,把数据传送到console驱动,打印调试信息(例如,把键盘信息缓冲区的内容发送到终端处理程序的进程)。
3.2 中断的top half和bottom half机制
正如上面所分析的,Linux中断按照事件的紧急程度划分不同的时间处理不同的事件,Linux内核进行中断响应时,内核一般要关闭中断,直到中断处理程序结束。如果中断处理程序执行时间较长,那么其它的一些进程将无法进行调度,严重影响了系统的实时性能。即使是最精简版的中断服务程序,它也要与硬件进行交互,告诉该设备中断已被接收。我们可以考虑一下网络设备的中断处理程序面临的实时性的压力,该处理程序除了要对硬件应答,还要把来自硬件的网络数据包拷贝到内存,对其进行处理后再交给合适的协议栈或应用程序。显而易见,这种工作量不会太小,尤其对于如今的千兆比特和万兆比特以太网卡而言。对此linux提出了top half和bottom half中断机制。
中断处理程序是上半部(top half)接收到一个中断,它就立即开始执行,但只做有严格时限的工作,例如对接收的中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成的,能够被允许稍后完成的工作都会推迟到下半部(bottom half)去。
在这里采用网卡作为一个驱动的例子来解释中断处理程序的实际执行过程。当网卡接收流入网络的数据包时,需要通知内核数据包到了,网卡需要立即完成这件事,从而优化网络的吞吐量和传输周期,以避免超时。因此,网卡立即发出中断告诉内核:最新数据包到了。内核通过执行网卡已注册的中断处理程序来做出应答。中断开始执行,应答硬件,拷贝最新的网络数据包到内存,然后读取网卡更多的数据包。这些都是重要、紧迫而又与硬件相关的工作。处理和操作数据包的其它工作在随后的下半部中进行。
4.嵌入式linux中断的实现
Linux中断体系采用的是面向对象的设计理念,这一体系降低了Linux中断系统与硬件的耦合度,提高了自身的可移植性。用户只需要关心芯片的中断触发条件以及编写相应的中断函数,就可以实现不同类型CPU的中断移植。下面以三星的s3c2440芯片的按键驱动为例,介绍嵌入式linux系统中断移植实现。
4.1 中断在linux中的注册
Linux在驱动程序中应用到中断的时候,必须先把中断处理程序注册到系统中。当有硬件中断请求发生后,操作系统调用中断处理程序,进行中断处理,完成对设备的操作。使用request irq()函数向内核注册中断处理程序,Request irq()函数声明如下:
*irq驱动程序使用的是中断号;
*handler是中断服务函数指针;
*Irqflags是中断类型标志;
*devname是发出中断请求的设备名;
*dev_id是处理程序的标识,将irqflags设置为IRQF_SHARED时,必须指定一个唯一dev_id作为该共享中断号上的处理程序的标识,即irqaction职责链上的标识符。
5. ARM-linux下的按键驱动程序实现
根据s3c2440芯片的原理图,硬件采用GPF0,GPF3,GPF5GPF6,GPF7,GPF11这6个端口对应6个按键。当按键按下时,分别产生EINT8、EINT11、EINT13、EINT14、EINT15、EINT19这6个外部低电平的中断请求。当按键按下时按键接通,中断线上原有的VDD33V高电平被拉低,从而触发中断的产生,电路如图2所示。
首先要设计一个按键的设备结构体。该结构体中包含了按键驱动的名字和中断号,引脚号与配置等信息。
为了消除按键抖动的影响,本驱动利用中断服务和定时器服务互相的作用,首先中断触发后启动延时定时器,进入定时器服务后处理按键的状态,最后当前按键抬起后,中断服务又开始处理新的中断,下面是定时器的代码片段。
6. linux中断应用要点
Linux内核一直工作在进程上下文或者中断上下文,提供系统调用服务的内核代码代表发起系统调用的应用程序运行在进程上下文;另一方面,中断处理程序,异步程序运行在中断上下文,中断上下文和特定进程无关。
对于运行在进程上下文的内核代码是可以被抢占的(Linux2.6支持抢占)。但是一个中断上下文,通常都会始终占有CPU。正因为如此,运行在中断上下文的代码就要受一些限制,下面是中断应用要注意的要点:
(1)睡眠或者放弃CPU
这样做的后果是灾难性的,因为内核在进入中断之前会关闭进程调度,一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,如不能通过wake up函数唤醒sleep。
(2)尝试获得信号量
如果得不到信号量,代码就会睡眠,一直等待内核获取该信号量,系统没办法通过别的进程唤醒。
(3)访问用户空间的虚拟地址
中断上下文是和特定进程无关的,它是内核代表硬件运行在内核空间,所以在中断上下文无法访问用户空间的虚拟地址。
(4)执行耗时的任务
中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能,例如在中断中频繁的调用printk函式,有可能导致系统崩溃。发提供一些借鉴。
7.结束语
本文基于三星公司的S3c2440芯片,分析了Linux中断系统的结构以及运行过程。尽管Linux中断系统的实现代码庞大,但由于在设计中使用了面向对象的设计模式,提供了中断所需要的函数接口,从而有效地屏蔽了底层硬件实现的复杂性,降低了Linux中断系统与硬件系统的耦合度,提高了Linux内核的可移植性。本文以一个嵌入式按键中断驱动为例,阐述了Linux在具体的嵌入式平台移植中断的基本框架和流程。尽管嵌入式系统的硬件平台千差万别,但通过充分运用面向对象的基本设计原则以及策略设计模式,使移植中断变得更系统化。笔者希望通过本文使读者对于Linux中断系统有一个完整的开发框架,对不同硬件平台的嵌入式中断开
摘要:Linux系统有着广泛的硬件平台、高效稳定的内核代码、丰富的应用软件、良好的网络接口等特点,已经成为嵌入式系统领域中的研究热点。中断管理是嵌入式操作系统的核心之一,在设备驱动程序中使用好中断是提高驱动的关键。本文分析了Linux系统的中断处理技术的框架与流程,详细讨论了嵌入式Arm-Llnux的中断移植和应用要点。
关键词:Linux,中断,嵌入式,S3c2440
参考文献
[1]毛德操,胡希明.Linux内核源码情景分析[M].杭州:浙江大学出版社,2001.
[2]王莹,何小庆.2008年度嵌入式应用调查报告[J].电子产品世界,2009(1):11214。
[3]王进德.嵌入式Linux程序设计与应用案例[M].北京:中国电力出版社,2007.
[4]赵明富,李太福,吴军,等.嵌入式Linux操作系统的实时化研究[J].西南师范大学学报(自然科学版),2003,28(3):386-390.
嵌入式Linux根文件系统的研究 第9篇
随着数字技术的发展,近年来嵌入式系统技术发展迅猛,已广泛应用于工业控制、国防、通信、办公自动化、消费电子等多种领域.而Linux作为一款优秀的源码开放、功能强大、高效稳定、开发环境成熟的多任务操作系统,具有许多商业操作系统不可比拟的优势,成为了最有潜力的嵌人式操作系统[1]。根文件系统是嵌入式Linux的重要组件,是内核启动加载的第一个文件系统,主要为内核的启动提供各种工具软件、库文件、脚本和配置文件等等,并且可以作为数据的存取区域,是决定系统能否正常启动的关键[2,3]。在此以Cramfs和Jffs 2文件系统为例,详述Linux根文件系统的制作过程。
1 文件系统层次标准
为了规范Linux的文件系统,促进Linux快速发展,Linux的开发者出台了所谓的文件系统层次标准(Filesystem Hierarchy Standard,FHS),它规范了在根目录“/”下面各个主要的目录应该放置什么样的文件。FHS定义了两层规范,第一层是“/”下面的各个目录应该要放什么文件数据,例如 /etc应该要放置配置文件,/bin与/sbin则应该要放置可执行文件等。第二层则是针对 /usr及 /var这两个目录的子目录来定义。例如 /var/log放置系统登录文件、/usr/share放置共享数据等。
在根文件系统的最顶层目录中,每一个目录都有其具体的目的和用途,表1提供了一个完整的FHS定义的根文件系统顶层目录[4,5]。
嵌入式Linux是标准Linux的裁剪,可以根据不同的用途对FHS进行必要的裁剪。例如/home,/root是在多用户时才有作用,在嵌入式系统中,如手持式智能终端等单用户设备是不需要这些目录的。
2 FLASH文件系统
FLASH是目前嵌入式系统中广泛采用的主流存储储装置,它是一种电擦除的非易失性存储器,具有低功耗、高密度、小体积等优点。FLASH存储器可以分为若干块,每块又由若干页组成,对FLASH的擦除操作以块为单位进行,而读和写操作以页为单位进行。FLASH 存储器在进行写入操作之前必须先擦除目标块[6]。目前FLASH中常见的文件系统有Romfs,Cramfs,Jffs 2,Yaffs2等,不同的文件系统有不同的特点。
2.1 Cramfs文件系统
Cramfs被设计为简单并且非常小的可压缩的文件系统,它主要用于ROM较小的嵌入式系统。在Cramfs文件系统中,每一页(4 KB)被单独压缩,可以随机页访问,其压缩比高达2∶1,为嵌入式系统节省大量的FLASH存储空间,同时在运行的时无需一次性地将文件系统中的任何内容都解压缩到内存之中,而是在系统需要访问某个位置的数据时,立即计算出该数据在Cramfs 中的位置,将其实时地解压缩到内存之中,然后通过对内存的访问来获取文件系统中需要读取的数据,其速度快,效率高。它的只读的特点有利于保护文件系统免受破坏,提高了系统的可靠性,但是它的只读属性同时又是一大缺陷,使得用户无法对其内容对进扩充[7]。
2.2 Jffs 2文件系统
Jffs 2是FLASH嵌入式系统上应用最广的一个日志结构的文件系统。它提供的垃圾回收机制,使得不需要马上对擦写越界的块进行擦写,而只需要为其设置一个标志,标明为块。当可用的块数不足时,垃圾回收机制才开始回收这些节点。同时,由于Jffs 2基于日志型结构,在意外掉电后仍然可以保持数据的完整性,而不会丢失数据。当文件系统已满或接近满时,因为垃圾收集的关系而使Jffs 2的运行速度大大放慢[8]。
3 Busybox的配置
Busybox是一个集成了一百多个最常用Linux 命令和工具的软件,具有实用、短小、稳定等特点。Busybox 利用Linux 实用工具中代码大量重复的事实,将重复的代码重新整理,放到一个文件中,减少了多次包含,这样就可以节省系统的空间和提高程序的执行速度,很适合对于资源比较紧张的嵌入式系统使用[9]。
Busybox的源码可以从官方网站www.busybox.net/下载,然后解压源码包进行配置安装,具体操作如下:
#tar-xjvf busybox-1.7.0.tar.bz2
#cd busybox-1.7.0
#make menuconfig
#make
#make install
最常用的配置命令是make menuconfig,也可以根据自己的需要来配置busybox,如果希望选择尽可能多的功能,可以直接用make defconfig,它会自动配置为最大通用的配置选项,从而使得配置过程变得更加简单、快速。在执行make命令之前应该修改顶层Makefile文件(ARCH=arm,CROSSCOMPLIE=arm-linux-)。执行完make install命令后会在当前目录的install目录下生成bin,sbin,linuxrc三个文件。
4 创建根文件系统
Busybox已经生成了根文件系统的三个重要的文件,其他的根目录文件要根据嵌入式设备的具体功能来对FHS进行裁剪,具体步骤如下:
(1) 创建根目录myrootfs,把Busybox生成的三个文件复制到myrootfs目录下,并在此目录下分别建立dev,lib,mnt,etc,sys,proc,usr,home,tmp,var等目录(只有dev,lib,sys,usr,etc是不可或缺的,其他的目录可根据需要选择)。在etc目录下建立init.d目录。
(2) 建立系统配置文件inittab,fstab,rcS,其中inittab,fstab放在etc目录下,rcS放在/etc/init.d目录中,下面给出这些文件的简单配置:
inittab文件(init进程根据它来创建其他子进程)
# This is run first except when booting
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
#Stuff to do when restarting the init process
::restart:/sbin/init
# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount-a-r
fstab 文件(定义了文件系统的各个“挂载点”,需要与实际的系统相符合):
none/proc proc defaults 0 0
none/dev /pts devpts mode=0622 0 0
tmpfs/dev/shm tmpfs defaults 0 0
sysfs/sys sysfs defaults 0 0
rcS文件
#! /bin/sh
/bin/mount-a
/bin/mkdir/dev/pts
/bin/mkdir-p/var/log
/bin/mkdir-p /var/run
/bin/mount-t devpts devpts/dev/pts
mdev-s
(3) 创建必须的设备节点,该文件必须在/etc目录下创建
#mknod console c 5 1
#mknod null c 1 3
(4) 如果Busybox 采用动态链接的方式编译,还需要把busybox 所需要的动态库: libcrypt.so.1,libc.so.6,ldlinux.so.2放到lib目录中。为了节约嵌入式设备的FLASH空间,通常会采用动态链接方式,而不采用静态链接方式。
(5) 改变rcS的属性
#chmod +x /etc/init.d/rcS
5 创建根文件系统映像
所谓创建某种格式的根文件系统,就是将根文件系统内容转换成选用的这种文件系统格式,或将根文件系统内容安装在具有这种文件系统格式的设备上。在嵌入式设备中常用的文件类型有Romfs,Jffs 2,Yaffs 2,Ramdisk,Ramfs,Cramfs等,下面主要介绍Jffs 2和Cramfs文件类型。
5.1 Jffs 2根文件系统映像
上面已经建立了根文件目录myrootfs,然后用命令mkfs.Jffs 2生成Jffs 2文件系统映像,命令源码包可以从http://sources.redhat.com/Jffs 2/处下载。
#mkfs.Jffs 2-n-s 512-e 16KiB-d myrootfs-o myrootfs.Jffs 2
其中“-n” 表示不要在每个擦除块上都加上清除标志;“-s 512” 指明一页大小为512 B;“-e 16 KB”指明一个擦除块大小为16 KB;“-d” 表示根文件系统目录;“-o” 表示输出文件。
5.2 cramfs根文件系统映像
使用命令mkcramfs创建根文件系统映像,这个工具在Linux 源码包里。
#mkcramfs myrootfs myrootfs.cramfs
6 结 语
Linux支持很多不同的文件系统,在具体使用时应根据设备的用途和配置来选择文件系统,也可以在一个设备上用多种文件系统。以Cramfs和Jffs 2为例介绍了Linux的根文件系统的制作过程,为其他文件系统的制作过程提供参考,也为Linux下应用程序的开发奠定基础。
参考文献
[1]杨洁洁.嵌入式Linux系统的移植及其根文件系统的实现[J].漳州师范学院学报,2005(2):46-48.
[2]陈立定,杨俊辉,陈伟欣.使用Busybox制作Cramfs根文件系统[J].计算机技术与发展,2009,19(4):146-148.
[3]耿增涛,史永宏.Jffs2文件系统在嵌入式Linux根文件系统中的应用研究[J].微型电脑应用,2008,24(2):44-46.
[4]李亚锋,欧文盛.ARM嵌入式Linux系统开发从入门到精通[M].北京:清华大学出版社,2007.
[5]查启鹏,姚国良,张萌.嵌入式Linux下大容量NAND FLASH的Yaffs2文件系统构建[J].现代电子技术,2007,30(18):55-58.
[6]张勇,裘雪红.嵌入式Linux下Jffs2文件系统的实现[J].计算机技术与发展,2006,16(4):138-140.
[7]赖于树.ARM微处理器与应用开发[M].北京:电子工业出版社,2007.
[8]王集森,刘昊,胡晨.嵌入式Linux中多文件系统的构建[J].单片机与嵌入式系统应用,2003(12):12-15.
Linux嵌入式技术 第10篇
关键词:嵌入式,Linux,GUI,消息机制,控件类库
1 引言
GUI (Graphical User Interface图形用户接口) , 早期的计算机采用命令行的模式, 也简称CUI模式, 在这种模式下玩转计算机的往往是专业人士。GUI采用图形方式显示计算机操作用户界面, 人机交互性较好。使得计算机及移动设备得以快速普及使用。
GUI是一个永恒的研究课题, 相信在不久的将来, 会有三维空间的GUI面世。
目前有几个成熟的GUI可适用于在嵌入式Linux系统中使用。如GTK、QT、MiniGUI等, 但是要很好地运行GTK, 通过现在的实验, 内存至少得扩展到64MB, 业界一般都采用128M, CPU的主频理想状态要在400MHZ以上, 这很大程度上提高了硬件的成本。而且关键点是二次开发均受制于它们的编程习惯。
嵌入式GUI需要具有下面几个方面的基本要求:占用资源少、高性能、高可靠性、便于移植、可配置、二次开发框架简洁易懂。
从大的框架论述基于Linux2.6的Framebuffer实现一个完整的GUI系统需要考虑到的几个方面, 包括GUI编程开发框架。在应用软件开发时, 编程框架对应用软件开发时效性起着决定性的作用。借鉴第四代编程语言的易学、方便性, 编程框架应该着重于易学易用, 而且还要易改, 易合作开发。所以论述在嵌入式Linux系统上实现GUI的主要出发点从软件开发人员角度出发。
C++的面向对象的思维接近我们世界中的事务处理思维。在实现的过程中可以采用C++作为开发语言。
GUI采用多线程的客户/服务器消息循环机制, 控件封装成类库。
2 功能分析
2.1 FrameBuffer、UNIX Domain SOCKET
FrameBuffer又名帧缓冲, 是Linux 2.2.xx内核中的一种驱动模型。FrameBuffer机制模拟显卡的功能, 将硬件结构抽象掉, 可以将Framebuffer看成是显示的一个内存映像, 将其映射到进程内存空间之后, 就可以直接进行读写操作, 写操作可以立即反应在屏幕上。这种操作是由显示驱动程序完成的。用户态程序不需关心物理显存的位置、换页机制等具体细节。用户态程序在操作的时候直接通过FrameBuffer的读写功能对显存进行操作。
FrameBuffer的设备文件一般是/dev/fb0、/dev/fb1等。在使用FrameBuffer时, Linux将显卡置于图形模式下。如果使用Frambuffer要求显示屏支持线性帧缓冲, 即CPU可以访问显示控制器的每一位。
在应用程序中, 操作Framebuffer设备的步骤如下:
(1) 打开/dev/fb0 (也可能是其他文件名) 设备文件。
(2) 用ioctrl操作取得当前显示屏幕的参数, 如分辨率、物理显示屏大小、每个像素点的比特数。根据屏幕参数可计算屏幕缓冲区的大小。ioctl的操作是由底层的驱动程序来完成的。
(3) 将屏幕缓冲区映射到用户进程空间并得到缓冲区的起始地址。
(4) 映射完后就可以直接读写缓冲区, 进行绘图操作了。
(5) 关闭framebuffer设备
采用C++实现GUI时, 可以自定义一个类来封装此对FrameBuffer的操作。
考虑到GUI控件绘制有先后关系, 而且其绘制过程中可能会出现连续的区域绘图, 这样可能会造成屏幕出现闪烁, 可以采用双显示缓冲机制。这主要在下面的管理器实现中讨论。
解决硬件绘图问题是GUI后续开发的首要问题。
2.2 UNIX Domain SOCKET
Socket API原本是为网络通信设计的, 但后来在Socket的框架上发展出一种IPC机制, 即UNIX Domain Socket。虽然网络Socket也可以用于进程间通信 (通过loopback地址127.0.0.1) , 但是UNIX Domain Socket用于IPC更有效率, 因为它不需要经过网络协议栈, 不需要打包拆包、计算校验和、维护序号和应答等, 只是将应用层数据从一个进程拷贝到另一个进程。IPC机制本质上是可靠的通信, 而网络协议是为不可靠的通信设计的。
UNIX domain也提供stream和dgram两种类型的服务, 类似于TCP和UDP。UNIX Domain Socket是全双工的。目前已成为使用最广泛的IPC机制, x-Window和GUI程序之间就是通过UNIX Domain Socket通信的。UNIX Domain Socket的地址是一个Socket类型的文件在文件系统中的路径, 这个Socket文件由bind () 调用创建, 如果调用bind () 时该文件已存在, 则bind () 错误返回。
总结DOMAIN Socket 5种操作, 监听、接收、读、写、连接。服务器端负责监听与接收, 客户端发起连接。读写就是全双工的。操作基本过程如下:
这里采用stream的服务类型, 在创建流套接字前先删除已存在的流文件。
连接的过程与监听的过程基本一致。只是不是监听而且连接了。
2.3 整体思路
如果在嵌入式Linux系统中只需要运行一个UI进程的话, 系统的实现会简单很多, 这种情况下不需要做进程间的通信。不需要做复杂的进程间窗口的调度。这种情况只适合设备任务单一性, 不需要进行用户二次开发。
还有一种情况就是需要在系统中实现多任务多窗口的操作, 这样的话系统实现将有很多的难题需要解决。而且开发周期也较长, 为了减少移植的工作量, 可以考虑把GUI的消息来源独立出来, 如果不需要进行复杂的操作则替换简单的消息源。
在唯一的屏幕资源中运行多进程、多窗口, 如何合理地显示用户所期望的内容成了GUI的重要任务。在处理过程中需要把握几个原则:
(1) 每创建一个窗口对象的同时创建一个线程。窗口的消息循环在线程中实现。
(2) 每个窗口对象分配一个虚拟显示设备进行绘图。最终通过消息传递提交管理器由管理裁减显示范围。
(3) 以控件为基础绘图单元, 也就是区域绘图的最小区域为控件区域。
(4) 由窗口管理着窗口的控件的刷新, 由窗口判断事件的来源, 并发送消息到对应控件, 由控件根据事件产生消息。
(5) 管理器调控窗口的先后关系以及窗口交割区域裁减。并传递相关硬件事件到事件发生区域所在的进程的当前窗口。
(6) 管理器与用户进程的GUI窗体类库对象采用Domain Socket方式通信。
2.4 消息机制与管理器
在Windows系统中消息机制成了它的主血脉。在Windows中发生的一切都可以用消息来表示, 消息用于告诉操作系统发生了什么, 然后又由操作系统分发消息到执行控件, 所有的Windows应用程序都是消息驱动的。
有了消息机制, 每个控件都被动地等着事件的到来, 而不主动地去查询硬件设备有没有事件。消息机制比较灵活, 方便管理, 占用内存开销也相对较小。
从这种机制考虑, 必须独立出一个进程来收集硬件所产生的事件, 然后由该独立的进程简单地封装成消息包, 传递给GUI系统, 由GUI系统做相应的处理。这个独立的进程就是文中所说的管理器。这只是管理器所要提供的功能的其中一个功能。
Linux中经典的管理器如x-Window, 现在知名的GNOME、KDE桌面系统也都是由x-Window为基础构建的。
开发GUI要考虑节省内存资源开销, 还要考虑资源唯一性。在我们的现实世界中, 人类生存的资源都是紧缺的, 人类发展到现在, 已经形成了相对完善分工体制, 比如谁需要什么, 可以向供方要求提供服务。当然供方也会向很多人提供同样的服务。与其说这是一种经济制序, 还不如说是一种服务机制。
管理器在这个GUI系统中, 就是资源服务的提供者。它需要提供以下几个方面的服务:
2.4.1 处理输入
管理器从键盘、触摸屏接受输入。这些输入被当成事件传送给窗口管理器 (这个窗口管理器在文中也是管理器的一个功能部份) 。键盘、触摸屏与硬件平台相关, 而且又是独占资源, 所以交给管理器是理所当然的, 也可以考虑接受虚拟设备而产生的事件。
2.4.2 窗口管理
管理器提供窗口管理服务, 提供让客户端创建或者销毁窗口。它可以是嵌套的。
窗口管理器在现在流行的系统中, 如x-Window中是一个普通的客户端。这种设计遵循了提供机制而不是功能策略的原则。但这里把窗口管理也交给了管理器。这样做的原因是这个GUI用于低配置的设备使用的机会比较多。为了机制增加资源消耗有点不太可行。
2.4.3 提供字体操作
不管是矢量字体还是点阵字体都是很耗内存资源的。一个TrueType矢量字库就达10M多, 而且这只是一种字体。可想而知如果再增加几种字体, 并在一个窗口中有多种字体存在, 这得耗费多少的内存资源。
所以考虑由管理器提供字体操作的服务。由客户端发起, 向管理器索要字体解析服务。
2.4.4 提供图形操作服务
这里的图形操作服务, 在管理器中只打算让管理器做窗口重叠处理、区域裁减处理, 外加一个图形最终显示处理, 也就是由管理器把各窗口的区域内存刷新到FrameBuffer显示屏缓冲区。
其他的绘图操作准备提供一个虚拟的绘图设备类, 也就是MFC里常说的GDI类。
2.4.5 与桌面进程配合
桌面进程是必须的。它负责启动用户应用程序, 负责整机的设置。与管理器相互监督和唤起。
消息在GUI中采用一个结构体传递。管理器获得事件后通过Socket传递到客户端后, 由客户端 (最终是控件类对象) 解析并构建一个消息结构体, 这个过程对用户程序是透明的。
sgui_peek_message函数是一个阻塞的函数, 通过轮询来读取Socket端口上的通信数据和本窗体中控件的自发消息。
Sgui_translate_message解析收到的事件消息。这个过程是交由当前控件解析产生一个具体的消息。
Sgui_dispatch_message分发消息。根据控件注册的消息来进行消息分发响应。
这个消息循环要放在一个线程里实现, 这个线程的作用就是进行消息的循环处理, 也就是每开一个窗口, 就要创建一个对应的线程, 如果没有消息则线程进入睡眠状态, 也不影响其他窗口收发消息。这样窗口内可以实现动画控件, 窗口间还可以通过消息相互实时通信。
2.5 进程间桌面资源调度
桌面资源在这里其实就是一个显示屏。也就是众多窗口, 哪个进程是当前进程, 则当前进程的当前窗口就显示在最前面, 覆盖掉其他进程的窗口。
这个实际上是管理器提供的窗口管理服务。
管理器的这项服务直接影响到GUI的最终效果。
管理器用一个双向链表管理着所有进程的窗口。
当有键盘按键事件的时候, 该事件直接发往当前进程的当前窗口。
如果触摸屏产生了触摸事件, 触摸屏的驱动程序会把该事件解析出来, 是点下还是弹起, 还是拖动。这种事件往往会导致不是当前进程的窗口获得焦点, 这也是用户的意愿, 他就想把那个仅显示一部分的窗口给弹出来至于最前面, 这个时候管理器需要做一个处理工作, 得判断产生事件的坐标属于哪个窗口区域, 并把这个窗口属于的进程置于最前, 然后在这个进程中判断这个窗口是不是该进程的当前窗口, 如果不是, 则显示这个进程的当前窗口, 当然这个判断过程是从上往下的。被盖住了的窗口是获不到这个事件的。
用一个结构体来描述一下这其中的大致情况。用双向链表方便窗口销毁与创建。同一个应用程序的窗口在同一链表段。
处理窗口的层次关系 (也可以用Z轴来表示) 时, 有一个很重要的情况, 需要管理器做符合用户意图的处理。当几个窗口重叠, 而窗体程序产生自刷新时, 这个时候需要做这样的处理, 遍历层次关系在它之上的窗体, 并计算出需裁剪的区域, 把裁剪出来的区域复制到FrameBuffer缓冲区对应的位置中。这个算法可能有点复杂且需要大量的测试, 考虑到嵌入式系统的独特性, 可以采用缓冲区覆盖复制的方法。而且在这种环境中完全可以避免不规则窗体出现。
使用裁剪的方法, 可以这样来实现, 如果两个窗口发生重叠, 则把这两个窗口裁剪成多个矩形, 当一个窗口与好几个窗口发生重叠的时候, 一个一个裁剪, 形成一个矩形链表, 然后在显示窗口的时候, 遍历裁剪出来的矩形链表把应该显示的矩形显示出来。
2.6 系统资源统一管理与分发
硬件相关的资源都由管理器统一管理。GUI客户端的操作仅对虚拟设备进行操作。这样可以达到一个效果就是当硬件发生变动时, 修改的地方只有一处。同时也解决了硬件资源的抢占问题。系统的资源除了硬件资源外, 还有很多维持系统运转的服务资源。如窗口访问应用程序的Socket套接字, 这里需要对套接字访问加锁操作, 一个对象在操作的时候, 另一个对象需排队等候。
消息也是GUI系统当中的一种资源, 它维系着这个系统的生存。消息源对于一个GUI来说, 有很多个来源, 有来自硬件的, 有来自GUI自身的窗体、控件。需要把这些消息都集中在一个先称它为消息管理的容器中, 然后由这个容器分发出来, 最终消息需要回到这个容器, 由这个容器消毁消息。这个机制是非常需要的, 只有这样才可能轻松地扩展GUI的控件。假定在基类就完成了消息的收发处理, 那么在基类的基础上扩展其他的类就显得不是难事了。也不需要去重新实现消息收发功能了。这相对来说是一个统一与分工的概念。在硬件层面来说, 把其集在一个模块处理方便了更换硬件带来的程序修改。在软件层面来说, 把功能集中在类继承的某一个层次上, 只要不对现有功能接口进行删减, 并不影响其他的功能模块的正常运行。
开发过程中功能模块间低耦合也可以成为衡量这个系统的优良性。
2.7 输入法及控件类库框架规划
输入法是人机交互的一种重要途径。也受很多因素影响, 如人的操作习惯不同, 有人喜欢用拼音, 有人喜欢用五笔, 有人喜欢用笔画, 不光要输入中文, 还要输入英文, 阿拉伯数字。这势必要求输入法是一个可拼装的模块, 当用户需要某种输入法时, 即调出某种输入法。
输入法一般是可编辑控件上才需要的。当一个窗体下有很多个可编辑控件, 是不是要每个可编辑控件都拥有输入法对象呢?如果这样的话, 会造成浪费很多的内存资源。如果可编辑控件使用很少的时候还可以采用这种方法。既然考虑做一个完整的GUI, 在这里花点功夫设定这个输入法框架也是应该的。
输入法其实是一个GUI应用程序, 只是它可以产生事件并发送给管理器。然后由管理器再发送到当前应用程序, 这就需要管理器区分输入法的独特性, 因为输入法这个时候往往是当前进程。
完成这个工作可能有点难度, 不过只要消息途径是通的。基本上不存在什么大的问题。
可编辑控件在需要输入法的时候, 通过消息告诉管理器需要调用出输入法输入。
管理器可以根据配置文件调出相应的输入法, 这个时候输入法就成了当前进程了, 输入法进程所产生的均发送给管理器, 由管理器判断该把这个消息发送给哪个进程的窗口, 消息到了进程, 就很容易由消息分发模块发送到了当前焦点控件。这样做可能有点复杂, 但目前没想出更好的办法来实现它, 如图1所示。
控件类库是供二次开发使用的, 也是GUI的表现之处, 虽然风格可随程序开发员的风格自已定义, 但也直接影响到二次开发方不方便。各种可显示控件有很多相同点, 如它们都需要创建控件的函数、刷新函数、绘图函数、事件解析函数、消息判断函数、消息发送函数这些都是每一个控件必须的, 有了C++的继承的机制可以把这些基本的操作函数集中在一个基类上, 扩展的控件类就不需要处理这些函数了, 除了控件需要在这些基础函数之上再做点其他的事情, 这个时候控件类可以继承实现这个函数。
2.8 编程框架的规划
很多公司衡量开发一个产品的性能, 开发容不容易成了他们主要取舍的标准。
现在很多知名的GUI的编程模式都是基于C的结构式编程模式, 这种模式结构性不太清晰, 像GTK等都是结构式的编程模式。QT是采用C++面向对象的编程模式, 其拥有良好的扩展性, 并且支持面向对象编程, 但QT对C++的语法应用的有点偏门, 有时候不太好把握。暂且利用C++的最基本的封装性、可继承性、多态性就足可以胜任模块化分工。而且编译出来的可执行文件相对使用其他特性的要小很多。
MFC的框架除去复杂的框架、视图、文档部份, 其框架还是比较经典的。完全可以借鉴MFC的编程模式。
2.9 桌面进程的实现
桌面进程是一个GUI的应用程序, 它也是管理器通信, 但它更多的起着管理整个机器的用途, 也就是它与管理器有更多的功能通信。同时它也起着管理器的守护进程, 当发现管理处于僵硬状态, 或者管理器退出, 它可以主动启动管理器。
虽然这个时候桌面进程界面也处于无反应状态, 但后台它可以重新向管理器注册。最坏的情况就是停顿几秒钟就可以恢复过来。
桌面进程是必须的, 当桌面进程出现异常退出或者死锁, 管理器可以检测出来, 并把它启动起来。
桌面进程与管理器成了相互守护的进程。
同时桌面进程负责启动其他的GUI应用程序, 只有通过桌面进程才能正常地启动其他的GUI应用程序。
桌面进程是全屏的, 它也是处于层次关系 (Z轴) 的最底层, 只有按桌面键的时候它才全部重绘并跳到最前。
3 GUI类库层次
如图2所示。
(1) s Object类
SGUI的根类是sObject, SGUI中大多数的类是从基类s Object派生出来的。它定义SGUI类对象的基本行为。
(2) s Application类
sApplication类是应用程序类, 这个类的实例的生命周期从应用程序开始到应用程序结束。它负责与GUI窗口管理器沟通信息, 是用户应用程序的入口处与出口处。入口处负责与窗口管理器沟通, 进行相关控制信息沟通。
(3) s Cwnd类
s Cwnd类是窗体的基类, 它由sEvent派生出来。它提供消息类型解析, 控件刷新, 自刷新的虚函数。窗体相关控件类需要继承这些函数。
(4) s Window_manager类
s Window_manager类是窗口管理类, 每个窗口都会像sWindow_manager类进行登记, 当窗口关闭时, 则在管理链表中删除。当应用程序类收到广播消息时, 它可以给每个窗口发送消息。当然这个类在管理器端也会有类似的管理链表。
(5) s Window类
s Window类是窗口类, 每个窗口类本身开启的时候都给自身的消息处理函数开启一个线程。只要这个函数能把消息接收进来并且发送出去, 就能保证系统的正常运行。
其他的类为SGUI的控件类。
4 管理器
在管理器中最为复杂的算法估计就是窗口的调度与控件区域绘图算法了, 如图3所示。
(1) 窗口的分类
(2) 窗口的属性
决定窗口处于最前面的消息有两种: (1) 窗口中属性为一直停留在最前面, 当这种窗口有绘画动作的时候, 一般覆盖性地即时显示; (2) 有点击事件或者调出消息时, 这种时候窗口也处于最前面。当处于最前面的窗口为最大化的时候, 则后续的窗口不再判断重绘了。
控件区域重绘考虑到裁减窗口的算法的时效性与全重绘的时效性不分上下, 从程序复杂性来讲, 全重绘性能更高, 所以在这里控件采用全重绘的方法。
5 结语
GUI是一个成熟的计算机应用领域。
从实现一个GUI的角度出发, 论述了实现一个完整的GUI的几个重要的部份。
参考文献
[1]Stanley B.Lippman李师闲, 等.C++Primer中文版.第4版.北京:人民邮电出版社, 2006, 3.
[2]李玉东, 李玉萍.精通嵌入式Linux编程:构建自己的GUI环境.北京航空航天大学出版社, 2010.
Linux嵌入式技术
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。