熊 杰,劉新德,馮仁劍
(北京航空航天大學 儀器科學與光電工程學院,北京100191)
圖形用戶界面 (graphical user interface,GUI)的引入為嵌入式設備提供了圖形化的監控和控制界面,提升了嵌入式系統的整體功能并降低了復雜性[1]。針對嵌入式系統,現有的GUI開發主要有自下而上逐步開發和使用嵌入式GUI系統兩種方式[2]。自下而上的GUI開發方式易于實現,但沒有將GUI作為一個軟件層從應用程序中剝離,導致開發效率不高,代碼復用性差。嵌入式GUI系統將顯示邏輯和數據處理邏輯劃分開,使得圖形界面開發相對獨立,且避免了代碼重復,便于實現應用程序開發。
目前,國內外針對嵌入式應用研究開發了一些GUI系統。Microwindows是Century Software公司開發的將GUI引入到小型設備平臺的項目[3]。Microwindows的圖形引擎開發比較完善,采用標準客戶/服務器結構,具有一定靈活性。但該結構占用更多系統資源,降低了系統效率。Trolltech公司在QT的基礎上開發實現的QT/Embedded[4],使用C++開發,功能完善。但其代碼所占用空間較大,且依賴于Linux操作系統,移植性差。MiniGUI是一種為嵌入式系統提供圖形用戶界面支持的中間件技術,早期由魏永明先生主持開發[5]。MiniGUI的窗口系統和應用開發接口完善,但基于Linux開發,難以移植到非POSIX標準的目標平臺,且過多注重于窗口模型的接口抽象,開發過于繁瑣。
為解決工業控制設備中的圖形顯示問題,有必要針對上述嵌入式GUI系統存在的平臺依賴性和輕型性等方面的不足,設計并實現一種輕量級嵌入式圖形用戶界面LIGUI系統。LIGUI采用雙向鏈表結構組織窗口,避免復雜的窗口剪切和操作;利用輸入輸出抽象層屏蔽具體硬件平臺的不一致,實現系統的移植;提供應用編程接口和配置選項,易裁剪和配置;核心層采用微內核的設計思想,具有輕量級的特點。
LIGUI系統采用分層體系結構,每層負責內部的具體實現,底層通過接口為上層提供服務,實現將層次內部的修改隔離,不影響上層調用底層完成相應功能。
如圖1所示,LIGUI總體上分為3層,分別為硬件抽象層,GUI核心層和應用接口層。

