はじめに
直近の記事 はじめてね AtomVM(4) ESP32でLチカ v0.7.0-alpha.1 版 でアルファ版の AtomVM をインストールしてみました。
普段なら v0.7.1 になるぐらいじゃないと手を出さないのですが、今回は新しい機能を試してみたくて珍しく手を出しました。
気になる新しい機能
Releases v0.7.0-alpha.0の Elixir improvements には Native GenServer and Supervisor support とあるじゃありませんか。これこれ。Elixir で楽しくプロセスごっこするにはこれが必要です。ということで今回は AtomVM での GenServer を試してみます。
なお AtomVM v0.7 系の新機能の詳細については Releases v0.7.0-alpha.0 と Releases v0.7.0-alpha.1 の Added 欄に書いてあります。
GenServer を用いたLチカ
デフォルトのサンプルプログラムでのLチカ Blinky は、単純なループで構成されています。これをタイマーをしかけて自分自身にメッセージを送る形のプログラムで構成してみます。
defmodule Blinky do
@compile {:no_warn_undefined, [GPIO, :atomvm]}
@gpio_pin 2 # for GPIO of ESP32
use GenServer
def start() do
IO.puts("LED Blink starts")
GenServer.start_link(__MODULE__, {@gpio_pin, :low})
Process.sleep(:infinity)
end
def init({pin, level}) do
GPIO.set_pin_mode(pin, :output)
GPIO.digital_write(pin, level)
set_interval(1000)
IO.puts("GenServer init finished")
{:ok, {pin, level}}
end
def handle_info(:toggle, {pin, :low}) do
{:noreply, {pin, :high, 100}, {:continue, :toggle_common}}
end
def handle_info(:toggle, {pin, :high}) do
{:noreply, {pin, :low, 700}, {:continue, :toggle_common}}
end
def handle_continue(:toggle_common, {pin, level, interval}) do
GPIO.digital_write(pin, level)
IO.puts("led level: #{level}")
set_interval(interval)
{:noreply, {pin, level}}
end
def set_interval(ms), do: Process.send_after(self(), :toggle, ms)
end
GenServer の状態の型が途中で変わる(handle_continue に渡すところだけ3要素のタプルで、ほかは2要素のタプル)という、ちょっと変則的な模範的でなさそうなプログラムを書いちゃいました。ま、いごいてます。
うまく行ってないこと
Lチカを出来るには出来ましたが、いくつかうまくいかなかったことや不便なことがあります。これ、書き方や使い方が悪いのか、そもそも出来ないのかがわからないものもあります。
不要な Warning メッセージが出る
上のプログラムで mix compile し、その後 mix atomvm.packbeam すると以下の Warning が出ます。
Warning: following modules or functions are not available on AtomVM:
* Elixir.GenServer:start_link/2
* Elixir.Supervisor:child_spec/2
* erlang:phash2/2
最初の Elixir.GenServer:start_link/2 は Elixir.GenServer:start_link/3 の第3引数を省略した形でプログラム中で使っています。実のところ使えているので、この Warning はよろしくないです。
あと Elixir.Supervisor:child_spec/2 と erlang:phash2/2 は明示的に使ってなくて、どっかで勝手に呼ばれてるのかなと思ったりもしますが、心当たりがないので困ります。
Logger はいごかない
require Logger を使ってもコンパイルはできます。が Logger.info/1 とかの関数を使うとクラッシュしちゃいます。
API Reference Documentation / Module logger には記載があるのですが、コンソールに Warning: module Elixir.Logger cannot be resolved. と出てくるので Erlang logger でOKでも Elixir Logger にはまだ対応してないということのようです。
まとめ
AtomVM v0.7.0-a.1 で GenServer が使えるのを確認しました。まだちょっとわからないこともありますので続けて調べていきたいです。
あとSupervisor や Binary のパターンマッチなど、IoT で使ういろいろな機能が実装されてきていますので、それも試していきたいと思います。