OS X用GigE Visionカメラドライバ - その29 [OS X用GigE Vision]
とりあえず前回までで抄訳は終わった。訳しててフラストレーションが溜まった。ずっとまえにAppleのI/O Kitのreferenceの訳をしたときにはそんなことはなかった。フラストレーションの原因は「ああ、こうだったらいいな」「僕だったらこうするのにな」というところが少なからずあったせい。規格書を読んでそう思うことって今まで経験したことがなかった。まあ、ふつうはそうじゃないだろうか。
ようするにはっきり言ってGEN<i>CAMの規格は抽象化のレベルが低い、と僕は思う。具体的にどこかどう、という話をしたい(そして「ばかものめ、GEN<i>CAMの規格はよくできていて美しいのだ」という人の話を聞きたい)けど、そのまえにGEN<i>CAMの規格に対する僕の理解が正しいかどうかを確かめるために僕なりにまとめておく。ちょっと長くなるけど、いっきに今回だけで終わらせる。
できればGEN<i>CAMの仕様をご存知の方がフィードバックしてくれるとうれしいんですが.....
以下はXMLファイルの先頭の例である。
ノードはRegisterDescriptionの中のエレメントとしてフラットにならんでいる。つまり(後述の例外を除いて)ノードは入れ子にはならない、ということである。
次はRegsterDescriptionの構造の例である(一部は「...」で省略してある)。
たとえばゲインを表すノードにはGainという名前になっている。ある名前を持つノードが実際のカメラのどのような機能をあらわしているかはセマンティクスの問題でカメラ記述ファイルの範囲ではない。そういうセマンティクスは別の規格で決めているが、その規格は強制ではないので実際にはカメラごとに確認する必要がある。
ゲインを表すノードの記述の例を以下に示す。
ノードは持ちえるエレメントを全て持っているとは限らない。ノードがあるエレメントを持っていない場合、そのプロパティはデフォルトがある場合と、その属性そのものがない場合がある。それはエレメントの定義(基本的にはスキーマファイル)で決められている。
たとえばGainノードに最大値のエレメントがない場合、そのカメラはどんなGainの値も受け付けることになる。ただしそれがカメラ側でどのように解釈されるかはカメラのハードウェアに依存する。
インターフェイスには
などがある。右側の説明を読んでわかるように、ノードの「インターフェイス」はユーザインターフェイスに対応しているが、ノードがすべてユーザインターフェイスを持つわけではない。
それぞれのインターフェイスには実質的にデータ型が決まっている。考えられるようにIIntegerは整数型、IFloatは浮動小数点型、などである。
ただしすべてのノードが値を持つわけではない。たとえばユーザアクセス可能な機能をまとめておくICategoryやカメラへのコマンドを表すICommandは意味ある値を持たない。
ノードの値は
たとえばIItengerインターフェイス(整数型)をもつノードタイプは
「ノードの形式」の節に書いたようにRegisterDescriptionのエレメントの名前としてノードタイプを指定して、そのNameアトリビュートにノードの名前を指定する。
したがってノードは有向非巡回グラフとなる(規格書では「ツリー」と呼んでいるが厳密には正しくない)。ノードAがノードBを読み書きすることを
と書くことにする。有向非巡回グラフは半順序集合になることに注意。
一方、最小値となるノードは複数個ある。これはグラフの末端となる。グラフの末端はふた通りある。ひとつは内部に定数を内包するノード(「フローティングノード」と呼ぶときがある)で、もうひとつはカメラのレジスタを参照する(読み書きする)ノードである。カメラレジスタを参照するノードを「Port」と呼ぶ。Portノードはただひとつだけ存在していなければならない。そのただひとつのノードの名前は一般的には「Device」である。また、カメラレジスタを参照する必要のあるノードは必ず単一のPortノードを参照していなければならない。
ユーザはRootノードから辿れるpFeatureノードのみ操作できる(カメラアプリはそうプログラムされるべきである)。
たとえば、
バイトオーダはEndiannessエレメントでLittleEndianかBigEndianが指定される。残念なことにLittleEndianがデフォルトになっている。ネットワークバイトオーダ(BigEndian)をとるのが自然なGigE VisionカメラではすべてEndiannessを指定しないといけない、ということになる。
ビット順を指定するとき、バイトオーダによって指定の仕方が逆になる。LittleEndianではLSBを0に、BigEndianではMSBを0にする。
またEnumerationは値に名前をつけた配列を保持できる。その要素はEnumEntryというノードで、名前と整数値を保持する。Enumerationノードのみにサブノード(ノードの入れ子)が許されている。最初に述べた例外とはEnumerationノードのことである。
Groupノードはユーザインターフェイスの上で他のノードをGroupにまとめる機能を持つ。これは単に表示のためだけで、ノードグラフの中には最終的には含まれない。
ようするにはっきり言ってGEN<i>CAMの規格は抽象化のレベルが低い、と僕は思う。具体的にどこかどう、という話をしたい(そして「ばかものめ、GEN<i>CAMの規格はよくできていて美しいのだ」という人の話を聞きたい)けど、そのまえにGEN<i>CAMの規格に対する僕の理解が正しいかどうかを確かめるために僕なりにまとめておく。ちょっと長くなるけど、いっきに今回だけで終わらせる。
できればGEN<i>CAMの仕様をご存知の方がフィードバックしてくれるとうれしいんですが.....
6.1.1 カメラ記述ファイル
GEN < i > CAM規格では、カメラの機能、たとえばゲインやシャッタにユーザがアクセスする方法をファイルに書いておく。このファイルを「カメラ記述ファイル」と呼ぶ。カメラ記述ファイルはXMLの形式で書く。XMLのトップレベルはRegisterDescriptionというノードをただ一つだけ含む。以下はXMLファイルの先頭の例である。
<?xml version="1.0" encoding="utf-8"?> <RegisterDescription ModelName="ICX445_M_T" VendorName="Imaging_Source" ....
6.1.2 ノード
カメラ記述ファイルの中では、カメラのひとつの機能をXMLでの呼び方にならって「ノード」と呼ぶ。ノードはユーザが直接アクセス可能なものと、ユーザからは見えないものがある。ノードはすべて固有な「名前」を持っていて区別することができる。ある名前を持つノードは一つのカメラ記述ファイルの中に二つ以上は存在しない。存在しない場合、その機能をカメラは持っていないということになる。ノードはRegisterDescriptionの中のエレメントとしてフラットにならんでいる。つまり(後述の例外を除いて)ノードは入れ子にはならない、ということである。
次はRegsterDescriptionの構造の例である(一部は「...」で省略してある)。
<RegisterDescription ......> <Port Name="Device" NameSpace="Standard" /> <Category Name="Root" NameSpace="Standard"> <pFeature>AcquisitionControl</pFeature> .... </Category> <Category Name="AcquisitionControl" NameSpace="Standard"> <pFeature>AcquisitionStart</pFeature> ..... </Category> <Command Name="AcquisitionStart" NameSpace="Standard"> <pValue>AcquisitionStartStopRegister</pValue> <CommandValue>0x00000001</CommandValue> </Command> ..... </RegisterDescription>この例ではPortノード、CategoryノードがふたつとCommandノードが見えている。
たとえばゲインを表すノードにはGainという名前になっている。ある名前を持つノードが実際のカメラのどのような機能をあらわしているかはセマンティクスの問題でカメラ記述ファイルの範囲ではない。そういうセマンティクスは別の規格で決めているが、その規格は強制ではないので実際にはカメラごとに確認する必要がある。
6.1.3 ノードの形式
ノードは<NodeType Name="NodeName" otherAttributes...>elements...</NodeType>の形をしている。ノードタイプについては後述。Nameアトリビュートがノードの名前に対応する。とうぜんNameアトリビュートの値はRegisterDescription内で重複はない(重複がないことを前提に読んでよい)。
ゲインを表すノードの記述の例を以下に示す。
<Float Name="Gain" NameSpace="Standard"> <Extension> <Default>0e0</Default> </Extension> <ToolTip>Gain</ToolTip> <pValue>GainToGainRaw</pValue> <pMin>GainMin</pMin> <pMax>GainMax</pMax> <Unit>dB</Unit> <Representation>Linear</Representation> </Float>
6.1.4 ノードのエレメント
カメラ記述ファイルはXMLの形式にしたがっているのでノードは「エレメント」を持っている。ノードはその属性をエレメントで表現する。後述するノードタイプごとに持ちえるエレメントの集合が決まっている。またエレメントはその名前で区別されて重複はない。たとえばGainノードはGainの値そのものを表現するエレメントや、値の最大値や最小値を表現するエレメントを持っている。ノードは持ちえるエレメントを全て持っているとは限らない。ノードがあるエレメントを持っていない場合、そのプロパティはデフォルトがある場合と、その属性そのものがない場合がある。それはエレメントの定義(基本的にはスキーマファイル)で決められている。
たとえばGainノードに最大値のエレメントがない場合、そのカメラはどんなGainの値も受け付けることになる。ただしそれがカメラ側でどのように解釈されるかはカメラのハードウェアに依存する。
6.1.5 アトリビュート
カメラ記述ファイルはXMLの形式にしたがっているのでノードは「アトリビュート」を持っている。アトリビュートにはノードのスタテイックな属性が書かれている。ノードの名前はNameアトリビュートが保持している。そのほかの持ちえるアトリビュートは決まっている(スキーマファイルを参照)。6.1.6 ノードの継承
ノードが持っているエレメントの集合は大きくなることがあるので、別のノードのエレメントに追加して新しいエレメントの集合を定義することがある。これをノードの継承と呼んでいるが、スキーマファイルの記述の簡略化のためのスタティックなものであり、継承によってプログラマが新しいノードを作れるような機能があるわけではない。また当然カメラのユーザには無関係である。6.1.7 インターフェイス
ノードは「インターフェイス」と呼ぶ「型」を持つ。インターフェイスには
IInteger | 値、最大値、最小値、増分を持つスライダ |
IFloat | 上に加えて物理的な単位を持つスライダ |
IString | 文字列を表すテキストボックス |
IEnumeration | ドロップダウンメニュー |
ICommand | コマンドボタン |
IBoolean | チェックボックス |
IRegister | 16進数のテキストボックス |
ICategory | カメラの機能のツリー構造へのエントリを示す |
IPort | カメラのポートを表す。これは表示されない |
それぞれのインターフェイスには実質的にデータ型が決まっている。考えられるようにIIntegerは整数型、IFloatは浮動小数点型、などである。
6.1.8 インターフェイスの値
ノードはそのインターフェイスに従った内部状態である「値」を持つ。ノードに対してその時点での具体的な値を要求することができる。これは一般的には「評価」と呼ばれるプロセスに対応すると考えられる。ただしすべてのノードが値を持つわけではない。たとえばユーザアクセス可能な機能をまとめておくICategoryやカメラへのコマンドを表すICommandは意味ある値を持たない。
ノードの値は
- Value
- pValue
6.1.9 エレメントの命名規則
小文字の「p」で始まる名前のエレメントは他のノードを参照していることを表す。たとえばGainノードのpValueエレメントはそのGainの値がpValueで参照されるノードの値で決まることを表している。一方GainノードはValueエレメントも持つことができる。ValueにはGainの定数値が内包するエレメントとして書かれている。とうぜんpValueとValueの両方を同時に持つことはない。6.1.10 ノードタイプ
ノードはいくつかのタイプに分類される。それをノードタイプと呼ぶ。ノードはインターフェイスによって大分類が、ノードタイプによってそのなかの小分類が与えられる。たとえばIItengerインターフェイス(整数型)をもつノードタイプは
- IntReg
- MaskedIntReg
- Integer
「ノードの形式」の節に書いたようにRegisterDescriptionのエレメントの名前としてノードタイプを指定して、そのNameアトリビュートにノードの名前を指定する。
6.1.11 ノードツリー
ノードは参照している他のノードの値を読んだり書き換えたりすることができる。ノードが参照するノードを読み書きしたとき、さらにそのノードが参照する他のノードの読み書きが発生する場合がある。もちろん参照の連鎖が元のノードに戻ることはない。したがってノードは有向非巡回グラフとなる(規格書では「ツリー」と呼んでいるが厳密には正しくない)。ノードAがノードBを読み書きすることを
| (1) |
6.1.12 RootノードとPortノード
ノードの読み書き「A → B」の関係を大小関係「A > B」とみなすと、最大値がひとつだけあってこれを「Root」ノードと呼ぶ。ユーザはRootノードからカメラの機能にアクセスできる。一方、最小値となるノードは複数個ある。これはグラフの末端となる。グラフの末端はふた通りある。ひとつは内部に定数を内包するノード(「フローティングノード」と呼ぶときがある)で、もうひとつはカメラのレジスタを参照する(読み書きする)ノードである。カメラレジスタを参照するノードを「Port」と呼ぶ。Portノードはただひとつだけ存在していなければならない。そのただひとつのノードの名前は一般的には「Device」である。また、カメラレジスタを参照する必要のあるノードは必ず単一のPortノードを参照していなければならない。
6.1.13 Rootノードのエレメント
RootノードはCategoryTypeというノードタイプでpFeatureというエレメントを複数個持っている。このエレメントは他のノードの名前を保持していて、ユーザが直接カメラの状態を知ったり、操作するためのノードであることを表す。機能を分類するためにほかのCategoryTypeノード保持している場合もある。ユーザはRootノードから辿れるpFeatureノードのみ操作できる(カメラアプリはそうプログラムされるべきである)。
6.1.14 ノードの一般的な属性
ノードタイプによっていろいろな属性が定義されているが、多くのノードに共通の属性もある。たとえば、
- 読み書き属性(Readable、Writable)
- キャッシュ可能性
- ビジビリティ(ユーザから見えるかどうかなど)
- ToolTip(ノードの簡単な説明)
6.1.15 典型的なノードタイプ
典型的なドードタイプとそのインターフェイスを示す。- Category(ICategory)
- Register(IRegister)
- Integer(IInteger)
- IntReg(IInteger)
- MaskedIntReg(IInteger)
- StructReg
- Boolean(IBoolean)
- Command(ICommand)
- Float(IFloat)
- FloatReg(IFloat)
- Enumeration(IEnumeration)、EnumEntry
- String(IString)
- StringReg(IString)
- SwissKnife(IFloat)
- Converter(IInteger)
- IntSwissKnife(IInteger)
- IntConverter(IInteger)
- Port(IPort)
- その他
- ユーザインターフェイスと直接対応するもの(Integer、Float、Enumerationなど)
- ユーザインターフェイスとは直接対応しないもの(Register、SwissKnifeなど)
- 特別なノード(Category、Portなど)
- 値を持たないもの(Category、Port、Commandなど)
- 整数の値をとるもの(Integer、IntReg、MaskedIntRegなど)
- 実数値をとるもの(Float、FloatRegなど)
- その他の値をとるもの(Boolean、Enumeration、Stringなど)
- Registerを継承するタイプ(IntReg、MaskedIntRegなど)
- 抽象タイプであるNodeを継承するタイプ(上記以外)
6.1.16 ビット幅、符号、バイトオーダ、ビット順
ノードの値は具体的なデータ型が指定される。その値のビット幅はバイト単位でLengthエレメントで表される。とり得る値は最大が8の2nに限られる。符号はSignエレメントでSignedあるいはUnsignedのどちらかが指定される。ただし、Lengthが8でUnsignedは指定できない。符号なし整数の最大値は263−1となる(だっせー。おっと、つい気持ちが入ってしまった)。バイトオーダはEndiannessエレメントでLittleEndianかBigEndianが指定される。残念なことにLittleEndianがデフォルトになっている。ネットワークバイトオーダ(BigEndian)をとるのが自然なGigE VisionカメラではすべてEndiannessを指定しないといけない、ということになる。
ビット順を指定するとき、バイトオーダによって指定の仕方が逆になる。LittleEndianではLSBを0に、BigEndianではMSBを0にする。
6.1.17 特殊なノード
CategoryやCommand以外に、GEM < i > CAMには特殊なノードタイプがある。SwissKnifeとConverterはC式に似た形式の数式が記述できる。変数には他のノードを参照することができる。例えばSwissKnifeはイメージャのサイズとピクセルあたりのバイト数を表すノードから転送バイト数を計算する、などに使える。またConverterは双方向に定義が可能なノードで、カメラのゲインレジスタの整数値と、浮動小数点型のdB値とを相互に変換できる。またEnumerationは値に名前をつけた配列を保持できる。その要素はEnumEntryというノードで、名前と整数値を保持する。Enumerationノードのみにサブノード(ノードの入れ子)が許されている。最初に述べた例外とはEnumerationノードのことである。
Groupノードはユーザインターフェイスの上で他のノードをGroupにまとめる機能を持つ。これは単に表示のためだけで、ノードグラフの中には最終的には含まれない。
6.1.18 具体的なノードタイプとアトリビュート
それぞれのノードタイプについては規格書を参照。あるノードタイプがとり得るエレメントの詳細はスキーマファイルを参照。エレメントの説明は規格書の方にある。とり得るアトリビュートもスキーマファイルを参照。2015-03-14 21:18
nice!(0)
コメント(0)
トラックバック(0)
コメント 0