周 蕓
(船舶重工集團公司723所,揚州225001)
在雷達數據處理系統(tǒng)中,顯控終端承擔著雷達數據錄取、目標顯示、人機交互、控制雷達工作、對外接口通訊等多項任務,是整個系統(tǒng)的控制處理中心。隨著現(xiàn)代雷達技術的迅速發(fā)展,對雷達顯控終端的實時性、任務異步性提出了更高的要求。VxWorks操作系統(tǒng)因其多任務、強實時、可裁減、高可靠性等諸多獨特優(yōu)勢而在實時顯控設備這一信息吞吐量大、計算解算頻繁、實時性要求高的平臺上獲得了開發(fā)者和設備使用者的廣泛認可,但其圖形界面顯示相對薄弱,較普遍的用法是采用風河公司提供的WindML媒體庫,其圖形功能使用用戶圖形庫(UGL)組件,代碼繁瑣,效率較低,開發(fā)高質量圖形界面相當困難[1]。
Zinc是運行在VxWorks上的圖形用戶接口工具(GUI),它類似在Windows下使用VB可視化編程一樣,用戶可以實現(xiàn)“拖-放”式的“所見即所得”的圖形界面設計,把設計者從大量編碼的圖形界面開發(fā)中解放出來,最大地簡化了界面開發(fā)過程,而顯控軟件復雜的多任務實時并發(fā)處理則由VxWorks操作系統(tǒng)得到保證。Zinc的開發(fā)及運行環(huán)境如圖1所示。
圖1 Zinc開發(fā)及運行環(huán)境示意圖
Zinc的應用程序是在基于事件驅動(Eventdriven)的機制下運行的。輸入設備和應用程序之間是通過事件相互作用的。Zinc的事件有3種來源:操作系統(tǒng)本身、外部設備和用戶應用程序。例如鍵盤輸入就是一個典型的外部設備輸入事件。在Zinc應用程序運行過程中,事件管理器以輪詢的方式接收類似鍵盤、鼠標等外部設備以中斷驅動方式發(fā)出的數據信息,然后把這些信息對應的事件匯集起來,放進內部的事件隊列等待下一步的處理。
在Zinc應用中,ZafApplication::Control()函數是主要的控制環(huán),它通過調用ZafWindowManager::Get()例程從事件管理器中得到事件,并且在應用終止之前不斷地把它們送到窗口管理器中。當事件傳遞到窗口管理器時,窗口管理器就會決定事件的最終目的地和正確路由,并正確地分派它們到相應的作用對象。首先,Event()方法調用最終的繼承類,這個類可能是Zinc庫中的類,或者是用戶自定義的繼承類,如果這個最終繼承類并不處理事件,這個事件就會傳遞到其基類的Event()方法,這個處理可能一直進行到找到最終的基類ZafWindowObject,此基類收到事件,要么處理它,要么把它交給操作系統(tǒng)對象進行處理,如圖2所示。
圖2 Zinc的運行機制
某雷達顯控終端界面是用Zinc設計實現(xiàn)的,終端界面上的元素復雜,但設計方法步驟相同,下面通過簡單的示例來介紹Zinc的開發(fā)過程。這個例子創(chuàng)建1個串口接收窗口,在這個窗口中可以設置接收端口、波特率、控制位等,并且在對話框中顯示接收到的數據,如圖3所示。
圖3 Zinc創(chuàng)建的串口接收窗口
設計步驟如下:
(1)步驟1:利用Zinc Designer設計窗口,生成.znc文件。
(2)步驟2:編輯視窗對象,設置對象屬性。
在編輯窗口上,有1排Zinc對象工具欄,用戶首先須選擇一個窗口并放置,再在窗口上放置按鈕或菜單等其他對象。以“設置串口”按鈕為例,按下這個按扭后,將發(fā)送1個用戶應用程序事件(自定義EVENT_CUSTOM_SET_PORT),用戶可選擇串口位置、波特率等信息來配置串口。設置這個按鈕屬性時,在“Send message”項的下拉菜單中選擇“True”,在“Send message value”項中輸入“10 005”(這是1個用戶應用程序事件,其值應大于10 000),在“Send message text”項中輸入“EVENT_CUSTOM_SET_PORT”。當應用程序運行后,用戶點擊這個按扭時就會向內部事件隊列發(fā)送1個EVENT_CUSTOM_SET_PORT事件,經過窗口管理器的路由后,按照“設置串口”的Event()方法來實現(xiàn)串口設置。
(3)步驟3:生成源代碼。
視窗對象編輯完成并保存example.znc文件后,選擇“Generate Code”,它的任務是生成example.cpp文件、example.hpp文件和example.inc文件。用戶在example.cpp文件中編寫代碼。example.inc是1個數據結構文件,存放了用戶的數據列表、對象列表、用戶函數列表等結構信息。
(4)步驟4:運行應用程序。
在Tornado下生成一個Download型工程,加載上面生成的3個文件,然后加入1個通用程序的入口文件v_app.cpp,編譯后下載到目標機。程序在開始運行時,會尋找example.znc資源文件,事先必須把它存放在VxWorks的同一目錄下。
根據某工程對顯控設備的具體要求,本應用軟件采用模塊化設計思想,劃分為以下幾個功能模塊:任務管理模塊、初始化模塊、人機交互模塊、圖形顯示模塊、通訊模塊、數據處理維護模塊,而每個功能模塊由一個或多個任務組成。人機界面布局上分為雙頁顯示,主頁面是雷達的PPI顯示,雷達工作模式及參數信息顯示,次頁面顯示雷達各分機的工作參數和自檢信息。設計框圖如圖4。
圖4 顯控軟件設計架構
設計中的難點1是非GUI任務與GUI任務之間的通訊
對于顯控軟件來說,雙屏顯示任務稱為GUI任務,與圖形繪制相關的操作都在這個任務中完成,而所有其他的任務稱為非GUI任務。非GUI任務需要在不同的時期和GUI任務通信,而非GUI任務與GUI任務之間的通信方式將對整個軟件系統(tǒng)的實時性、可靠性和穩(wěn)定性產生影響。
Zinc主要提供了如下幾種通信機制供程序員選擇使用:Zinc入口點、共享內存、OS消息隊列。
(1)Zinc入口點對Zinc來說,主要的通信入口函數是ZafEventManager::Put(),通過它可以把事件放到事件隊列上,此方法屬于異步方法。
(2)共享內存在VxWorks中,共享內存是容易實現(xiàn)的。為了安全地共享內存,最好給共享的內存分配1個信號量,這樣就能防止共享內存被同時多次修改。共享內存的使用并不要求線程安全,但是對Zinc卻是要求的,否則當1個窗口對象的成員指向共享內存時,1個異常就會發(fā)生。
(3)OS消息隊列可以在Zinc中創(chuàng)建OS消息隊列,利用消息隊列實現(xiàn)從GUI任務到非GUI任務的通信,或者是從非GUI任務到GUI任務的通信,但不允許同時進行2個方向上的通信。
在顯控軟件中使用的是Zinc入口點方式。網絡接收任務(非GUI任務)接收來自雷達內各分系統(tǒng)的資源數據,利用ZafEvenManager::Put()函數將其存放到事件隊列中,GUI任務利用ZafApplication::Control()循環(huán)讀取事件隊列,進而窗口管理器決定事件的最終目的地和合適的路由并將其發(fā)送。
非GUI任務與GUI任務之間通信的實現(xiàn)主要包括如下幾個方面:
(a)用戶事件的定義
Zinc中的事件共分為7類,其中用戶事件的取值范圍為10 000~32 767。在顯控軟件系統(tǒng)中定義“刷新數據”用戶事件為:
const ZafEventType EVENT_CUSTOM_SETTEXT=10011;
其中ZafEventType為Zinc事件類型。
(b)數據打包并發(fā)送用戶事件
char*text= “hello”;//要刷新的文本“hello”
ZafEventStruct event(EVENT_CUSTOM_SETTEXT); //創(chuàng)建“刷新文本”事件
event.route=pMainWin;//事件路由的目標窗口
event.SetVoidData(text);//數據打包到事件中
zafApplication->EventManager()->Put(event);//發(fā)送事件
(c)用戶事件的處理
ZafEventType MainWin::Event(const ZafE-ventStruct &event)
{
char*tmpText;
//判斷是否是用戶事件EVENT_CUSTOM_SETTEXT
if(event.type== EVENT_CUSTOM_SETTEXT)
{
tmpText= (char*)event.VoidData();
ProcessText(tmpText);//事件處理函數
}
else
{
/*處理其他事件*/
}
}
這樣類似操作就能使界面的控件“活”起來。
設計中的難點2是多頁顯示技術。在人機界面上有時需要多頁可切換的頁面以增加顯示信息容量,用Zinc設計顯控界面時,在界面框架布局上設計合理就可以實現(xiàn)這項技術。
將應用程序對應的根窗口設計為主窗口(R),而顯控界面的每個頁面設計為子窗口(M,F(xiàn)),在子窗口上又可以添加各種類型的子子窗口(M1,M2,M3,…,F(xiàn)1,F(xiàn)2,F(xiàn)3,…),如圖5所示。
圖5 多窗口層次關系
這樣在用Zinc Designer進行界面設計時初始化將子窗口M的屬性設置為顯示,子窗口F設置為隱藏,子子窗口 M1,M2,…,F(xiàn)1,F(xiàn)2,…的可視屬性和其父窗口相同,這樣在接收到外部的換頁指令后,可以通過子窗口(M或F)的指針來調用SetVisible函數(參數true或false),可實現(xiàn)頁面的顯示或隱藏。
在Zinc中可以利用Zinc Designer來設計圖形用戶界面,實際上也可以直接寫代碼來繪制圖形。就修改而言,窗口上的控件如果較多且較規(guī)則,用Zinc Designer設計時修改很方便。但要繪制一些不規(guī)則的復雜圖形(如PPI顯示)時當然要通過寫代碼來實現(xiàn)。實際應用中,最好將2種方法結合起來使用。
設計界面的步驟主要有:
(1)用Zinc Designer設計好界面,并產生代碼。
(2)對界面上的對象根據需要定義相應的類,并對其中的成員函數編寫代碼。
另外,在Tornado安裝目錄下的\target\src\zinc\demos子目錄中有Zinc提供的2種用法的例子,只要對其深入研究,定會開發(fā)出高質量的程序。
總之,Zinc是基于VxWorks強大的GUI開發(fā)工具。Zinc的類庫及編程方法與MFC十分類似,有過MFC編程經驗的人一定體會過MFC為Windows編程帶來的方便,而Zinc堪稱VxWorks上的MFC[2]。利用Zinc已經成功實現(xiàn)了在某型雷達終端上的圖形界面設計,系統(tǒng)運行穩(wěn)定且性能良好。
[1]孔祥營,柏桂枝.嵌入式實時操作系統(tǒng)VxWorks及其開發(fā)環(huán)境Tornado[M].北京:中國電力出版社,2001.
[2]侯俊杰.深入淺出MFC[M].武漢:華中科技大學出版社,2007.