基于ulTRON操作系统的嵌入式GUI设计
本设计是在东南大学国家专用集成电路系统工程技术研究中心自主研发的,并在遵循uITRON 3.0标准的RTOS-ASIX OS基础上设计出一套适合于手持设备、仪器仪表等应用的图形用户界面一一ASIX Window。该图形用户界面采用面向对象的设计思想,基于消息循环和事件驱动机制,构建了比较完整的窗口系统,为用户提供了类Win32 API的用户编程接口。考虑到一般嵌入式应用的屏幕较小,以及嵌入式系统处理器与存储器容量的限制,ASIX Window在设计上放弃了窗口剪切等复杂特性,大大降低了系统的复杂性,减少了对系统资源的占用。由于采用基于控件的设计概念,ASIX Window非常适合裁减,可以根据用户的需求方便地增加或删减控件,增加了系统的可裁减性。该图形用户界面已成功应用于PDA,电子词典,税控收款机等多款产品设计中。
1 与操作系统内核的接口
ASIX Window的整体架构是基于消息分发,消息循环以及消息处理之上的。整个ASIX OS平台的结构如图1所示。图1中,最底层的是系统的消息源,包括中断(键盘、触摸屏等)和定时器,一般将它们统称为中断源。中断发生后,进入中断处理程序,该中断处理程序维护其对应的缓冲区后(如果它需要缓冲区),设置事件发生(通过调用内核的事件标志系统调用)。因为系统任务是阻塞在这个事件标志上的,而且系统任务的优先级最高,系统任务将被内核调度运行,系统任务根据所发生事件的类型,来进行相应的处理。比如说,如果是笔中断事件,中断处理程序将笔的坐标信息存放在相应的缓冲区中,并设置相应的事件标志,系统任务将笔坐标的数据转换为相应活动区域(Active Area)的消息,并由系统任务将这个消息发送到当前需要该中断事件的任务中。LCD显示,键盘和笔中断一定是由前台任务(拥有屏幕的任务)接管的,其他外围设备所对应的中断源则由占用该资源的任务接管。
每个任务都有一个自己的信箱(Mail B0x),在每个信箱上都维护着一条消息队列,所有发往该任务的消息都连接在这个队列中。任务代码应该通过消息循环不断地从该队列中取消息并处理,如果消息队列为空,则该任务阻塞,由ASIX OS内核选择下一个就绪的高优先级任务运行。
系统任务是内核的扩展,提供系统基本的服务功能和接口。它接管系统所有的中断资源并将相应的中断事件翻译成为相应的系统消息,并将该消息分发到对应的应用程序任务;系统任务同时维护系统中所有任务的信息,负责确定前台任务(拥有显示屏幕和用户输入焦点的任务,前台任务不一定是CPU正在运行的任务)以及前台任务的切换。系统任务阻塞在底层中断的事件标志上,系统任务拥有最高的优先级。
在系统任务之上是服务任务。服务任务负责提供系统的其他扩展服务。服务任务没有屏幕显示(类似于Linux中的守护进程),服务任务阻塞在自己的消息队列
上。服务任务拥有第二高的优先级。
应用程序任务是用户使用的各个应用。应用任务阻塞在自己的消息队列上,所有的应用程序一般都应该拥有屏幕显示,所有的应用程序在同一优先级上。
2 窗口管理
ASlX Windows是基于消息驱动的图形用户接口。从ASIXWindows的角度来看,应用程序是由一组窗口和控件组成的,程序的功能是通过窗口的操作来实现的。控件是在ASIX Windows中定制的具有特定功能的独立模块,例如:按钮、菜单、下拉框、软键盘等。在ASIX Windows中,每一个控件在数据结构上都被描述为一个窗口(也就是说,在数据结构上,窗口和控件是一样的),不同的是,控件是作为某个窗口的子窗口。在数据结构上将窗口与控件统一,使得整个系统的结构更简单,对窗口的操作与对控件的操作可以统一到一起,这使得系统的编程接口可以统一到窗口的操作函数上。在ASIX Windows中所有的窗口操作,不管是窗口或是控件,都使用这些统一的函数。系统通过下面这个统一的数据结构来对所有的控件进行管理。
typedef struct asix_window
{ struct asix window *prey}//指向前一个兄弟窗口
struct asix_window *next;//指向后一个兄弟窗口
struct asix_window *child;//指向子窗口链表
/*本窗口的相关ID*/
WNDCLASS *wndclass;//指向本窗口的窗口类
U32 task_id; //本窗口所属任务的任务号
U32 wnd_id; //本窗口ID号
U32 parent_id; //本窗口的父窗口 ID号
/*本窗口的位置、状态、风格以及窗口标题等*/
U32 status; //本窗口状态
U16 x; //本窗口左上角x坐标
U16 v; //本窗口左上角Y坐标
U16 width; //本窗口的宽度
U16 hight; //本窗口的高度
char *caption} //本窗口标题
U32 style; //本窗口风格
/*指向本窗口私有数据结构的指针*/
void *etrl_str; //指向本窗口的私有数据结构
}ASIX_WINDOW;
实际上,不同的控件拥有不同的功能和结构,所以它们的操作是不同的。为了拥有统一的操作函数接口,为每一个不同的窗口或控件定义了相应的窗口类,窗口类实际上是每种控件的模版,这个模版定义了与该控件相关的内容。当应用程序员调用CreatWindow函数创建某类控件时,CreatWindow查找该类控件的窗口类,并根据窗口类中的定义,调用与该控件相关的创建函数,进行实际的创建工作。然后CreatWindow填写相应的数据结构,描述该控件类的实例,并将其链接到系统窗口链表中去,以便后续的管理。利用窗口类描述不同控件设计的同时,可以将不同控件的开发独立于系统构架的实现,使得控件的开发可以独立进行。使用独立窗口类来描述每个控件的另一个好处是可以非常方便的对ASIX Window进行裁减。下面给出窗口类数据结构的定义。
typedef struct window_class
{ U8 wndclass_id; //窗口类的ID号
//CreateWindow()调用本函数执行控件的具体创建
STATUS (。create)(char‘caption,U32 style,U16 x,
U16 Y,U16 width,U16 hight,U32 wndid,U32 menH,void*
*etrl_str,void*exdata);
//DestroyWindow()调用本函数执行控件的具体删除
STATUS (*destroy)(void*ctrl_str);
//DefWindowProc()调用本函数进行消息处理
STATUS (。msg_proe)(U32 win_id,U16 asix_msg
评论