mrb_funcallについて

少しずつですが、PICrouterのC側でやっている処理をmruby側で行うように作業しています。
 
PICrouterでは、OSCの受信とUSBの送受信処理はmainループで行い、OSCの送信処理は
タイマーを使うようにしています。mainループで行う処理はmruby側に移行させやすいのです
が、タイマーで実行している処理はどうしたもんか・・・と考えています。
 
少し調べたところ、Cからmrubyで定義したメソッドを呼び出せるmrb_funcallというのがあり、
Cのタイマー割り込み用の関数内部で定期的にmrb_funcallを呼べないかな?と試してみる
ことにしました。
 
まず、mruby側のコードは極力シンプルに
 
def toggle_led
  onboard_led(1, 'toggle')
end

6.times do
  toggle_led
  onboard_led(2, 'toggle')
  delay_1ms(200)
end
とします。toggle_ledメソッドの中で呼んでいるonboard_ledはC側でmrb_define_methodで
登録したPICrouterボード上のLEDを制御する関数です。
 
このtoggle_ledをCから次のように呼び出してみます。
 
mrb_state* mrb = mrb_open();

    mrb_define_method(mrb, mrb->object_class, "delay_1ms", mrb_delay_1ms, ARGS_REQ(1));
    mrb_define_method(mrb, mrb->object_class, "onboard_led", mrb_onboard_led, ARGS_REQ(2));

    // 1.
    mrb_load_irep(mrb, bytecode);

    // 2.
    LED_1_On();
    LED_2_On();
    // 3.
    DelayMs(1000);
    // 4.
    LED_1_Off();
    LED_2_Off();

    // 5.
    mrb_funcall(mrb, mrb_top_self(mrb), "toggle_led", 0);
    // 6.
    DelayMs(500);
    // 7.
    mrb_funcall(mrb, mrb_top_self(mrb), "toggle_led", 0);
    // 8.
    DelayMs(500);

    mrb_close(mrb);
ここで問題発生。mrb_funcallから次の処理に進みません。あれれ?と思ってtwitterで
呟いてみたところ、Matzさんから直接レスを頂き、上のテストコードを見て頂きました。
mrb_funcall等の使い方には問題無さそうとのこと。となると、自分がすっとぼけた事を
どっかでやってるなぁ・・・となり、いきなりmrb_funcallで呼ぶメソッド内でmrb_define_method
した関数を使うのを止め、単純に数値を返すようなメソッドにしてみたところ、それでも
mrb_funcallそのものが、呼び出すと行ったきり戻ってこない。一晩頭を冷やして翌朝に
ICD3でbreakpoint張って、地道に探ってみることに。
 
原因は、mrubyの省メモリ化を行おうと、value.hのmrb_value構造体を#pragma pack(1)
で詰めていたことでした。この部分を削って再度コンパイルし直したら無事にmrb_funcallが
動作するようになりました。内部でmrb_define_methodした関数を呼んでも問題なし。
#pragma pack()を使うときは注意した方が良いですね。
 
さて、ようやく本題のタイマー割り込み内でmrb_funcallですが・・・・、やっぱりタイマー内で
実行するには処理が重すぎる?ようで、PICrouterが動作停止してしまいました。
 
この部分はもうちょっと考える必要がありそうです。むむむ。

コメントをどうぞ

Your email address will not be published. Required fields are marked *

*