利用QNX的模塊性和和可裁剪性,其嵌入過程一般是:
構建Buildfile -> 編譯buildfile生成系統映象文件 -> 啟動目標系統 ->嵌入式系統軟件設計。
其中的關鍵是構建Buildfile[19]。通常一個嵌入式系統需要一個可啟動的操作系統映象文件(OS Image)。對於基於QNX的嵌入式一個應用系統,就是根據所選擇的CPU類型以及應用程序所需要的操作系統模塊來定制嵌入式系統。構建Buildfile的過程就是配置操作系統映象的過程。簡單來說Buildfile是一個產生映象文件所需遵守的一組規則、准則。Buildfile由三部分組成,其結構如下:
l bootstrap script(啟動引導腳本)
l startup script(啟動腳本)
l file list(文件列表)
1.1.1 啟動引導腳本(bootstrap script)
不同的CPU其啟動的方式不同,相應的啟動引導程序也就不同。啟動引導腳本bootstrap script的作用就是配置和CPU相適應的微內核。一個典型的啟動引導腳本如下:
[virtual=x86,bios +compress] .bootstrap = {
startup-bios -s 64k -D 8250.3f8.57600 -A
PATH=/proc/boot procnto
}
在這個例子中,第一行說明它是一個啟動引導文件。其中“virtual” 表明該Buildfile將構造一個與啟動時產生的虛擬地址空間相對應的啟動映象。關鍵詞“x86,bios” 則分別指處理器(x86)和機器類型(通過bios啟動)。而“+compress”使得映象文件被壓縮,以產生更小的映象文件。startup-bios是運行於具有BIOS的PC兼容系統的可執行程序,主要負責利用BIOS檢測PC硬件資源,在這里主要是提取映象,將其置於RAM的相應位置,做基本的配置並運行內核。該例中“-s 64k”表明復制ROM中第一段64k視頻BIOS到RAM使其更快的執行,即所謂的ROM BIOS映射。第二項參數表明以57600波特率打開第一個串口作為一個調試通道,其調試輸出可以在另一台通過計算機數據傳輸線(null modem cable)連接的PC上捕捉到。最后一項參數則是實時系統中比較典型的情形,其作用是在任何異常內核終止后系統均立即重啟動。“PATH=/proc/boot” 確定了PATH環境變量。“procnto” 是微內核和進程管理器,包括QNX 6 微內核,進程管理,內存管理以及路徑名管理,每個利用mkifs工具的可啟動映象都必須具有procnto。需要注意的是在bootstrap中,第一個可執行程序必須是startup-*,而最后一個必須是procnto!
1.1.2 啟動腳本(startup script)
啟動腳本是在進程管理啟動后的一系列將要被執行的命令列表。一個簡單的script如下:
[+script] .script = {
devc-con &
reopen /dev/con
+session] sh
}
可以在這里進行配置網絡,設置顯示卡等操作。通常我們自己編寫的需要開機自動執行的程序也放在這里,詳細例子見開發案例。
1.1.3 文件列表(file list)
文件列表是上面的系統程序和用戶程序執行所必須的一些文件列表,尤其是一些共享庫。由於用戶程序是用C語言開發的,所以必須至少包括一個標准C共享庫。例如(“#”后的內容為注釋):
#include the C shared library
libc.so
#create a symlink called ldqnx.so.2 to it
[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.so
其中[type=link]行是用一個ldqnx.so.2重新定位libc.so。如果不知道在映象文件中都是需要哪些共享庫,可以利用“objdump” utility(實用程序)來顯示相關的需求信息。假如我們用到了ping命令,可以在終端執行:
# objdump -x ‘which ping’ | grep NEEDED
回車,將顯示信息:
objdump: /usr/bin/ping: no symbols
NEEDED libsocket.so.2
NEEDED libc.so.2
表明ping命令需要libsocket.so.2和libc.so.2,再利用objdump
# objdump -x /lib/libsocket.so.2 | grep NEEDED
NEEDED libc.so.2
# objdump -x /lib/libc.so.2 | grep NEEDED
即是說libsocket.so.2需要libc.so.2,而libc.so.2不需要任何其他的庫。那么如果包括ping在映象中,就必須在文件列表中列出libsocket.so.2和libc.so.2。
有了Buildfile,我們就可以通過“mkifs”utility生成啟動映象文件,其語法格式是:
#mkifs [可選參數] 源文件 目標文件
比如:
#mkifs -v mydoc.build mydoc.ifs
就得到了映象文件mybuild.ifs
啟動映象文件生成后就可以嵌入到目標系統,啟動目標系統,為進一步的系統開發做好了准備。詳細的例子見如下開發案例一。
1.1.4 QNX嵌入案例分析
目標系統:pc104的板子,DOC(Diskonchip)存儲器。
設計目標:啟動圖形界面程序,通過網絡實現資源互訪。
1、構建Buildfile,我們的mydoc.build如下:
[virtual=x86,bios +compress] .bootstrap = {
startup-bios –NTarget # 使目標機的名字為Target
PATH=/proc/boot:/bin:/sbin:/usr/bin:/usr/sbin:/usr/photon/bin LD_LIBRARY_PATH=/proc/boot:/dev/shmem:/lib:/lib/dll:/usr/lib:/usr/lib/dll procnto
}
[+script] .script = {
devc-con & # 在后台打開一個控制台。
reopen /dev/con1
display_msg Welcome to QNX-DOC world !
pci-bios &
waitfor /dev/pci
devb-doc blk automount=hd0t77:/ & # 后台運行DOC驅動程序
#以下設置網絡
io-net -d rtl -ptcpip -pqnet &
ifconfig en0 192.168.1.1 # IP地址
route add default 192.168.1.2 #網關IP
waitfor /dev/socket # 等待設置
waitfor /bin 15 # 等待調入其他命令
# 后台運行其他程序
pipe &
mqueue &
devc-pty -n 32 &
waitfor /sbin
waitfor /usr/sbin
# 設置環境變量
SYSNAME=nto
TERM=vt100
# 啟動sh
reopen /dev/con1
[+session] sh
}
[type=link] /tmp=/dev/shmem # 設置/tmp為共享內存區
[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.so # 加入運行時庫
libc.so #標准C庫
libsocket.so # socket 庫
devn-rtl.so # 網卡驅動
npm-tcpip.so # TCP/IP協議
npm-qnet.so # Qnet協議
libcam.so #包含磁盤文件,使我們能夠訪問DOC上的文件
io-blk.so
cam-disk.so # 文件系統所需共享庫
fs-qnx4.so
devc-con # 控制台驅動
devb-doc # DOC驅動
io-net # 可執行文件文件列表
ifconfig
pipe
mqueue
devc-pty
pci-bios
2、編譯生成mydoc.ifs
3、做啟動軟盤
把軟盤放進開發機軟驅,在終端運行:
#dinit /dev/fd0
#mount /dev/fd0 /mnt/fd0
#cp /…/mydoc.ifs /mnt/fd0/.boot
這里假設mydoc.ifs在目錄/…/下
4、啟動目標系統,格式化DOC
#devb-doc &
# fdisk /dev/hd0 delete -a
# fdisk /dev/hd0 add -s 1 qnx all
# fdisk /dev/hd0 boot -s 1
# fdisk /dev/hd0 loaderfds
注意,DOC上所有的原有數據都不復存在,需要慎重。
5、重新軟盤啟動目標機,初始化QNX文件系統
# dinit -h /dev/hd0t77
# dinit -hb /dev/hd0t77
# mount /dev/hd0t77 /
此時在開發機上運行“# ls /net”應該可以看到Target和Host(假設開發機的名字為Host)。
# cp /…/mydoc.ifs /net/Target/.boot
至此,DOC目標機就可以自啟動,而不再依靠軟盤。
1.2 Photon的嵌入過程
在桌面環境中Photon的運行是通過腳本“ph”實現的[35]。ph腳本主要做如下一些工作:
l 啟動Photon服務
l 檢測輸入硬件設備
l 啟動輸入硬件設備驅動
l 啟動顯卡驅動,初始化視頻硬件為合適的模式
l 啟動字體管理器
l 啟動windows管理器
l 啟動各個桌面服務程序,比如shelf、桌面背景管理器等。
在嵌入式環境中,需要手工啟動上述各個服務。這樣做有很多好處,比如可以自己決定系統需要的文件,合理配置自己的嵌入式運行環境。下面詳細闡述Photon的嵌入過程:
1、設置PHOTON_PATH環境變量
PHOTON_PATH環境變量是為了保存Photon安裝的基本目錄。缺省情況下是目錄/usr/photon。該目錄下一般至少存在一下幾個子目錄:
l bin:存放Photon的可執行程序
l font_repository :Photon的字體以及字體配置文件(OS independent)
l palette:圖形調色板 (OS independent)
l translations:Photon 語言翻譯支持 (OS independent)
PHOTON_PATH環境變量的設置可以通過export進行,如下所示:
export PHOTON_PATH=/usr/photon
2、啟動Photon服務器
如果不需要給Photon服務進程傳遞任何參數,可以簡單的啟動如下:
Photon &
但是,如果嵌入式環境中有觸摸屏,需要增加Photon的參數-D,-R,-U等。因為人的手指比一個象素大的多,為阻止觸摸位置的任意變化就需要指定-U選項。需要注意的是Photon必須包含在PATH環境變量下。在QNX Neutrino中,該位置是/usr/photon/bin。可以通過
export PATH=:/bin:/usr/bin:/usr/photon/bin
來設置PATH環境變量。
3、啟動輸入設備驅動
在桌面環境中,一般通過inputtrap工具來自動搜索輸入設備(鼠標、鍵盤、觸摸屏等)並為其啟動合適的驅動程序。在嵌入式環境中,由於存儲空間的限制一般不用inputtrap,因為inputtrap比較大而且嵌入式環境中輸入設備可能在一個特殊的位置或者不被已存在的devi-*驅動支持。當然,如果情況允許也可以利用inputtrap,畢竟方便省事的多。手工加載驅動需要用devi-*系列驅動,具體見后面的實例。devi-*系列驅動的位置是/usr/photon/bin。
4、啟動字體管理器
在建立嵌入式系統時要根據自己的情況決定需要支持什么樣的字體以及是否需要矢量字體等。字體的確定主要有以下幾個方面:
l 一般都需要cursor font(phcursor.phf)。
l 如果嵌入式系統中包括了pterm(Photon的一個終端程序),則需PC Terminal(pcterm*.phf),PC Serif(pcs*.phf),或者PC Sanserif (pcss*.phf)字體族。而且需要建立一個$HOME/.photon/pterm.rc文件或$PHOTON_PATH/config/pterm.rc文件來配置終端字體。
l 大多數基於widget應用程序需要如下幾個定義在fontmap文件里的別名字體:
n TextFont
n MenuFont
n FixedFont
n BalloonFont
n TitleFont
l Web瀏覽器需要如下幾種字體:
n Body字體(例如PrimaSans BT、Dutch 801 Rm BT等)
n Heading字體(例如Swis721 BT等)
n Nonproportional字體(例如Courier10 BT、PrimaSansMono BT等)
QNX Photon的字體管理器主要有以下幾種:
l phfontphf:只支持Bitmap字體。
l phfontpfr:支持Scalable Bitstream PFR,和TrueType Collection字體。
l phfontFF:支持Scalable TrueType, Type 1, Type 2, Bitstream Speedo (retail encryption),以及Bitstream Stroke等字體。
l phfontFA:支持以上所有字體。
我們要根據自己所使用字體的實際情況選擇合適的字體管理器。字體管理器的啟動很簡單,如:
/usr/photon/bin/phfontphf &
如果啟動映象里沒有包括使用的字體文件,在啟動字體管理器時需要指定包括這些字體文件的路徑,比如:
/usr/photon/bin/phfontphf -d /my_dir/font_repository
必須注意的是my_dir必須與$PHOTON_PATH一致。
5、啟動顯卡驅動
Photon圖形子系統的啟動通過io-graphics實現。例如:
io-graphics -g640x480x8 -dldevg-vga.so -P/usr/photon/palette/vga4.pal
io-graphics -g1024x768x16 -dldevg-vesabios.so
io-graphics -g1024x768x16 -dldevg-rage.so -d0x1002,0x4755 -I0
其中,-g指定圖形的顯示分辨率和顏色深度,-dl指明硬件的驅動程序,-d指明驅動唯一確定硬件所需要的PCI制造商以及設備ID,如果有兩個具有相同的制造商和ID的圖形卡的話需要用-I指明是哪塊卡,-P指定使用的palette文件。
這一部分需要的文件主要有:
l /usr/photon/bin/io-graphics:啟動圖形子系統
l /lib/dll/devg-*:設備驅動
l /usr/lib/libdisputil.so.2:devg*驅動使用的庫
l /usr/lib/libffb.so.2:devg*驅動使用的庫
l /usr/lib/libgui.so:io-graphics使用的庫
l /lib/dll/gri-photon.so:Photon DLL
l /usr/lib/libphrender.so:The software rendering routines。
6、啟動windows管理器(可選)
QNX Photon Window管理器是pwm(the Photon Window Manager),它提供了標准的窗口管理功能,包括move、resize、minimize、maximize、raise、lower和close。應用程序可以根據需要定制由pwm提供的標准windows框架。在QNX中,可以通過Ctrl-Alt-Backspace結束圖形模式回到終端模式。但在嵌入式運行環境中往往不提倡最終用戶這樣做,我們可以通過pwm來阻止該情況的發生。例如:
/usr/photon/bin/pwm –k
7、啟動自己的GUI程序
如果自己設計的圖形界面程序是一個單個的可執行程序且不需要window管理器的話,可以靜態編譯。如果需要窗口管理器或者有不止一個Photon程序在運行的話最好連接動態鏈接庫編譯。
只要好好把握以上這七步,很容易就可以定制出優異的QNX圖形運行系統。下面修改開發案例一中的Buildfile,使圖形界面程序可以在目標系統上執行。在Buildfile中增加如下部分,重新編譯Buildfile,並把mydoc.ifs復制到目標系統的/ .altboot,重新啟動目標系統。注意啟動時按Esc使系統以altboot啟動。
waitfor /usr/photon
Photon &
waitfor /dev/photon
phfontFA &
io-graphics -g800x600x15 -dldevg-geode.so -I0 -d0x100b,0x504 &
devi-hirun kbd kbddev ps2 mousedev & #PS/2 鍵盤和鼠標驅動
myph-program # 執行自己的圖形界面程序程序
libm.so.2 # 包含圖形顯示文件
devg-geode.so # 顯卡驅動