先日、
libftdiライブラリへのバインディングを構築する必要がありました
。libftdiライブラリは、
FTDIチップ(RS-232またはTTLレベルを介したシリアルデータ伝送をUSBバス信号に変換するためのチップです)。
バインディングを作成するために、
FFI拡張機能を選択しました。これにより、動的ライブラリをロードし、それらのバインダーを構築できます。
FFIにはいくつかの利点があり、その利点があります。
- インタプリタMRI Ruby 1.9、MRI Ruby 1.8、JRubyのサポート、Rubiniusの限定サポート。
- (特に)Windowsプラットフォームのサポート。
- バインダーをコンパイルする必要はありません。
- 便利なバインディング記述言語。
Rubyのリポジトリをバインドします 。
開始する
libftdiライブラリをロードするバインディングモジュールを作成します。
require 'ffi'
管理されていないリソース管理
libftdiの主な本質はそのコンテキストです。このコンテキストは、作業を開始するときに強調表示し、それに応じてリリースする必要があります。
FFI::ManagedStruct
クラスは、アンマネージリソースの自動収集を担当します。
attach_function :ftdi_new, [ ], :pointer attach_function :ftdi_free, [ :pointer ], :void
FFI :: ManagedStructコンストラクターは、指定されたレイアウト(ネイティブビューからFFIビューへの構造変換のマップ)によってマーシャリングされる構造へのポインターを受け入れます。 コンストラクターでは、ftdi_newの呼び出し(基本的にmallocを使用)でポインターを取得し、スーパークラスに渡します。
ガベージを収集するとき、ネイティブクラスへのパラメーターポインターを使用してreleaseクラスメソッドが呼び出され、そのクラスで解放されます。
APIを形成します
すべてのライブラリ呼び出しはコンテキストで機能するため、すべてのAPIコンテキストメソッドを作成し、libftdiコンテキストへのポインターを返すctxメソッドを作成して、これらの呼び出しの呼び出しを簡素化します。
ほとんどのlibftdi関数は、結果がゼロより小さい場合にエラーを示す符号付き整数を返します。 したがって、関数呼び出しの結果を解析し、問題が発生した場合に例外をスローするためのヘルパーを作成すると便利です。
private def ctx self.to_ptr end def check_result(status_code) if status_code < 0 raise StatusCodeError.new(status_code, error_string) end nil end
ここで、
error_string
は、libftdiコンテキストからエラーメッセージを受け取るメソッドです。
次に、たとえば、ポートオプションの列挙を作成し、
ftdi_set_interface
関数
ftdi_set_interface
バインドし
ftdi_set_interface
。 私たちが踊る場所:
enum ftdi_interface { INTERFACE_ANY = 0, INTERFACE_A = 1, INTERFACE_B = 2, INTERFACE_C = 3, INTERFACE_D = 4 }; int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface);
そして、私たちは何を得ます:
バイト配列を使用する
ASCIIZ文字列の操作は簡単ですが(type
:string
)、それらを使用してバイトの配列を転送しようとすると、FFIマーシャラーが最初のゼロバイトでつまずくため、失敗に終わります。
バイトの配列を転送するには、type
:pointer
を使用し
:pointer
。これは、FFI :: MemoryPointer(メモリ内の対応するバッファの割り当てと充填)を通じて作成します。
attach_function :ftdi_write_data, [ :pointer, :pointer, :int ], :int class Context
ご覧のとおり、バインダーの作成は簡単な作業でした。
構築を自動化する場合は、
SWIGの方向を確認することをお勧めします。