mruby/cデバイス側のC実装

# はじめに
mruby/cを勉強中なので少しずつ書いていく予定です。(デバイス側のCの実装)
間違っている箇所があればコメントしていただけるとありがたいです。
(mrb・mrbcがバージョンの違いで混ざっているかもしれない)

mruby/cの導入やチュートリアルに関しては[こちら](https://www.s-itoc.jp/activity/research/mrubyc/mrubyc_tutorial/)を参照くださいm(_ _"m)

# ハードウェア設定：hal.h
新しいハードウェアへ適応させるための記述法

上がタイマーを使用する場合の記述で下がタイマーを使用しない場合となっている。
タイマーを使用する場合は別途タイマーの実装が必要となる。
タイマーを使用しない場合は1ms単位のスリープを入れてあげる。


下記PIC32の例
xc32を使用(ドキュメント：[MPLAB® XC32 C/C++ コンパイラユーザガイド](http://ww1.microchip.com/downloads/jp/DeviceDoc/50001686G_JP.pdf))

``` hal.h
#ifndef MRBC_NO_TIMER
# define hal_init()        ((void)0)
# define hal_enable_irq()  __builtin_enable_interrupts()
# define hal_disable_irq() __builtin_disable_interrupts()
# define hal_idle_cpu()    _wait()

#else // MRBC_NO_TIMER
# define hal_init()        ((void)0)
# define hal_enable_irq()  ((void)0)
# define hal_disable_irq() ((void)0)
# define hal_idle_cpu()    ((delay(1)), mrbc_tick())

#endif
```
ちなみにdelayは作った関数 →　https://qiita.com/aikawa_YO/items/3f95c597907c53f0999d

# クラス、メソッド定義
MY_CLASS.funcを定義する。

```c
void main{
  mrb_class *my_class;
  my_class = mrbc_define_class(0, "MY_CLASS",	mrbc_class_object);
  mrbc_define_method(0, my_class, "func",	c_func);
}
```

#関数の書き方

```c
/*
mrb_vm *vm    :vm構造体へのポインタ
mrb_value v[] :引数
　v[0]：自分自身
  v[1..n]：引数
int argc      :　引数の数
*/
static void c_func(mrb_vm *vm, mrb_value v[], int argc){}
```

# 関数の中身

```c
static void c_func(mrb_vm *vm, mrb_value v[], int argc)
{
  # 引数6個ありますか？
  if(argc == 6){}
  # 引数の型をチェック
  # v[1].tt :引数１のタイプ 
  # タイプはvalue.hに定義されてる
  #ストリングですか？
  if(v[1].tt == MRB_TT_STRING){};
  # フロートですか？
  if(v[2].tt == MRB_TT_FLOAT){};
  
  #引数を受け取る
  # intの場合
  int nam = v[4].i;
  

  # 文字列を返す
  mrb_value moji = mrbc_string_new_cstr(vm, "moji");
  SET_RETURN(moji);
  # 配列を返す
  mrb_value hako = mrbc_array_new(vm, 4);
  SET_RETURN(hako);
}
```

##int
取得した整数をそのまま返すプログラム

<TABLE>
<TR><TD>関数名</TD><TD>役割</TD><TD>第一引数</TD><TD>第二引数</TD></TR>
<TR><TD>[mruby value].i</TD><TD>int化</TD><TD></TD><TD></TD></TR>
<TR><TD>SET_INT_RETURN</TD><TD>intを返す</TD><TD>int</TD><TD></TD></TR>
</TABLE>

```c
static void c_test(mrb_vm *vm, mrb_value *v, int argc)
{
    int val;
    //値を取得(int)
    if(v[1].tt == MRB_TT_FIXNUM){
        val = v[1].i;
    };
    /* 別方法
    val = GET_INT_ARG(1);
    */

    //intを返す
    SET_INT_RETURN(val);

    /* 別方法
    mrb_value mv = mrb_fixnum_value(val);
    SET_RETURN(mv);
    */
}
```

##float
取得した浮動小数点数をそのまま返すプログラム

<TABLE>
<TR><TD>関数名</TD><TD>役割</TD><TD>第一引数</TD><TD>第二引数</TD></TR>
<TR><TD>[mruby value].d</TD><TD>float化</TD><TD></TD><TD></TD></TR>
<TR><TD>SET_FLOAT_RETURN</TD><TD>floatを返す</TD><TD>float</TD><TD></TD></TR>
</TABLE>

```c
static void c_test_float(mrb_vm *vm, mrb_value *v, int argc)
{
    double val;
    
    //値を取得(float)
    if(v[1].tt == MRB_TT_FLOAT){
        val = v[1].d;
    };
    /* 別方法
    val = GET_FLOAT_ARG(1);
    */

    //floatを返す
    SET_FLOAT_RETURN(val);

    /* 別方法
    mrb_value mv = mrb_float_value(val);
    SET_RETURN(mv);
    */
}
```

##配列
取得した配列をそのまま返すプログラム(整数のみが入った配列)

<TABLE>
<TR><TD>関数名</TD><TD>役割</TD><TD>第一引数</TD><TD>第二引数</TD></TR>
<TR><TD>mrbc_array_size</TD><TD>配列のサイズを取得</TD><TD>引数</TD><TD></TD></TR>
<TR><TD>mrbc_array_get</TD><TD>配列の要素を取得</TD><TD>引数</TD><TD>取得したい配列位置番号</TD></TR>
<TR><TD>mrbc_array_new</TD><TD>新しくruby用の配列作成</TD><TD>vm</TD><TD>配列のサイズ</TD></TR>
<TR><TD>mrbc_array_set</TD><TD>ruby用配列に値を挿入</TD><TD>mruby value(配列)</TD><TD>挿入位置</TD><TD>mruby value(挿入値)</TD></TR>
<TR><TD>SET_RETURN</TD><TD>ruby用の値を返す</TD><TD>mruby value</TD><TD></TD></TR>
</TABLE>

```c
static void c_test_array(mrb_vm *vm, mrb_value *v, int argc)
{
  //rubyから配列取得
  int n = mrbc_array_size(&v[1]);
  int a[n]; //aがｃ用の配列
  for(int i=0;i < n;i++){
    a[i] = mrbc_array_get(&v[1] ,i).i;
  }
  //配列の取得完了

  //ruby用の配列に入れ直して返す
  mrbc_value hako = mrbc_array_new(vm, n);
  for(int j=0;j < n;j++){
    mrbc_value v = mrb_fixnum_value(a[j]);
    mrbc_array_set(&hako,j,&v);
  }
  SET_RETURN(hako);
}
```

##hash

<TABLE>
<TR><TD>関数名</TD><TD>役割</TD><TD>第一引数</TD><TD>第二引数</TD></TR>
<TR><TD>mrbc_hash_size</TD><TD>ハッシュ数を取得</TD><TD>引数</TD><TD></TD></TR>
<TR><TD>mrbc_hash_iterator</TD><TD>イテレーター取得？</TD><TD>引数</TD><TD></TD></TR>
<TR><TD>mrbc_hash_i_has_next</TD><TD>次の要素を確認有無</TD><TD>mrb_hash_iterator</TD><TD></TD></TR>
<TR><TD>mrbc_hash_i_next</TD><TD>キーを取得</TD><TD>mrb_hash_iterator</TD><TD></TD></TR>
</TABLE>

```c
static void c_test(mrb_vm *vm, mrb_value *v, int argc)
{
    int val;
    val = mrbc_hash_size(&v[1]);
    mrb_hash_iterator it = mrbc_hash_iterator(&v[1]);
    mrb_value a;
    int ab[val];
    int num = 0;
    for(int num=0;mrbc_hash_i_has_next(&it);num++){
        mrb_value *key = mrbc_hash_i_next(&it);
        a =  mrbc_hash_get(&v[1], key);
        ab[num] = a.i;
    }
    mrb_value hash = mrbc_array_new(vm, val);
    for(int j=0;j < val;j++){
      mrb_value v = mrb_fixnum_value(ab[j]);
      mrbc_array_set(&hash,j,&v);
    }
    
    SET_RETURN(hash);
}
```

##文字列
文字が"a"なのかチェックするプログラム

<TABLE>
<TR><TD>関数名</TD><TD>役割</TD><TD>第一引数</TD><TD>第二引数</TD></TR>
<TR><TD>mrbc_string_size</TD><TD>文字の数を取得</TD><TD>引数</TD><TD></TD></TR>
<TR><TD>mrbc_string_cstr</TD><TD>文字列を取得</TD><TD>引数</TD><TD></TD></TR>
<TR><TD>mrbc_string_new_cstr</TD><TD>新しくruby用の文字列作成</TD><TD>vm</TD><TD>文字列</TD></TR>
<TR><TD>SET_RETURN</TD><TD>ruby用の値を返す</TD><TD>mruby value</TD><TD></TD></TR>
</TABLE>

```c
static void c_test_string(mrb_vm *vm, mrb_value *v, int argc)
{
  mrb_value moji;
  //int size = mrbc_string_size(&v[1]);

  //文字列取得
  char *mo = mrbc_string_cstr(&v[1]);

  //判別
  if(!strcmp(mo, "a")){
    moji = mrbc_string_new_cstr(vm, "ok");
  }else{
    moji = mrbc_string_new_cstr(vm, "no");
  }
  
  //文字を返す(ok or no)
  SET_RETURN(moji);
}
```