Wio3G Soracom EditionやWioLTE JP Versionでmruby/c動くようにした

## レポジトリ

githubのリポジトリは以下
[https://github.com/hiroeorz/mrubyc_for_Wio_cell_lib](https://github.com/hiroeorz/mrubyc_for_Wio_cell_lib)

使い方とかは[README](https://github.com/hiroeorz/mrubyc_for_Wio_cell_lib/blob/master/README.md)に書いたので、関心のある方はそれをみていただければ。

## 全体の構成

サーバーサイド含めてなんだかんだやってるうちに、全体の構成はこんなかんじになった。今流行りの（?）サーバーレスアーキテクチャー。

![Monban IoT ネットワーク構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13835/e722432f-7848-5b22-7c57-02ad426b2642.png "Monban IoT ネットワーク構成図.png")


## Wio3G SoracomEdition、 WioLTE JP Version とは

Wio3G、WioLTEはSeeed社が開発したマイコンモジュールです。
特徴はこのサイズで3G,LTEの通信モジュールを搭載しており、Groveと呼ばれるインターフェイスを通してデジタル、アナログI/Oはもとより、UART、I2Cなどの入出力をもっている点です。

<div>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13835/b7fae0ba-6c78-2d37-d3a4-8ec9c443bd9c.png" width=60% style="display:block; float:left;">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13835/cfe6f0dc-2ba5-d1f0-589a-7cbc2838dfca.png" width=60% style="display:block; float:left;">
</div><div style="clear:both;">


## 経緯

モンスターラボの[hasumi](https://twitter.com/hasumikin)さんが講師をされた、[ESP32×mruby／c IoTハンズオンセミナー](https://www.s-itoc.jp/news/wanted_seminar/825)に参加したのがきっかけでmruby/cに関心を持ち、ググったら[kishima](https://twitter.com/kishima)さんという方がすでに[WioLTEでmruby/cを動かしておられる](https://silentworlds.info/2018/05/26/post-188/)ことがわかり、手元にあった[Wio 3G SORACOM Edition](https://soracom.jp/products/module/wio_3g_soracom_edition/)でも動かないかなと思ったのがきっかけです。

ハンズオンがあったのが3月でしたが、4月、5月は出張や会議が多く、なんとなく気持ちもせかせかしてたので見送り、6月に少し落ち着いたので腰を据えて取り組んでみました。

やったことは以下の通り。

1. とりあえず[mruby/c library for Wio LTE](https://github.com/kishima/libmrubycForWioLTEArduino)がそのまま使えないか試してみたけど、流石にWio3GとはCのライブラリも異なるので動かなかった。
2. 気を取り直してkishimaさんの書いておられる[mruby/cの小さな世界](https://nextpublishing.jp/book/10601.html)の電子書籍を購入して読む。
3. Wio3G向けのライブラリとしてコードを書き始める。mruby/cのリポジトリからソースをコピーし、halディレクトリ以下をWio3G用に作る。
4. Wio3G SORACOM Edition用のArduinoライブラリ[Wio_3G_for_Arduino](https://github.com/SeeedJP/Wio_3G_for_Arduino)をラップするRubyのクラス[Wioクラス](https://github.com/hiroeorz/mrubyc_for_Wio_cell_lib/blob/master/doc/Wio.md)のコードを書く。
5. 途中で[Wio_3G_for_Arduino](https://github.com/SeeedJP/Wio_3G_for_Arduino)はすでにメンテされていなことを知り、[Wio_cell_lib_for_Arduino](https://github.com/SeeedJP/Wio_cell_lib_for_Arduino)に切り替える。この時点でWio3Gの基本的な機能はmruby/cから実行できるようになった。
6. [Wio_cell_lib_for_Arduino](https://github.com/SeeedJP/Wio_cell_lib_for_Arduino)をラップするようにしたことで、LTE-M版である[Wio LTE M1/NB1](https://soracom.jp/products/module/wio_lte_m1_nb1/)も（たぶん）カバーできたことから、どうせならWioLTEでも動くようにするか、と思い[Wio LTE JP Version](https://soracom.jp/products/module/wio_lte/)もカバーした。
7. 実戦で使うにはサーバーとの通信や、送受信するデータのパーサ、ジェネレータも欲しかったので[MQTTクライアント](https://github.com/hiroeorz/mrubyc_for_Wio_cell_lib/blob/master/doc/MQTT.md)、[JSONパーサ・ジェネレータ](https://github.com/hiroeorz/mrubyc_for_Wio_cell_lib/blob/master/doc/JSON.md)も使えるようにした。


## 現在

* 自社製品（工場に設置される設備）の制御基板とUARTでシリアル通信してみたところ正常に通信でき、基板から情報を取得したり書き込んだりできた。
* Soracom BeamとMQTTで接続し、BeamからAWS IoTへデータを送り、DynamoDBに保存するのも特に問題なくできた。
* 逆にWebインターフェイスからAWS IoT、そしてUARTシリアルを通してデータを書き込み遠隔設定もできた。

## ハマったところなど

1. そもそもC、C++の経験がゼロなので人のコード読みながら書いてる感じ。　
2. mruby/cの `self` がブロック中で自身のオブジェクトを指さないことがあってハマった。
3. CのコードからRubyのコードの呼び出し方がよくわからなかった。 `mrbc_funcall(struct VM *vm, const char *name, mrbc_value *v, int argc);` がそれっぽかったが、結局自分のところではうまく動かなかった。


2に関しては[githubのイシュー](https://github.com/mrubyc/mrubyc/issues/71)に上げておいた。自分で解決してプルリク投げられればいいんだけど、ちょっとどうしていいのかわからなかった。
この問題に対しては、一旦変数に `myself = self` のような形でとっておいて、ブロック内では変数（ `myself` ）の方を使うような書き方にしたらとりあえず意図した動きになった。

3に関しては、MQTTでサブスクライブしてるデータを受信した際に一旦Cのコールバックで受け取ってそこからRubyのブロックなどに投げたかったんだけどうまくいかなかった。
ただ、CからRubyコードのインスタンス変数には値を代入できたので、インスタンス変数を使って受け渡しすることにした。リアルタイム性は落ちるけど、サブスクライブしたデータで割り込まれるのも予測できない部分があって怖いので、Rubyコード側からインスタンス変数を確認しにいく形の方がいいと思いそうしている。

## 感想とか

やはり使い慣れているRubyのシンタックスで書けるのは楽でいいです。設計も慣れた感覚で行える。
それと、mruby/c特有の機能であるマルチタスクが、IoT特有の、「I/Oなめつつサーバーとも通信する」という使い方にマッチしていると思った。おそらくマルチタスク使うとリアルタイム性は低下するんだろうけど、そもそもそういうところではmruby/c使うことないだろうから問題にはならないだろう。
機能面だけでなく、マルチタスクを意識した設計にすることによって、サーバーとの通信とI/O通信のコードを明確に分けることができるから全体にすっきりとした構成にできた。

あとは、わからないことがあってもmruby/cのコードが小さいのでコード見てある程度どうすればいいか自分で判断できた。（とはいえ、スコープがどう実装されてるのかは自分のゼロに等しいC力ではさっぱりわからんかった）

現在はmrubycで組んだコードをWioLTEで動かして（結局WioLTEも購入した）継続して稼働させてみてるけど、今のところクラッシュなどは起こっていない。しばらくは継続して稼働させてみて、問題なさそうなら社内プロジェクトに使うことを提案してみようと思う。