mrubyでのバイナリの扱い
GR-SAKURAにmrubyを移植しているのですが、Rubyに関してそれほど詳しくないので、バイナリをどう扱えばいいのか分かりませんでした。
例えば、Cなどでよくある write関数(write(int handle, void *buf, unsigned n))などを実現したいとき、mrubyではどのように扱えばいいのか?
mrubyに詳しい方に聞いてみたところ分かりました。
mrubyは文字列でバイナリも扱える
そう、mrubyは文字列でバイナリも扱えました。結局、Luaと同じでした。
例えば、0x10 0x20 0x30 0xD0 0xE0 0xF0というバイナリデータを作りたいときは以下のように書けます。
bin = 0x10.chr + 0x20.chr + 0x30.chr + 0xd0.chr + 0xe0.chr + 0xf0.chr
たとえ、文字列に0が含まれていても大丈夫です。下記のようなバイナリ列もできます。
bin = 0.chr + 0.chr + 0.chr + 0.chr + 0.chr + 0.chr
chrはmrbgem扱い
ここで注意が必要です。chrはmrbgemになっており、ビルドするときにmruby-numeric-extをインクルードする必要が有ります。
mruby-numeric-extをインクルードするには、build_config.rbに下記を追加するだけです。
# Cross build for GR-SAKURA MRuby::CrossBuild.new('grsakura') do |conf| toolchain :grsakura conf.gem "#{root}/mrbgems/mruby-numeric-ext" end
バイナリ列を扱うmruby関数を作る
では、バイナリ列を扱うmruby関数を作るにはどうするか、それは単純に文字列を扱うメソッドを作成すればいいだけです。
例えば、GR-SAKURAの関数にSerial.write(const unsigned char *buf,int len)というものが有ります。これをmrubyでラップするとすると以下のようになります。
ライブラリを定義します。int read() と write(const unsigned char *buf,int len)を作ってみます。
//************************************************** // ライブラリを定義します //************************************************** void serial_Init(mrb_state *mrb) { struct RClass *systemModule = mrb_define_module(mrb, "Serial"); mrb_define_module_function(mrb, systemModule, "read", mrb_system_read, ARGS_NONE()); mrb_define_module_function(mrb, systemModule, "write", mrb_system_write, ARGS_REQ(2)); }
read()は下記です。1文字読み込んでint型なので、mrb_fixnum_value()を使って戻しています。
//************************************************** // シリアルから1バイト取得します: Serial.read // Serial.read() // 戻り値 // 0x00〜0xFFの値、データが無いときは-1が返ります //************************************************** mrb_value mrb_system_read(mrb_state *mrb, mrb_value self) { int ret = -1; if(Serial.available()){ ret = Serial.read(); //1文字取得 } return mrb_fixnum_value( ret ); }
write()は下記です。mrb_get_args()を"S"で受けて、RSTRING_PTR()で文字列のポインタを取得し、あとは通常のchar配列として扱います。
//************************************************** // シリアルにデータを出力します: Serial.write // Serial.write( buf, len ) // buf: 出力データ // len: 出力データサイズ // 戻り値 // 出力したバイト数 //************************************************** mrb_value mrb_system_write(mrb_state *mrb, mrb_value self) { int len; mrb_value value; char *str; mrb_get_args(mrb, "Si", &value, &len); str = RSTRING_PTR(value); int ret = Serial.write( (const unsigned char *)str, len ); return mrb_fixnum_value( ret ); }
以上、防備録としてmrubyのバイナリの使い方を書いておきます。