Qt/Embedded在嵌入式Linux系統(tǒng)中的應(yīng)用
摘要:分析和討論qt/embedded的主流版本3.x系列的底層實(shí)現(xiàn)技術(shù);結(jié)合2.x版本系列和3.x版本系列,在兩種不同的硬件平臺(tái)(intel pxa255開(kāi)發(fā)系統(tǒng)與筆者自行設(shè)計(jì)的motorola mc9328 mx1開(kāi)發(fā)系統(tǒng))上的移植過(guò)程,討論qt/embedded的底層設(shè)備接口與應(yīng)用移植技術(shù)。 關(guān)鍵詞: 引言 隨著嵌入式linux應(yīng)用的不斷發(fā)展,嵌入式處理器運(yùn)算能力的不斷增強(qiáng),越來(lái)越多的嵌入式設(shè)備開(kāi)始采用較為復(fù)雜的gui系統(tǒng),手持設(shè)備中的gui系統(tǒng)發(fā)展得非常迅速。傳統(tǒng)的gui系統(tǒng),如microwindows等,由于項(xiàng)目規(guī)模較小、功能較為薄弱,缺乏等三方軟件開(kāi)發(fā)的支持等諸多原因,在比較高級(jí)的手持或移動(dòng)終端設(shè)備(如pda、smart-phone、車(chē)載導(dǎo)航系統(tǒng))中應(yīng)用較少。 qt/embedded是著名的qt庫(kù)開(kāi)發(fā)商trolltech公司開(kāi)發(fā)的面向嵌入式系統(tǒng)的qt版本,開(kāi)發(fā)人員多為kde項(xiàng)目的核心開(kāi)發(fā)人員。許多基于qt的x window程序可以非常方便地移植到qt/embedded上,與x11版本的qt在******程度上接口兼容,延續(xù)了在x上的強(qiáng)大功能,在底層徹底摒棄了x lib,僅采用framebuffer作為底層圖形接口。qt/embedded類(lèi)庫(kù)完全采用c++封裝。豐富的控件資源和較好的可移植性是qt/embedded最為優(yōu)秀的一方面,使用x下的開(kāi)發(fā)工具qt designer可以直接開(kāi)發(fā)基于qt/embedded的ui(用戶(hù)操作接口)界面。越來(lái)越多的第三方軟件公司也開(kāi)始采用qt/embedded開(kāi)發(fā)嵌入式linux下的應(yīng)用軟件。其中非常著名的qt palmtop environment(qtopia)早期是一個(gè)第三方的開(kāi)源項(xiàng)目,并已經(jīng)成功應(yīng)用于多款高檔pda。trolltech公司針對(duì)smart-phone中的應(yīng)用需求,于2004年5月底發(fā)布了qtopia的phone版本。 1 qt/embedded的實(shí)現(xiàn)技術(shù)基礎(chǔ)分析 橫向來(lái)看,由于發(fā)布的版權(quán)問(wèn)題,qt/embedded采用兩種方式進(jìn)行發(fā)布:在gpl協(xié)議下發(fā)布的free版與專(zhuān)門(mén)針對(duì)商業(yè)應(yīng)用的commercial版本。二者除了發(fā)布方式外,在源碼上沒(méi)有任何區(qū)別??v向看來(lái),當(dāng)前主流的版本為qtopia的2.x系列與最新的3.0x系列。其中2.0版本系統(tǒng)較多地應(yīng)用于采用qtopia作為高檔pda主界面的應(yīng)用中;3.x版本系列則應(yīng)用于功能相對(duì)單一,但需要高級(jí)gui圖形支持的場(chǎng)合,如volvo公司的遠(yuǎn)程公交信息系統(tǒng)。圖1為qt/embedded的實(shí)現(xiàn)結(jié)構(gòu)。 3.x版本系列的qt/embedded相對(duì)于2.x版本系統(tǒng)增加了許多新的模塊,如sql數(shù)據(jù)庫(kù)查詢(xún)模塊等。幾乎所有2.x版本中原有的類(lèi)庫(kù),在3.x版本中都得到極大程度的增強(qiáng)。這就極大地縮短了應(yīng)用軟件的開(kāi)發(fā)時(shí)間,擴(kuò)大了qt/embedded的應(yīng)用范圍。 1.1 qt/embedded的圖形引擎實(shí)現(xiàn)基礎(chǔ) qt/embedded的底層圖形引擎基于framebuffer。framebuffer是在linux內(nèi)核架構(gòu)版本2.2以后推出的標(biāo)準(zhǔn)顯示設(shè)備驅(qū)動(dòng)接口。采用mmap系統(tǒng)調(diào)用,可以將framebuffer的顯示緩存映射為可連續(xù)訪(fǎng)問(wèn)的一段內(nèi)存儲(chǔ)針。由于目前比較高級(jí)的arm體系的嵌入式cpu中大多集成了lcd控制模塊,lcd控制模塊一般采用雙dma控制器組成的專(zhuān)用dma通道。其中一個(gè)dma可以自動(dòng)從一個(gè)數(shù)據(jù)結(jié)構(gòu)隊(duì)列中取出并裝入新的參數(shù),直到整個(gè)隊(duì)列中的dma操作都已完成為止。另外一個(gè)dma與畫(huà)面緩沖區(qū)相關(guān),這部分由兩個(gè)dma控制器交替執(zhí)行,并每次都自動(dòng)按照預(yù)定的規(guī)則改變參數(shù)。雖然使用了雙dma,但這兩個(gè)dma控制器的交替使用對(duì)于cpu來(lái)說(shuō)是不可見(jiàn)的。cpu所獲得的只是由兩個(gè)dma組成的一個(gè)“通道”而已。 framebuffer驅(qū)動(dòng)程序的實(shí)現(xiàn)分為兩個(gè)方面:一方面是對(duì)lcd及其相關(guān)部分的初始化,包括畫(huà)在緩沖區(qū)的創(chuàng)建和對(duì)dma通道的設(shè)置;另外一方面是對(duì)畫(huà)面緩沖區(qū)的讀寫(xiě),具體到代碼為read、write、lseek等系統(tǒng)調(diào)用接口。至于將畫(huà)面緩沖區(qū)的內(nèi)容輸出到lcd顯示屏上,則由硬件自動(dòng)完成。對(duì)于軟件來(lái)說(shuō)是透明的。當(dāng)對(duì)于dma通道和畫(huà)面緩沖區(qū)設(shè)置完成后,dma開(kāi)始正常工作,并將緩沖區(qū)中的內(nèi)容不斷發(fā)送到lcd上。這個(gè)過(guò)程是基于dma對(duì)于lcd的不斷刷新的?;谠撎匦?,framebuffer驅(qū)動(dòng)程序必須將畫(huà)面緩沖區(qū)的存儲(chǔ)空間(物理空間)重新映射到一個(gè)不加高緩存和寫(xiě)緩存的虛擬地址區(qū)間中,這樣能才保證應(yīng)用程序通過(guò)mmap將該緩存映射到用戶(hù)空間后,對(duì)于該畫(huà)面緩存的寫(xiě)操作能夠?qū)崟r(shí)的體現(xiàn)在lcd上。 在qt/embedded中,qscreen類(lèi)為抽象出的底層顯示設(shè)備基類(lèi),其中聲明了對(duì)于顯示設(shè)備的基本描述和操作方式,如打開(kāi)、關(guān)閉、獲得顯示能力、創(chuàng)建gfx操作對(duì)象等。另外一個(gè)重要的基類(lèi)是qgfx類(lèi)。該類(lèi)抽象出對(duì)于顯示設(shè)備的具體操作接口(圖形設(shè)備環(huán)境),如選擇畫(huà)刷、畫(huà)線(xiàn)、畫(huà)矩形、alpha操作等。以上兩個(gè)基類(lèi)是qt/embedded圖形引擎的底層抽象。其中所有具體函數(shù)基本都是虛函數(shù),qt/embedded對(duì)于具體的顯示設(shè)備,如linux的framebuffer、qt virtual framebuffer做的抽象接口類(lèi)全都由此繼承并重載基類(lèi)中的虛函數(shù)實(shí)現(xiàn)。圖2為qt/embedded中底層圖形引擎實(shí)現(xiàn)結(jié)構(gòu)。 qt/embedded在體系上為c/s結(jié)構(gòu),任何一個(gè)qt/embedded程序都可以作為系統(tǒng)中唯一的一個(gè)gui server存在。當(dāng)應(yīng)用程序首次以系統(tǒng)gui server的方式加載時(shí),將建立qwsserver實(shí)體。此時(shí)調(diào)用qwsserver::opendisplay()函數(shù)創(chuàng)建窗體,在qwsserver::opendisplay()中對(duì)qwsdisplay::data中的init()加以調(diào)用;根據(jù)qgfxdriverfactory實(shí)體中的定義(qlinuxfbscreen)設(shè)置關(guān)鍵的qscreen指針qt_screen并調(diào)用connect()打開(kāi)顯示設(shè)備(dev/fb0)。在qwsserver中所有對(duì)于顯示設(shè)備的調(diào)用都由qt_screen發(fā)起。至此完成了qt/embedded中qwsserver的圖形發(fā)生引擎的創(chuàng)建。當(dāng)系統(tǒng)中建立好gui server后,其它需要運(yùn)行的qt/embedded程序在加載后采用共享內(nèi)存及有名管道的進(jìn)程通信方式,以同步訪(fǎng)問(wèn)模式獲得對(duì)共享資源framebuffer設(shè)備的訪(fǎng)問(wèn)權(quán)。 1.2 qt/embedded的事件驅(qū)動(dòng)基礎(chǔ) qt/embedded中與用戶(hù)輸入事件相關(guān)的信號(hào),是建立在對(duì)底層輸入設(shè)備的接口調(diào)用之上的。qt/embedded中的輸入設(shè)備,分為鼠標(biāo)類(lèi)與鍵盤(pán)類(lèi)。以3.x版本系列為例,其中鼠標(biāo)設(shè)備的抽象基類(lèi)為qwsmouse handler,從該類(lèi)又重新派生出一些具體的鼠標(biāo)類(lèi)設(shè)備的實(shí)現(xiàn)類(lèi)。該版本系列的qt/embedded中,鼠標(biāo)類(lèi)設(shè)備的派生結(jié)構(gòu)如圖3所示。 與圖形發(fā)生引擎加載方式類(lèi)似的,在系統(tǒng)加載構(gòu)造qwsserver時(shí),調(diào)用qwsserver::openmouse與qwsserver::openkeyboard函數(shù)。這兩個(gè)函數(shù)分別調(diào)用qmousedriverfactory::cr-eate()與qkbddriverfactory::cr-eate()函數(shù)。這時(shí)會(huì)根據(jù)linux系統(tǒng)的環(huán)境變量qws_mouse_proto與qws_keyboard獲得鼠標(biāo)類(lèi)設(shè)備和鍵盤(pán)類(lèi)設(shè)備的設(shè)備類(lèi)型和設(shè)備節(jié)點(diǎn)。打開(kāi)相應(yīng)設(shè)備并返回相應(yīng)設(shè)備的基類(lèi)句柄指針給系統(tǒng),系統(tǒng)通過(guò)將該基類(lèi)指令強(qiáng)制轉(zhuǎn)換為對(duì)應(yīng)的具體子類(lèi)設(shè)備指針,獲得對(duì)具體鼠標(biāo)類(lèi)設(shè)備和鍵盤(pán)類(lèi)設(shè)備的調(diào)用操作。 值得注意的是,雖然幾乎鼠標(biāo)類(lèi)設(shè)備的功能上基本一致,但由于觸摸屏和鼠標(biāo)底層接口并不一樣,會(huì)造成對(duì)上層接口的不一致。舉例來(lái)講,從鼠標(biāo)驅(qū)動(dòng)接口中幾乎不會(huì)得到絕對(duì)位置信息,一般只會(huì)讀到相對(duì)移動(dòng)量。另外,鼠標(biāo)的移動(dòng)速度也需要考慮在內(nèi),而觸摸屏接口則幾乎是清一色的絕對(duì)位置信息和壓力信息。針對(duì)此類(lèi)差別,qt/embedded將同一類(lèi)設(shè)備的接口部分也給予區(qū)別和抽象,具體實(shí)現(xiàn)在qmousedriverinterface類(lèi)中。鍵盤(pán)類(lèi)設(shè)備也存在類(lèi)似問(wèn)題,同樣引入了qkbddriver inteface來(lái)解決。具體實(shí)現(xiàn)此處暫不多述。 2 qt/embedded的移植與應(yīng)用 針對(duì)qt/embedded的實(shí)現(xiàn)特點(diǎn),移植該嵌入式gui系統(tǒng)一般分為以下幾個(gè)步驟: ①設(shè)計(jì)硬件開(kāi)發(fā)平臺(tái),并移植linux操作系統(tǒng); ②采用靜態(tài)鏈接進(jìn)linux內(nèi)核的方式,根據(jù)該平臺(tái)顯示設(shè)備的顯示能力,開(kāi)發(fā)framebuffer驅(qū)動(dòng)程序; ③開(kāi)發(fā)針對(duì)該平臺(tái)的鼠標(biāo)類(lèi)設(shè)備驅(qū)動(dòng)程序,一般為觸摸屏或usb鼠標(biāo); ④開(kāi)發(fā)針對(duì)該平臺(tái)的鍵盤(pán)類(lèi)設(shè)備驅(qū)動(dòng)程序,一般為板載按鈕或usb鍵盤(pán)(該部分可選); ⑤根據(jù)framebuffer驅(qū)動(dòng)程序接口,選擇并修改qt/embedded中的qlinuxfbscreen和qgfxraster類(lèi); ⑥根據(jù)鼠標(biāo)類(lèi)設(shè)備驅(qū)動(dòng)程序,實(shí)現(xiàn)該類(lèi)設(shè)備在qt/embedded中的操作接口; ⑦根據(jù)鍵盤(pán)類(lèi)設(shè)備驅(qū)動(dòng)程序,實(shí)現(xiàn)該類(lèi)設(shè)備在qt/embedded中的操作接口(該部分可選); ⑧根據(jù)需要選擇qt/embedded的配置選項(xiàng),交叉編譯qt/embedded的動(dòng)態(tài)庫(kù); ⑨交叉編譯qt/embedded中的example測(cè)試程序,在目標(biāo)平臺(tái)上運(yùn)行測(cè)試。 framebuffer設(shè)備驅(qū)動(dòng)程序提供出的接口是標(biāo)準(zhǔn)的,除了注意endian問(wèn)題外,配置qt/embedded時(shí)選擇相應(yīng)的色彩深度支持即可,因此該部分的移植難點(diǎn)就在于framebuffer驅(qū)動(dòng)程序的實(shí)現(xiàn)。qt/embedded部分的qwsserver打開(kāi)/dev/中的framebuffer設(shè)備后讀出相應(yīng)的顯示能力(屏幕尺寸、顯示色彩深度),模板qgfxraster<depth.type>將根據(jù)色彩深度在用戶(hù)空間設(shè)備創(chuàng)建出與顯示緩存同樣大小的緩沖作為雙緩沖,并采用正確方式進(jìn)行顯示。 在筆者參與設(shè)計(jì)的某smart-phone開(kāi)發(fā)平臺(tái)中,gui系統(tǒng)實(shí)現(xiàn)方案采用了qt/embedded 2.3.7和qtopia 1.7.0(基于qt/embedded 2.x系列的手持套件),硬件平臺(tái)采用了基于intel xscale pxa255處理器的嵌入式開(kāi)發(fā)系統(tǒng)。該開(kāi)發(fā)系統(tǒng)采用640×480分辨率的tft lcd和pxa255內(nèi)部lcd控制模塊作為顯示設(shè)備,ads7846n作為外部電阻式觸摸屏控制器;另外,采用了五方向按鍵作為板載鍵盤(pán)。由于該系統(tǒng)采用了isp1161作為usb host控制器,較好地支持了usb接口的鍵盤(pán)和鼠標(biāo),操作系統(tǒng)為arm linux 2.4.19。參考linux 2.4.19內(nèi)核目錄drivers/input部分,可以按照標(biāo)準(zhǔn)內(nèi)核中input device接口設(shè)計(jì)實(shí)現(xiàn)觸摸屏和鍵盤(pán),在實(shí)現(xiàn)了基于isp1161的ehci驅(qū)動(dòng)程序后,移植標(biāo)準(zhǔn)的usb接口的人機(jī)界面設(shè)備驅(qū)動(dòng)hid和usb鍵盤(pán)、鼠標(biāo)的驅(qū)動(dòng)程序后,可以獲得對(duì)于該類(lèi)設(shè)備的調(diào)用接口。此過(guò)程不屬本文討論范疇,此處暫不多述。 qt/embedded 2.x系列對(duì)于輸入設(shè)備的底層接口與3.x系列不同,觸摸屏設(shè)備和鍵盤(pán)設(shè)備需要根據(jù)具體的驅(qū)動(dòng)程序接口在qt/embedded中設(shè)備實(shí)現(xiàn)對(duì)應(yīng)的設(shè)備操作類(lèi)。其中 |