圖1 LIGUI系統體系結構
其中,硬件抽象層為上層模塊提供一致接口,解決移植問題;GUI核心層完成圖形圖像繪制,窗口的組織和消息管理;應用接口層為用戶提供應用編程接口和配置選項,可以實現系統擴展。
由于嵌入式應用硬件平臺的多樣性,為實現LIGUI系統在不同底層設備之間的移植,抽象了輸入輸出設備的功能,并且提供一致的接口。針對不同的輸入輸出設備編寫硬件驅動程序,在此基礎上將輸入輸出抽象層獨立出來,封裝底層系統和硬件設備的功能函數,使得上層的界面繪制和輸入處理在訪問不同硬件設備時,無需考慮系統和設備差異帶來的影響。硬件抽象層包括輸入抽象層和輸出抽象層。
1.1.1 輸入抽象層
輸入抽象層將輸入設備的功能抽象為統一的輸入接口[6]。任何獨立按鍵、矩陣鍵盤、虛擬鍵盤的按下動作都可以抽象出鍵值和敲擊次數;對于鼠標移動和觸摸屏的點擊輸入,可以提取坐標值和按壓狀態信息。
1.1.2 輸出抽象層
輸出抽象層的主要功能是為圖形圖像的繪制輸出提供顯示設備接口,上層圖形程序的編寫只需調用接口數據結構提供的函數,而不用考慮針對不同底層顯示設備的具體實現。
顯示輸出最終都要對應到單個像素點的操作,所以在數據結構中定義屏幕像素點的信息,抽象出SetPixel和GetPixel接口。顯示設備接口用結構體LCDAPI來表示。
typedef struct{
void (*InitLcd)();
void (*SetPixel)(Pixel pixel,int x,int y);
void (*GetPixel)(Pixel*pPixel,int x,int y);
int(*GetXSize)();
int(*GetYSize)();
U8(*GetBPP)();
void (*InitPalette)(U8bpp);
}LCDAPI;
提供讀取顯示設備的屬性信息接口,包括屏幕尺寸GetXSize和GetYSize,每個像素點的位數GetBPP,以及初始化調色板InitPalette。
應用接口層負責給用戶提供系統的應用編程接口,方便系統擴展。用戶程序通過調用應用接口層封裝的接口函數完成界面設計以及數據邏輯的處理,LIGUI負責輸入事件響應,消息的接受和分發,以及顯示的更新。
應用編程接口為用戶提供如下對象的操作:
作圖原語集:完成LIGUI的繪圖功能;
窗口類對象:實現對窗口的組織和操作;
控件類對象:完成對控件的管理和使用。
應用接口層提供可配置選項,可以實現對LIGUI系統的裁剪和配置,以滿足具體應用環境的需求。
核心層實現LIGUI的關鍵功能,采用模塊化設計,模塊之間低耦合,內部結構的修改不影響其接口,可以有效支持裁剪,滿足系統輕量級的需求[7]。核心層包括圖形圖像模塊、窗口管理模塊和消息系統。
圖形圖像模塊提供圖形、文本和各種圖像的繪制,窗口與消息模塊完成窗口組織和操作,輸入輸出事件消息和窗口消息的分發。
圖形圖像模塊實現圖形圖像和文本的繪制輸出,調用輸出抽象層提供的顯示設備接口,在單個像素點繪制的基礎上完成圖形圖像的繪制。向上層以作圖原語集的形式為應用提供調用接口。
2.1.1 基本圖形繪制
向上層LIGUI對象提供基本繪圖原語的圖形服務,完成基本幾何圖形的繪制和填充,如點、直線、圓、矩形、橢圓、多邊形等。
支持與設備無關的圖形操作,所有繪圖函數都以顯示設備接口SetPixel為基礎,從繪制一個像素點出發,而線段是由點連接組成,多邊形的繪制、填充也是由點和線段組合而成的,進而完成全部顯示區域的繪制。
對于圖形圖像繪制而言,直線和圓弧作為描述所有圖形的基礎,其效率直接影響到整個LIGUI系統的顯示效率。采用改進的Bresenham算法繪制直線和圓弧,充分利用圖形斜率的幾何特性和點與點之間的相關性,一次可計算出若干個點,提高了繪制效率[8]。
2.1.2 文本輸出
文本輸出功能向屏幕顯示字符和漢字,完成字符在字符集中的查找和繪制輸出。
為提高顯示效率和節省資源空間,LIGUI采用點陣字體,單獨用數組來定義每個字符的點陣,然后將每一個字符的信息用CHAR_INFO結構體來表示。
typedef struct{
U8XSize;
U8YSize;
U8BytesPerLine;
const U8*pData;
}CHAR_INFO;
結構體中定義的字符信息包括字符點陣的高和寬,每行的字節數,以及字符點陣數據指針。
將所有字符信息存入一個數組中構成字符集。由于漢字的機內碼不連續,是區間分布的,所以將所有漢字分成若干個字符集區段,各個字符集區段以鏈表組織起來。如下的FONT_INFO為字符集區段的數據結構,包括字符集區段中首末字符的索引FirstChar和LastChar,首個字符信息的指針pCharInfo和指向下一個字符集區段的指針pNext。
typedef struct{
U16FirstChar;
U16LastChar;
const CHAR_INFO*pCharInfo;
const FONT_INFO*pNext;
}FONT_INFO;
利用漢字的機內碼對字符集鏈表進行索引,先找到要顯示字符所在的字符集區段,返回字符集區段的指針,再根據字符相對字符集區段中第一個字符地址的偏移量,找到要顯示字符的字符信息。
2.1.3 圖像模塊
LIGUI支持顯示BMP格式的圖像文件,BMP文件本身就包含了設備無關位圖格式,經文件調用讀入內存,再結合顯示設備特性轉換成設備相關位圖[9]。
同時,LIGUI支持其它圖像格式繪制的接口,其文件解碼都使用第三方標準庫來完成,然后將位圖選入到圖形設備上下文中,以便上層應用程序進行繪圖操作。
窗口管理模塊負責窗口組織、窗口繪制和窗口操作,是LIGUI系統組織圖形圖像輸出,處理外設輸入的基礎。
由于嵌入式應用的顯示屏一般不大,窗口可以獨占整個屏幕,不必考慮相互剪切的位置關系。LIGUI系統的窗口組織采用雙向鏈表結構,如圖2所示。

