1 前 言
電子海圖系統(tǒng)是一種把需要向航海人員顯示和解釋的各種各樣信息融成一體的實時導(dǎo)航系統(tǒng),是地理信息系統(tǒng)在艦船組合導(dǎo)航系統(tǒng)中的重要應(yīng)用,被認(rèn)為是繼雷達(dá)/ARPA之后在艦船導(dǎo)航方面又一項偉大的技術(shù)革命。與簡單地用顏色顯示的紙海圖相比,電子海圖系統(tǒng)包括更多的使用簡單、操作容易的地理和文字信息。作為一種自動判定儀器,它能夠連續(xù)測定船舶相對于陸地、圖示物標(biāo)、導(dǎo)航標(biāo)志和不可見礙航物的位置,對海上航行、安全和商業(yè)都有重要意義。
VxWorks是一種嵌入式的實時操作系統(tǒng)。將應(yīng)用較為廣泛的電子海圖系統(tǒng)移植到VxWorks操作系統(tǒng)下的主要原因有兩個:一是VxWorks系統(tǒng)的實時性,能夠很好的滿足導(dǎo)航系統(tǒng)實時性的要求;二是基于信息安全方面的考慮,海圖系統(tǒng)要求一種保密性好、沒有漏洞的操作系統(tǒng),使用VxWorks操作系統(tǒng),程序開發(fā)者可以進(jìn)行最底層的程序開發(fā),能夠完全控制系統(tǒng)的資源,確保海圖信息的安全。
2 電子海圖系統(tǒng)打印功能的總體設(shè)計思路
在VxWorks操作系統(tǒng)中,實現(xiàn)電子海圖信息打印功能設(shè)計的總體思路是:首先將打印內(nèi)容,包括圖像和報表,轉(zhuǎn)換成恰當(dāng)格式的圖像文件,如PostScript文件,而后對于沒有內(nèi)置PostScript語言解釋器的打印機(jī),需要將PostScript語言解釋成打印機(jī)可以識別的語言,最后把圖像文件輸送到打印機(jī)。
本文介紹基于內(nèi)置有PostScript語言解釋器的HP LaserJet 1200打印機(jī),在VxWorks操作系統(tǒng)下,完成電子海圖信息打印功能的實現(xiàn)過程。
3 打印驅(qū)動
打印機(jī)驅(qū)動程序中的各個函數(shù)的實現(xiàn):
(1)基本的I/O函數(shù)的實現(xiàn)
根據(jù)打印機(jī)并口的特點,驅(qū)動程序中要實現(xiàn)的基本的I/O函數(shù)應(yīng)該是lptOpen(…)、lptRead(…)、lptWrite(…)和lptIoctl(…)。這4個基本函數(shù)的聲明分別是:
LOCAL int lptOpen(LPT_DEV*pDev,char*name,int mode); LOCAL int lptRead(LPT_DEV*pDev,char*pBuf,int size);
LOCAL int lptWrite(LPT_DEV*pDev,char*pBuf,int size);
LOCAL STATUS lptIoctl(LPT_DEV*pDev,int function,int arg); 其中LPT_DEV結(jié)構(gòu)的定義為:
typedef struct lptDev
{
DEV_HDR devHdr;
BOOL created;/*TRUE if this device has been created*/
BOOL autofeed;/* TRUE if enable autofeed */
BOOL inservice;/* TRUE if interrupt in service */
USHORT data; /* data register */
USHORT stat; /* status register */
USHORT ctrl; /* control register */
int intCnt;/* interrupt count */
int retryCnt; /* retry count */
int busyWait; /* loop count for BUSY wait */
int strobeWait;/* loop count for STROBE wait */
int timeout; /* timeout second for syncSem */
int intLevel; /* interrupt level */
SEMAPHORE muteSem;/* mutex semaphore */
SEMAPHORE syncSem;/* sync semaphore */
} LPT_DEV
DEV_HDR是所有設(shè)備的頭結(jié)構(gòu),是由VxWorks系統(tǒng)定義的,定義為:
typedef struct/* DEV_HDR device header for all device structures*/
{
DL_NODE node; /* device linked list node */
short drvNum; /* driver number for this device */
char * name; /* device name */
} DEV_HDR
(2)設(shè)備的硬件初始化函數(shù)xxDrv(…)的實現(xiàn)
該函數(shù)的聲明為:
STATUS lptDrv(int channels, LPT_RESOURCE *pResource)
其中,參數(shù)channels 為打印并口的通道號;參數(shù)pResource是指向結(jié)構(gòu)LPT_RESOURCE的指針,結(jié)構(gòu)LPT_RESOURCE的定義為:
typedef struct lptResource /* LPT_RESOURCE */
{
int ioBase;/* IO base address */
int intVector;/* interrupt vector */
int intLevel; /* interrupt level */
BOOL autofeed;/* TRUE if enable autofeed */
int busyWait; /* loop count for BUSY wait */
int strobeWait;/* loop count for STROBE wait */
int retryCnt; /* retry count */
int timeout; /* timeout second for syncSem */
}LPT_RESOURCE;
該函數(shù)lptDrv(int channels, LPT_RESOURCE *pResource)完成了打印機(jī)并口的初始化,其中調(diào)用函數(shù)intConnect(…)和iosDrvInstall(…)的具體形式為:
(void)intConnect((VOIDFUNCPTR*)INUM_TO_IVEC(pResource->intVector),
(VOIDFUNCPTR)lptIntr, (int)pDev);
lptDrvNum = iosDrvInstall (lptOpen, (FUNCPTR) NULL, lptOpen,
(FUNCPTR) NULL, lptRead, lptWrite, lptIoctl);
(3)設(shè)備的創(chuàng)建函數(shù)xxDevCreate(…)的實現(xiàn)
該函數(shù)的聲明為:
STATUS lptDevCreate (char *name, int channel)
該函數(shù)將設(shè)備的創(chuàng)建標(biāo)志置為TRUE,然后調(diào)用函數(shù)iosDevAdd (&lptDev[annel],devHdr.name, lptDrvNum) 將創(chuàng)建的設(shè)備加入I/O系統(tǒng)中。
對于打印驅(qū)動程序,重點在于函數(shù)lptWrite(…)的編寫,這個函數(shù)的實現(xiàn)可采用兩種方式。一種是中斷方式,即將控制寄存器中的允許中斷位置為1,這樣,打印機(jī)每打印輸出一個字符后,立即向主機(jī)發(fā)出中斷請求信號,要求發(fā)送下一個字符;主機(jī)方面只要在中斷服務(wù)程序中實現(xiàn)數(shù)據(jù)傳輸即可,而不必循環(huán)查詢打印機(jī)的“忙”信號。另一種是查詢方式,用這種方式時,主機(jī)不停地測試打印機(jī)的“忙”信號,當(dāng)檢測到打印機(jī)不忙時,便向其發(fā)送打印數(shù)據(jù),若打印忙,則主機(jī)必須等待,直到打印機(jī)不忙。
根據(jù)編寫打印機(jī)驅(qū)動程序的兩種方式,選用查詢方式,其流程如圖1。
4 PostScript文件的生成
在VxWorks操作系統(tǒng)的開發(fā)環(huán)境Tornado下,軟件包ZINC中的ZafPrinter類及ZafDisplay類提供的函數(shù)可完成PostScript文件的生成。ZafPrinter類繼承ZafDisplay 類而來,因此,在ZafPrinter 中除了繼承來的圖形顯示函數(shù)之外,還定義了與打印機(jī)接口相關(guān)的函數(shù),如BeginJob(),EndJob(),BeginPage(),EndPage()等。
在用ZINC自帶的程序生成PostScript文件時,需注意以下幾點:
(1)將自定義的顏色值加入顏色表中,在i_print.cpp文件(在目錄…\Tornado\target\src\zinc\generic下)中,原來的顏色表定義為:
static unsigned long psColorTable[16]=
{
0x00000000L, // 0-ZAF_CLR_BLACK
0x00000080L, // 1-ZAF_CLR_BLUE
0x00008000L, // 2-ZAF_CLR_GREEN
0x00008080L, // 3-ZAF_CLR_CYAN
0x00800000L, // 4-ZAF_CLR_RED
0x00800080L, // 5-ZAF_CLR_MAGENTA
0x00808000L, // 6-ZAF_CLR_BROWN
0x00C0C0C0L, // 7-ZAF_CLR_LIGHTGRAY
0x00808080L, // 8-ZAF_CLR_DARKGRAY
0x000000FFL, // 9-ZAF_CLR_LIGHTBLUE
0x0000FF00L, // 10-ZAF_CLR_LIGHTGREEN
0x0000FFFFL, // 11-ZAF_CLR_LIGHTCYAN
0x00FF0000L, // 12-ZAF_CLR_LIGHTRED
0x00FF00FFL, // 13-ZAF_CLR_LIGHTMAGENTA
0x00FFFF00L, // 14-ZAF_CLR_YELLOW
0x00FFFFFFL, // 15-ZAF_CLR_WHITE
};
保留原有的16種顏色,再增加48種海圖中的顏色:
0x00000000, 0x00000080, 0x0000b400, 0x0080ffff,
0x00d20000, 0x00ff00ff, 0x00dc8000, 0x00c0c0c0,
0x00ffc7ab, 0x000000ff, 0x0000ff00, 0x00c8ffff,
0x00ff0000, 0x00ff96ff, 0x00ffffc0, 0x00ffffff,
0x00ff02fd, 0x00ff02fd, 0x00ff02fd, 0x00ff02fd,
0x00ff02fd, 0x00ff02fd, 0x00ff02fd, 0x00ff02fd,
0x00ff02fd, 0x00ff02fd, 0x00ff02fd, 0x00ff02fd,
0x00ff02fd, 0x00ff02fd, 0x00ff02fd, 0x00ff02fd,
0x00000000, 0x000000ff, 0x0033aa00, 0x0060c0c0,
0x00b03030, 0x00c040c0, 0x00804040, 0x00a0a0a0,
0x00404040, 0x008080ff, 0x0080ff80, 0x0016edfe,
0x00e02020, 0x00e010e0, 0x00ffff80, 0x00ffffff,
這樣顏色表中共有64種可用顏色。
同時將
for(index = 0; index < 16; index++)
colorTable[index]= psColorTable[index];
改為:
for(index = 0; index < 64; index++)
colorTable[index]= psColorTable[index];
(2)為使生成的PostScript文件盡可能的小,對原來海圖的畫圖程序做了一點改動。在原程序中,多邊形的繪制是通過畫兩點線完成的,這樣,生成PostScript文件比較大,可將其改為直接調(diào)用畫多邊形的函數(shù)Polygon()。經(jīng)過這樣的改動,生成的PostScript文件減小了很多,原來的一頁圖生成的PostScript文件為3.65M,改動后不足1M。
5 PostScript 文件在VxWorks操作系統(tǒng)下的打印輸出
要使用打印驅(qū)動程序,首先要調(diào)用函數(shù)lptDevCreate(char*name,intchannel)為LPT端口創(chuàng)建設(shè)備,其中端口號由參數(shù)channel指定,創(chuàng)建的設(shè)備的名稱為name。只能為一個端口號創(chuàng)建一個設(shè)備。
創(chuàng)建設(shè)備成功之后,主機(jī)就可以向打印機(jī)發(fā)送PostScript文件了,其程序流程如圖2。
6 漢字打印輸出的實現(xiàn)
在VxWorks操作系統(tǒng)下,實現(xiàn)電子海圖中漢字的顯示和打印輸出功能的基本思路是:利用Windows操作系統(tǒng)中的TrueType字庫,根據(jù)需要顯示漢字的Unicode編碼,在TrueType字庫中找到該漢字的相應(yīng)信息,按照TrueType字庫中存儲的信息,將漢字顯示或打印輸出。
TrueType字庫由很多表組成,它是用一些閉合的輪廓線來描述每個字符的。若能夠訪問TrueType字庫獲得相應(yīng)漢字的描述信息,就能將漢字畫出來。對于TrueType字庫的訪問,網(wǎng)上有開放的資源可以實現(xiàn),這就是FreeType2,它為應(yīng)用程序訪問字庫文件提供了統(tǒng)一的接口,支持的格式包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。要使用FreeType, 就要在相應(yīng)的操作系統(tǒng)下對源代碼進(jìn)行編譯,生成一個庫文件,然后在應(yīng)用程序中調(diào)用相應(yīng)的API庫函數(shù)。
通過FreeType提供的庫函數(shù),應(yīng)用程序可以訪問TrueType字庫,根據(jù)所得到的TrueType漢字信息,就能實現(xiàn)TrueType字體的顯示或打印輸出。但是TrueType字庫的訪問是通過Unicode編碼進(jìn)行的,也就是說,只有獲得了字符的Unicode編碼,才能在TrueType字庫中得到該字符的描述信息。在電子海圖程序中,字符的Unicode編碼的獲得是通過查表實現(xiàn)的。所謂的查表,是指將國際漢字字符集中所有字符的Unicode編碼,存在一個數(shù)組unsigned long gb2312_uni_data[87][94],根據(jù)字符的區(qū)位碼就可以得到相應(yīng)的Unicode編碼。例如區(qū)號為qh,位號為wh的字符的Unicode編碼就是數(shù)組元素gb2312_uni_data[qh-1][wh-1]的值。
保存所有字符的Unicode編碼的數(shù)組gb2312_uni_data[87][94]是在Windows操作系統(tǒng)下轉(zhuǎn)換得到的。具體的做法是將國際漢字字符集中的所有字符按照一定的格式保存成文本文件,然后從文件中讀出每個字符,調(diào)用函數(shù)MultiByteToWideChar(…)將其轉(zhuǎn)換成Unicode編碼,并將其保存。
根據(jù)TrueType字庫中字符的信息,顯示或打印輸出字符有兩種途徑:一種是調(diào)用FreeType的API函數(shù)得到相應(yīng)字符的輪廓線,然后將其填充;另一種是調(diào)用FreeType的API函數(shù)直接得到字符的位圖,再調(diào)用相應(yīng)操作系統(tǒng)中的打點函數(shù)實現(xiàn)位圖的顯示。由于第二種方法實現(xiàn)起來比較簡單,并且海圖系統(tǒng)中的漢字不是很多,所以在海圖程序中使用的是第二種方法。
在獲得相應(yīng)漢字的字形位圖信息的基礎(chǔ)上,實現(xiàn)漢字打印輸出功能的關(guān)鍵是如何使用PostScript語言描述相應(yīng)漢字字形的位圖信息。在程序的設(shè)計中,通過畫1個像素長度的直線來實現(xiàn)點的輸出,然后用一系列的點輸出位圖信息。其中,點的輸出用PostScript語言表示為:
x y moveto
x+1 y lineto
根據(jù)漢字橫多豎少的特點,可以對以上產(chǎn)生的PostScript文件進(jìn)行優(yōu)化,如果N點在一條橫線上,就直接畫N長度的直線,用PostScript語言表示為:
x y moveto
x+N y line to
這樣,就將原來的N條PostScript語句轉(zhuǎn)化為1條語句,從而減少了PostScript文件的長度。
7 結(jié)束語
VxWorks實時操作系統(tǒng)的特點決定了在此操作系統(tǒng)中開發(fā)驅(qū)動程序的重要性。根據(jù)需要配置相應(yīng)的設(shè)備,并實現(xiàn)硬件的驅(qū)動,是VxWorks系統(tǒng)中進(jìn)行軟件設(shè)計與開發(fā)的前提。本文介紹的電子海圖系統(tǒng)打印功能的總體設(shè)計思想及實現(xiàn)方法,已在哈爾濱工程大學(xué)研制的某型電子海圖系統(tǒng)的二次開發(fā)中得到應(yīng)用。