Raspberry pi 2 で ElixirなLチカを

今回はちょっと目先を変えてRaspberry Pi 2のハードウェア制御をElixir/Erlang OTPでやってみます。実は今までRaspberry Pi 2、もっぱらお手軽Linux機として使っていてLチカやったことないことに気づきました(笑)。

-----

## 下準備

#### Raspbian(Jessie)でElixirを走らせる

Raspbian(Jessie)で既にRaspberry Pi 2が動いていて、ビルドに必要なコンパイラなどがインストールされているものとします[^0]。

[^0]: ググるといくらでも例が出てきますのでここはさっくり略。

まずErlang/OTPとElixirをビルドします[^1]。
[DOWNLOAD OTP 18.2.1](http://www.erlang.org/download.html)から最新の18.2.1のソースをダウンロードしましょう。Elixirも1.2.1[^2]をビルドする予定なのでErlangは18.0以降が必須です。

[^1]: これがWheezyならcontribにElixirのビルド済バイナリがあるのですが(とはいえ1.0なので古いです)。http://tomohikoseven-andre-tomohikoseven.blogspot.jp/2015/07/elixirraspberrypielixir.html 参照。
[^2]: こないだ1.2.0が出たと思ったらもう1.2.1がリリースされています。

先に必要なライブラリなどをRaspbianにインストールしておきます。

```bash
$ sudo apt-get update
$ sudo apt-get install libncurses5-dev libssl-dev 
$ sudo apt-get install libwxgtk2.8-dev libwxgtk2.8-dbg 
$ sudo apt-get install xsltproc libxml2-utils
```

最低限OpenSSL library とlibncursesを入れておけばよいと思います。Xで使うことを想定してwxwidgets関連とドキュメント関連(使わないかなあ)でxsltproc及びxmlライブラリを入れています。fopはPDF出力が欲しい！というわけでなければjava7をインストールするので入れないほうがいいかと。

落としてきたotp_src_18.2.1.tar.gzを展開しできたディレクトリにcd。

```bash
$ tar xzf otp_src_18.2.1.tar.gz
$ cd otp_src_18.2.1 
```

以下、configureしてmakeします。詳しいやり方は展開したディレクトリのHOWTO/INSTALL.mdにあります。

```bash
$ export ERL_TOP=`pwd`   # ベースディレクトリの指定
$ export LANG=C    # Perlのバグよけ。Raspbian(Jessie)のPerlだと不要
$ ./configure
Ignoring the --cache-file argument since it can cause the system to be erroneously configured
Disabling caching
checking build system type... armv7l-unknown-linux-gnueabihf
checking host system type... armv7l-unknown-linux-gnueabihf
checking for gcc... gcc
...
```

ではビルドします。かなり時間がかかりますよ[^3]。

[^3]: X Windowなし、コンソール起動の状態でtimeで測ったらreal 67m54.622s user 63m9.200s sys 4m34.490s で1時間超え。X Windowありだとreal 97m22.034s user 91m43.120s sys 4m33.380sでした。 Raspi無印のXありだと5時間かそれ以上かかるでしょう。

```bash
$ make
 MAKE   depend
make[1]: Entering directory '/home/tamori/otp_src_18.2.1/erts/emulator'
 MAKE   generate
make[2]: Entering directory '/home/tamori/otp_src_18.2.1/erts/emulator'
...

```

インストールします。

```bash
$ sudo make install
 MAKE   emulator
make[1]: Entering directory '/home/tamori/otp_src_18.2.1/erts'
make[2]: Entering directory '/home/tamori/otp_src_18.2.1/erts/emulator'
 MAKE   opt
make[3]: Entering directory '/home/tamori/otp_src_18.2.1/erts/emulator'
...
```

無事ビルド及びインストールが成功したら試しにerlを起動してみましょう。

```bash
$ erl
Erlang/OTP 18 [erts-7.1] [source] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V7.1  (abort with ^G)
1>
```
が表示されればOK。次はElixirのビルドです。こちらはgitでソースを持ってきます。HEADは開発版なので…

```bash
$ git clone https://github.com/elixir-lang/elixir.git
Cloning into 'elixir'...
remote: Counting objects: 88364, done.
...
$ cd elixir
$ git checkout tags/v1.2.1 -b v1.2.1
...
Switched to a new branch 'v1.2.1'
$ make clean test
cd lib/elixir && "/home/tamori/elixir/rebar" clean
==> elixir (clean)
rm -rf ebin
rm -rf lib/*/ebin
...
$ sudo make install
==> elixir (compile)
==> elixir (install)
...
```

これも無事にビルド・インストールできたら試しにiexを立ち上げてみましょう。

```bash
$ iex
Erlang/OTP 18 [erts-7.2.1] [source] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.2.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>

```

お疲れ様でした。

## ElixirでRaspberry Piのハードウェアを制御する

まずいくつか探してみて
[こちら](http://www.zohaib.me/blinking-led-using-elixir-embedded-image-for-raspberry-pi/)と[こちら](https://github.com/fhunleth/elixir_ale)を参考になりそうだと考えて調べてみました。

まず前者ですがRaspberry Piのデバイスは例えば本体LEDならば`/sys/class/leds/led0/trigger`や`/sys/class/leds/led0/brightness`といった仮想ファイルに機能がマップされているのでそれを叩くやり方です。シンプルなんですがテキストのechoばっかり並んでもつまらなさそうなので後者の`Elixir/ALE`を使うことにします。

## Elixir/ALE

Elixir/ALEは[Erlang/ALE](https://github.com/esl/erlang-ale)をベースにしたハードウェア制御用のライブラリです。I/OピンなどがElixir(Erlang)のプロセスとして起動しそいつに向かってメッセージを投げる感じなので「Elixirぽい…」かな…。

LチカなのでGPIOとGNDに抵抗挟んでLEDを繋ぎます。


![DSC_6367_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/46294/5717762f-6fa0-4cf1-5310-7e3c3911800e.jpeg)

GPIO17(11番ピン 左列上から6番目) ==> 180Ω抵抗 ==> +LED LED- ==> GND(3番ピン 右列上から3番目)に繋ぎました。



ではお試し用のコードを書いて動かしてみましょう。

```bash
$ mix new ledtest1
* creating README.md
* creating .gitignore
* creating mix.exs
...
Run "mix help" for more commands.

$ cd ledtest1
```

mix.exsにElixir/ALEを使うための設定等を追加します。

```ex
defmodule Ledtest1.Mixfile do
  use Mix.Project

  def project do
    [app: :ledtest1,
     version: "0.0.1",
     elixir: "~> 1.2",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    [applications: [:logger],
     mod: {Ledtest1,[]}]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    [
      {:elixir_ale, "~> 0.4.1"}
    ]
  end
end

```

```bash
$ mix deps.get
Could not find Hex, which is needed to build dependency :elixir_ale  # 初回だけHexが見つからないので聞いてくる
Shall I install Hex? [Yn] # Yなのでリターン
...
```

あとは以下のように`lib/ledtest1.ex`を書きます。

```ex
defmodule Ledtest1 do
  require Logger

  def start(_type, _args) do
    {:ok, pid} = Gpio.start_link(17, :output)
    blink_forever(pid)
  end

  def blink_forever(pid) do
    Gpio.write(pid, 1)
    Logger.debug "Turn LED on"
    :timer.sleep 1000
    Gpio.write(pid, 0)
    Logger.debug "Turn LED off"
    :timer.sleep 1000
    blink_forever(pid)
  end

end
```

実行にはスーパーユーザー権限がいるので

```bash
$ sudo iex -S mix
```

でいいはずなんですが、先に

```bash
$ sudo mix hex.info
```

する必要がありました(sudoすると /root/.mix/の方にも環境を作ろうとするため)。うまくいくと

```bash
$ sudo iex -S mix
Erlang/OTP 18 [erts-7.2.1] [source] [smp:4:4] [async-threads:10] [kernel-poll:false]

==> elixir_ale
cc -c -I/usr/local/lib/erlang/lib/erl_interface-3.8.1/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/ale_main.o src/ale_main.c
cc -c -I/usr/local/lib/erlang/lib/erl_interface-3.8.1/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/gpio_port.o src/gpio_port.c
...
Compiled lib/ledtest1.ex

22:56:32.834 [debug] Turn LED on

22:56:33.835 [debug] Turn LED off

22:56:34.837 [debug] Turn LED on

22:56:35.840 [debug] Turn LED off
...
```
とLチカが始まります。

もっともPythonで書けば

```bash
$ sudo apt-get install python-rpi.gpio
```

で必要なライブラリをインストールした後

```py
#! /usr/bin/env python

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
GPIO.output(17, GPIO.HIGH)

while True:
    GPIO.output(17, GPIO.HIGH)
    time.sleep(1)
    GPIO.output(17, GPIO.LOW)
    time.sleep(1)
```

でできちゃうんで、**Elixir/Erlangならではの使い道やメリット**はこれから考えないと。