圖2 窗口組織結構
窗口創建時即建立一個節點,窗口中的控件繼承了窗口的特性,并且加入窗口節點。節點與節點之間組成一個鏈表。當刪除窗口時,將窗口從窗口鏈表中移除,并遞歸銷毀其所有子控件。窗口鏈表還能表示窗口之間的覆蓋關系,鏈表后端的窗口覆蓋前端的窗口,所以對窗口進行前置、后置操作即相當于在窗口鏈表上向前或向后移動窗口節點。
LIGUI用WIN_Obj結構體來描述窗口,這個結構中記錄了窗口對象的基本性質和窗口函數等屬性。
typedef struct{
int hWin;
int x0,y0,x1,y1;
U8*title;
WIN_Obj*pPre;
WIN_Obj*pNext;
int hFocussedChild;
int WidgetNum;
void(*WinManage)(MSG_Obj*pMsg);
int StatusFlag;
}WIN_Obj;
其中,hWin是系統中窗口對象全局唯一的標識,即窗口對象的句柄;x0,y0,x1,y1是窗口矩形區域的坐標值,存儲窗口的位置和大小;title指向窗口標題字符串;pPre和pNext為指向鏈表中上一個窗口節點和下一個節點的指針;hFocussedChild為處于焦點的子控件的句柄,Widget-Num為窗口子控件的數目;WinManage是窗口過程函數指針,完成各種消息的響應處理;StatusFlag存儲窗口的狀態信息。
LIGUI系統采用事件驅動機制。消息系統是事件驅動的圖形用戶界面的關鍵,保障整個系統流程有序進行,消息由事件產生[10],LIGUI的事件包括輸入設備事件,窗口操作事件,以及系統定時、用戶自定義等其它事件。
事件的產生具有隨機性,LIGUI用消息表示各種事件。在外設驅動和輸入抽象層提供的硬件接口基礎上,用消息結構封裝實現用戶輸入事件,轉化為輸入消息;系統運行過程中引起的窗口狀態改變,會產生與窗口操作相關的邏輯消息;同時,用戶可以自定義消息和響應處理。
將不同類型的消息用一個消息結構表示,并且定義類型字段來區分各種消息類型。如下MSG_Obj為消息對象結構體,用于表示事件消息。
typedef struct{
int MsgID;
int hWinTag;
int hWinSrc;
int MsgData;
void*p;
}MSG_Obj;
其中,用MsgID作為類型字段來區分不同的消息類型;hWinTag和hWinSrc分別為接受消息的目標窗口句柄和消息源窗口句柄;MsgData用于存儲消息具體數據,如果數據超過整形范圍可以用數據指針p表示。
2.3.1 消息系統結構
消息系統結構如圖3所示,包括消息隊列、消息循環和窗口過程等。

圖3 消息系統結構
同步消息經過消息循環直接交給窗口過程函數處理,異步消息進入消息隊列等待處理。
消息隊列組織異步消息,負責事件壓縮和過濾重復無用的事件消息。
消息循環從消息隊列讀取消息,發送至目標窗口,窗口過程函數將消息結構作為參數,執行相應的消息響應過程。
2.3.2 消息循環
消息循環是消息系統和圖形用戶界面應用程序的核心部分,是將從消息隊列輪詢獲得的消息分發至目標窗口的循環過程[11]。消息循環流程如圖4所示。

圖4 消息循環
消息循環不斷輪詢消息隊列,若隊列為空,則執行空消息處理,若不為空且不是退出消息,則調用消息發送函數進行分發和投遞,送達目的窗口,即調用指定窗口的窗口過程函數,并傳遞消息為其參數。目標窗口的窗口過程負責解釋所接收的消息,由MsgID確定具體的消息類型,進行分類處理。處理結束后,重新進入消息循環,當收到退出消息時,退出消息循環。
LIGUI系統采用的這種消息機制支持用戶自定義消息,利用自定義的消息傳遞數據,并且在窗口過程對自定義消息類型進行處理,滿足了嵌入式GUI系統對擴展性的需求。
LIGUI系統現已應用在太陽能控制器配套的手持設備中,用于對太陽能控制器進行參數設定和管理。手持控制器如圖5所示。

