2 GenApi模塊 – 配置相機
2.1. 簡介
GenApi模塊解決如何去配置相機的問題。主要的思路是,讓相機生產廠商為他們的相機提供機器可以識別的產品說明。這些相機描述文件(camera description files)包含所有需要的信息,用以自動地把相機的屬性(features)和其寄存器(registers)相對應。
相機的Gain屬性是一個典型的例子,假設用戶想令Gain=42,利用GenICam,通用的軟件可以讀相機的描述文件並發現,要把Gain屬性設成42意味着向地址為0x0815的寄存器寫入值0x2A。其他要做的工作可能是檢查相機是否提供Gain屬性,並檢查要寫入的值是否在Gain的允許范圍內。
請注意,給相機添加新的屬性僅僅意味着擴展相機的描述文件,就可以對所有符合GenICam標准的程序立即生效。
圖2 Layers for accessing a camera
2.3. 節點、接口和抽象特征
相機描述文件中的每個節點只描述一個項目。基於項目的自然性,節點有一個特定的類型(node type)和一個特定的接口(interface)。下列接口目前可用3(每個接口有一個控件用於映射到GUI):
l IInteger – 映射到一個帶有value、min、max和increment的slider
l IFloat – 映射到一個帶有value、min、max和一個物理單位的slider
l IString – 映射到一個顯示字符串的編輯框
l IEnumeration – 映射到一個下拉框
l ICommand – 映射到一個命令按鈕
l IBoolean – 映射到一個復選框(check box)
l IRegister – 映射到一個顯示16進制字符串的編輯框
l ICategory – 映射到一個可以反映相機屬性結構的樹控件
l IPort – 映射到一個相機端口,通常不用圖形顯示
第2.9章給出了接口特性的更多細節。可用的節點類型在第2.8章中說明。可能有多種節點類型實現同樣的接口類型。例如,IInteger接口,被下列(不是全部)節點類型實現:
l IntReg – 根據字節邊界,從寄存器取出一個整數
l MaskedIntReg – 從寄存器的一段取出一個整數,例如,從第8位到第12位
l Integer – 從不同的節點得到value、min、max和increment屬性,合並在一起
每個節點類型從不同的源,用不同的方法取出一個整數值。對於需要輸入一個整數值的連接,所有這些節點的輸出值都可以用作類型安全的輸入。
當用戶讀或寫一個節點的值,節點會觸發節點圖內一系列的讀寫操作。為了說明這一點,圖4顯示了Gain屬性的一個更復雜的例子。Gain屬性可以抽象成一個IInteger接口,通過這個接口,用戶可以設置Value並且可以讀(或其它操作)Min和Max值。圖4的例子假定相機有3個寄存器,一個是Gain的Value,另兩個是Min和Max。利用IntReg節點可以從每個寄存器取出相應的值。名字為Gain的Integer節點收集並合並這些數據,再通過IInteger接口把結果傳遞出來。
圖4 Example of the control flow when getting and setting features
如果用戶讀取Gain節點的值,調用會被分派到GainValue節點,而GainValue節點會通過IPort接口向Device節點查詢正確的寄存器。
如果用戶試圖設置Gain節點的值,實現程序可能首先會從GainMin和GainMax節點讀出Min和Max值以檢查范圍。如果輸入值在允許的范圍內,Gain節點會通過GainValue節點和Device節點把值寫入相機。注意,根據相應IntReg節點的Cacheable屬性,實現程序可能會把Min和Max值放入緩存。
2.5. 訪問模式
每個節點都有一個下表定義的訪問模式:
Readable |
Writable |
Implemented |
Access Mode |
* |
* |
0 |
NI – 未實現 |
0 |
0 |
1 |
NA – 不可用 |
0 |
1 |
1 |
WO – 只寫 |
1 |
0 |
1 |
RO – 只讀 |
1 |
1 |
1 |
RW – 讀寫 |
1 = yes, 0 = no, * = don’t care
屬性可能已經被相機實現,但暫時不可用。如果可用,則根據定義,屬性被實現並且可以讀和/或寫。
有些節點由某些元素來控制訪問權限,例如寄存器節點(參見2.8.3)。另外,GenICam還提供3種在運行時改變訪問權限的機制。
l 根據另一個節點的值,屬性可能暫時被鎖定(locked)。屬性在鎖定的狀態下不可寫。根據上面的表格,寫標志位暫時強制為0。
l 根據另一個節點的值,屬性可能暫時不可用(not available)。根據上面的表格,寫標志位和讀標志位暫時強制為0。
l 根據另一個節點的值,屬性可能沒有實現(not implemented)。根據上面的表格,實現標志位始終強制為0。
“可用”和“已實現”是不同的,因為GUI可能想用不同的方法來處理這兩種情況。未實現的屬性不會顯示給用戶;而暫時不可用的項目只是灰色的並且值會被替換,例如替換成“—”;暫時被鎖定的屬性是灰色的,但是屬性的值仍然會顯示。
以硬件Trigger為例來說明讓一個屬性暫時不可用(temporarily not available)的情況,硬件Trigger的值可以為On或Off。如果Trigger是On,另外一個屬性TriggerPolarity變得可用,TriggerPolarity屬性指示硬件信號是ActiveHigh還是ActiveLow。如果Trigger是Off,則TriggerPolarity屬性是無意義的,應該被置為灰色。
圖5顯示了這個信息在相機描述文件中如何處理,Trigger和TriggerPolarity屬性用Enumeration類型的節點來實現,這種類型把一組枚舉型的入口映射到整數值。例如,Trigger屬性的入口是On=1和Off=0。利用IntReg類型的節點把整數值映射到寄存器。
圖5 Controlling whether a feature is accessible
TriggerPolarity節點有個叫pIsAvailable的連接,這個連接需要指向一個提供IInteger接口的節點。如果這個被指向的節點的值為0,那么TriggerPolarity節點暫時不可訪問。
在這個例子中,pIsAvailable可以直接指向TriggerReg,因為Trigger=On被映射為1,Trigger=Off被映射為0。如果不是這樣的話,一個類型為IntSwissKnife的節點會很有用,它能根據數學公式計算其他整數節點的值,並得到一個整數的結果。在XML文件中,節點看起來像這個樣子:
- <IntSwissKnife Name="TriggerEnabled">
- <ToolTip>Determines if the Trigger feature is switched on</ToolTip>
- <pVariable Name="TRIGGER">TriggerReg</pVariable>
- <Formula>TRIGGER==1</Formula>
- </IntSwissKnife>
<Formula>入口的數學公式被計算,得到節點的計算結果。在計算之前,變量的符號名稱被對應節點的整數值替換。在本例中,只有一個<pVariable>入口指向TriggerReg節點,符號名稱是TRIGGER。這個名稱在公式“TRIGGER==1”中也有。
如果GUI升級了,就會去查看TriggerPolarity節點是否可用。而TriggerPolarity節點會去檢查IntSwissKnife,而IntSwissKnife又會根據TriggerReg節點的值去計算結果。
兼容DCAM的1394相機的BytesPerPacket屬性是“暫時鎖定屬性”( temporarily locked)的一個典型例子。用戶可以改變相機的這個參數,僅當PC適配器的DMA未被設定為采集圖像的時候5。設定DMA的意思是,傳輸層查詢相機的BytesPerPacket參數,並把這個參數設置到DMA。這個工作完成后,直到傳輸層釋放DMA之后才能改變BytesPerPacket。在這之前,相機的這個參數必須被鎖定。
注意,相機本身沒有辦法知道DMA是否設置。因此,相機描述文件中“普通的”節點不能被用來控制BytesPerPacket的鎖定狀態。
圖6 Locking a feature
GenApi內的解決方案是提供一個浮動的Boolean型節點TLParamsLocked(參見圖6)。BytesPerPacket通過pIsLocked連接到這個節點。傳輸層(TL)需要通過更新TLParasLocked節點的值來反映其DMA狀態。在設定DMA之前,它會通過令TLParamsLocked為true的方式來鎖定相機參數(例如BytesPerPacket),在采集圖像完成之后,它會把TLParamsLocked設置回false。改變TLParamsLocked節點會更新所有關聯節點的鎖定狀態,例如BytesPerPacket節點。
注意,為保證這種方式正常工作,TLParamsLocked必須是標准的節點名,並且傳輸層必須有訪問相機的GenApi接口的權限。另外,相機描述文件的設計者必須注意哪個參數要被傳輸層鎖定。這個信息包含在傳輸層標准之中,例如DCAM規范,這個規范規定,在采集數據的時候每楨的包數和每個包的大小必須固定。
“屬性沒有被實現”( not implemented)的一個典型的例子是,同一個家族的某些相機有Gamma屬性而有些則沒有。如果相機有一個查詢位(inquiry bit)來標識是否實現了Gamma屬性,就可以為這個家族的所有相機維護一個相機描述文件。
圖7顯示了GenICam如何處理這種情況。Gamma屬性節點有一個叫pIsImplemented的連接指向GammaInq節點,GammaInq節點映射相機的查詢位。通常把多個查詢位合並到一個寄存器里。為了取得這些位,要使用MaskedIntReg節點類型。這個類型有點像IntReg節點,但是,你可以像查詢整數一樣取查詢想要的一個或一組連續的位。
圖7 Checking whether a feature is implemented