ch32funのmruby/cのhalと標準入出力
mrubyc_arduinoでは、hal_writeなどは、メインのスケッチの中で定義されている。 ch32funを使ったmruby/cにおいても、なんとなくその流儀を踏襲していたが、ファイルの構造を眺めていたら、これらはhal.cの中で定義すべきものであることに気が付いた。 そこで、ch32fun用のhal.cを作ってみたが、こんな感じになった。
#include "hal.h"
#include "ch32fun.h"
int hal_write(int fd, const void *buf, int nbytes) {
_write(0, (char*)buf, nbytes);
return nbytes;
}
int hal_flush(int fd) {
return 0;
}
void hal_abort(const char *s) {}
するとこれらをメインのコードに書く必要が無くなる。
hal_writeはmruby/cの標準出力に対応するが、 2026/4/25のブログに書いたように、 私は標準入力も使いたいので、mrbc_get.cなどを作ってhal_readという関数を介してgetbyte,getc,getsを使えるようにしている。 以前はhal.hの中でhal_readの宣言を行っていたが、mruby/cのファイルをできるだけ変更するべきでは無いと考えて、mrbc_get.hに移動した。
#ifndef _MRBC_GET_H #define _MRBC_GET_H #include "mrubyc.h" unsigned char hal_read(int fd); void mrbc_init_class_get(void); #endif
また、mrbc_get.cにおいては、getbyteはC言語で定義したが、getcとgetsはrubyで書いてmrbに変換して組み込んでいた。 しかし、コンパイルしたときのサイズを少しでも小さくするために、これらもC言語で書いてみた。 getsは動的なバッファを確保すると複雑になるので、一行は127文字以下とした。
#include "mrbc_get.h"
static void c_object_getbyte(struct VM *vm, mrbc_value v[], int argc)
{
uint8_t ret=hal_read(0);
SET_INT_RETURN( ret );
}
static void c_object_getc(struct VM *vm, mrbc_value v[], int argc)
{
char buf[2] = {0,0};
buf[0]=hal_read(0);
mrbc_value value = mrbc_string_new_cstr(vm, buf);
SET_RETURN(value);
}
static void c_object_gets(struct VM *vm, mrbc_value v[], int argc){
int i;
char buf[128];
for(i=0;i<127;){ buf[i]=hal_read(0); if(buf[i++]=='\n') break; }
buf[i]=0;
mrbc_value value = mrbc_string_new_cstr(vm, buf);
SET_RETURN(value);
}
void mrbc_init_class_get(void){
mrbc_define_method(0, 0, "getbyte", c_object_getbyte);
mrbc_define_method(0, 0, "getc", c_object_getc);
mrbc_define_method(0, 0, "gets", c_object_gets);
}
確認してみると、160バイト程ではあるがコンパイルサイズは小さくなったし、おそらくメモリの使用量も減っただろう。 また、これも僅かではあるが、メインのコードもすっきりした。 hal_readもmrbc_get.cの中で定義した方が良いのかも知れないが、USB CDCを使っている関係で、main.cの中で定義するようにしている。