圖5 手持控制器
手持控制器采用基于Cortex-M3內核的STM32F103VBT6處理器,外擴Flash存儲器采用SST25VF016B芯片,用于存儲字庫和位圖的點陣文件,其它外設包括液晶顯示屏、紅外收發器、矩陣鍵盤、蜂鳴器、LED指示燈和RS232/485通信口。
手持控制器作為太陽能控制器的圖形化顯示和操作控制終端,采用2.6寸TFT彩色液晶,像素點總數為320×240。其圖形用戶界面的顯示基于LIGUI體系結構實現,采用層次化、模塊化的結構設計來組織各參數設置界面之間的邏輯關系,界面顯示及切換流暢,使用方便、靈活。其界面結構圖如圖6所示。

圖6 界面結構
實現手持控制器的界面顯示,LIGUI核心部分代碼所占用靜態存儲空間不足30KB。通過調用LIGUI系統提供的應用編程接口和修改配置選項,編程開發者只需編寫底層硬件驅動和進行數據邏輯處理,開發周期短,效率高。
采用分層次和模塊化的結構體系,設計并實現了一種輕量級嵌入式圖形用戶界面LIGUI系統。系統通過硬件抽象層來隔離不同底層設備;采用高效的算法進行圖形圖像繪制;在應用接口層為用戶提供已封裝的應用編程接口,提高了開發編程效率。
將實現的LIGUI系統作為圖形顯示模塊應用于手持控制設備,解決了自底層到頂層的GUI開發方法導致的開發效率低、代碼復用性差的問題。實際應用表明,LIGUI系統具有輕型的特點,占用資源少,且功能齊全,能夠支持運行在低端配置的系統。系統配置選項提供窗口、控件等模塊的裁剪,可以實現具體嵌入式環境下的定制和擴展。
[1]Bjelica M Z,Teslic N,Papp I,et al.A characterization to evaluate graphical user interface frameworks for television receivers[C].The 9th International Conference on Telecommunication in Modern Satellite,Cable,and Broadcasting Services(TELSIKS),2009:285-288.
[2]Scoditti A,Stuerzlinger W.A new layout method for graphical user interfaces [C].The IEEE Toronto International Con-ference on Science and Technology for Humanity.2009:642-647.
[3]Greg Haerr.The Nano-X Window system [EB/OL].http://www.microwindows.org,2010.
[4]Trolltech Inc Qt/Embedded Whitepaper [EB/OL].http://www.trolltech.com/files/pdf/qt-4.6-whitepaper,2009.
[5]Beijing Feynman Software Technology Co,Ltd.MiniGUI technology white paper [EB/OL].http://www.minigui.org/fileadmin/minigui_org_downloads/MiniGUITechWhitePaper-2.0-4E.pdf,2007.
[6]Bode S,Riebisch M.Usability-focused architectural design for graphical user interface components [C].The International Conference on Computational Intelligence for Modelling Control& Automation,2008:1246-1251.
[7]Lamberti F,Sanna A.Extensible GUIs for remote application control on mobile devices [J].IEEE Computer Graphics and Applications,2008,28 (4):50-57.
[8]LOU Jiantao,WANG Xiuhe.Anti-aliasing line drawing algorithm based on symmetry [J].Computer Engineering and Applications,2011,47 (1):173-175 (in Chinese). [樓劍濤,王秀和.基于對稱的反走樣直線生成算法 [J].計算機工程與應用,2011,47 (1):173-175.]
[9]Luostarinen R,Manner J,M tt J,et al.User-centered design of graphical user interfaces [C].Military Communications Conference,2010:50-55.
[10]Yoshida M.A succinct graphical user interface programming model for low-end embedded devices [C].The 13th IEEE International Symposium on Consumer Electronics,2009:920-921.
[11]HE Xiang,MENG Xiaohua.Design and implementation of humancomputer interface in embedded intelligent home system [J].Computer Engineering and Design,2010,31 (10):2166-2168 (in Chinese).[賀翔,孟小華.嵌入式智能家居終端人機界面設計與實現 [J].計算機工程與設計,2010,31 (10):2166-2168.]