Raspberry Pi ZeroにUbuntu仕立てのYocto焼き ～gccにlibusbを添えて

# やりたいこと
Raspberry Pi Zero WHでYocto Projectを動かします。
Wi-Fiが使えて、gccが使えて、libusbでUSBの制御ができるところまで。
色々な情報を参考にさせていただいたのですが、あちこち困りました。
ようやく動くようになったのでやったことをまとめておきます。

図で書くとこんな感じ。
![linux_Yocto概要（一般）.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449620/55092d6b-abd2-2053-5c1f-d72bd0b317c9.png)

# 環境
だいたい上の図にある通り。

ホストPC側は

* Windows10
* Virtual Box 6.1
* Ubuntu 20.04.1

ターゲット側は

* Raspberry Pi Zero WH

で、Yocto Projecto は 3.1 (Dunfell) を使っていきます。
Dunfell を使うのは Ubuntu 20.04.1 のリリース時期に近いためです。

Ubuntuには128GBほど仮想HDDを割り当てています。64GBでも以降に書いてあることはぎりぎり行けると思います。32GBではDiskFullでビルド失敗しました。ご注意ください。

# 参考資料
https://blog.web.nifty.com/engineer/1040
こちらを参考にさせていただきました。
ほとんどこちらと同じ流れでやってます。
バージョン違いや入れたいパッケージの違いによりところどころ異なっています。

# Yocto環境を作る
Windows10 PC に Virtual Box 6.1 が入ってて Ubuntu 20.04.1 が動いてる前提で行きます。
ここまでの環境については詳しく説明しません。

## Yocto環境に必要なパッケージのインストール

[こちらの記事](http://blog.web.nifty.com/engineer/810)を参考にインストール

```shell
$ sudo apt-get install sed wget subversion git-core coreutils unzip texi2html texinfo libsdl1.2-dev docbook-utils fop gawk python-pysqlite2 diffstat make gcc build-essential xsltproc g++ desktop-file-utils chrpath libgl1-mesa-dev libglu1-mesa-dev autoconf automake groff libtool xterm libxml-parser-perl
```

なんかこれだとちょっと足りなかったような気がする。
思い出したら追記します。

## Pokyを持ってきてビルド環境の準備

ホームディレクトリの yocto/rpi0 で作業する感じです。この辺はお好みで。
Pokyとmeta-raspberrypiのdunfellブランチを持ってきます。

```shell
$ mkdir yocto
$ cd yocto
$ mkdir rpi0
$ cd rpi0
$ git clone git://git.yoctoproject.org/poky.git -b dunfell
$ cd poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi -b dunfell
$ source oe-init-build-env ../build
```

コマンド成功すれば buildディレクトリが作られて、その中に移動します。

## レイヤーの編集
meta-openembedded と meta-linaro を持ってきてます。ブランチは上に合わせて dunfell で。
gcc を linaro にしようかと思って meta-linaro をもって来たんですが、実際は使いませんでした。たぶん、なくてもこれ以降うまくいくと思います。が、meta-linaro なしでの確認をしていないので、一応ここでは残しておきます。

```shell
$ cd ../poky
$ git clone git://git.openembedded.org/meta-openembedded -b dunfell
$ git clone git://git.linaro.org/openembedded/meta-linaro.git -b dunfell
$ cd ../build
$ nano conf/bblayers.conf
```

Raspberry Pi でよく使うので nano派です。
bblayers.conf に meta-openembedded系と meta-raspberrypiを追加します。

```shell:bblayers.conf
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
  /home/mine/yocto/rpi0/poky/meta \
  /home/mine/yocto/rpi0/poky/meta-poky \
  /home/mine/yocto/rpi0/poky/meta-yocto-bsp \
  /home/mine/yocto/rpi0/poky/meta-openembedded/meta-oe \
  /home/mine/yocto/rpi0/poky/meta-openembedded/meta-networking \
  /home/mine/yocto/rpi0/poky/meta-openembedded/meta-perl \
  /home/mine/yocto/rpi0/poky/meta-openembedded/meta-python \
  /home/mine/yocto/rpi0/poky/meta-raspberrypi \
  "
```

## local.conf 編集してパッケージとか追加する
local.conf の編集

```shell
$ nano conf/local.conf
```

[参考とさせていただいたところ](https://blog.web.nifty.com/engineer/1040)をほとんどそのままコピペ。
違うところは下に説明書きます。
local.conf の一番上にこれらを追加して、他はデフォルトのままにしてあります。
```DL_DIR ?= "${TOPDIR}/downloads"``` の行はコメント外して有効にしました。

```shell:local.conf
# machine setting
MACHINE = "raspberrypi0-wifi"

DISTRO_FEATURES_append = " bluez5"
COMBINED_FEATURES_append = " alsa ext2 usb-gadget usbhost wifi bluetooth"

# images
IMAGE_INSTALL_append = " linux-firmware-bcm43430 connman connman-client pulseaudio pulseaudio-server usbutils sudo "
IMAGE_INSTALL_append = " libusb-compat libusb-compat-dev libusb1 nano net-tools bash libjpeg-turbo libjpeg-turbo-dev tiff "
IMAGE_FEATURES_append = " ssh-server-dropbear"
EXTRA_IMAGE_FEATURES_append = " tools-sdk "
 
# use systemd
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""
IMX_DEFAULT_DISTRO_FEATURES_append = " systemd"
 
# host setup
hostname_pn-base-files = "yoctopi"
INHERIT_append = " extrausers"
EXTRA_USERS_PARAMS = "useradd -P raspberry pi;usermod -P raspberry root;"
```

* `MACHINE` 今回は Raspberry Pi Zero WH で確認したので `raspberrypi0-wifi` を指定しました。`raspberrypi`, `raspberrypi0`, `raspberrypi0-wifi`, `raspberrypi2`, `raspberrypi3`, `raspberrypi3-64`, `raspberrypi-cm`, `raspberrypi-cm3` 色々定義があるみたいです（未確認）。
* `COMBINED_FEATURES_append` の `usbgadget` は、そのままだとビルドエラーが出ました。どの資料を見てもこの書き方で正しい気がするのですが、海外のサイトで稀に `usb-gadget` と書いてあるところがあり、藁にもすがる思いで書いてみたらエラーが出なくなりました。正しいのかどうか分かりません。名前変わったんでしょうか？
* `IMAGE_INSTALL_append` の2行目でlibusb関連、nano（nano派なので）、net-tools、bashを追加。net-toolsは効果あったのかよく分かりません。bashはとりあえず追加してみましたが使ってません。
* `EXTRA_IMAGE_FEATURES_append` [マニュアル](https://www.yoctoproject.org/docs/1.8/ref-manual/ref-manual.html#var-EXTRA_IMAGE_FEATURES)を見たところ、ここに `tools-sdk` と書いておくと gccが追加されるっぽいです。動いてるのでこれでいいことにします。
* `EXTRA_USERS_PARAMS` 特にネットにつなげる気もないのでセキュリティは最低限。rootのパスワードも "raspberry" にしちゃってます。もしコピペしようと思った方がいらっしゃたらお気をつけて。

# いよいよビルド
## ビルドします
build ディレクトリにて bitbake コマンドでビルドかけます。
あちこちのサイトで `$ bitbake rpi-hwup-image` でビルドするよう書いてますが、やってみたら「rpi-hwup-image は非推奨です」みたいな警告が出ました。新しいやつでは `core-image-base` を使うみたいです。

```shell
$ bitbake core-image-base
```

私の環境ではこのまま 8時間くらい待ちます。。
成功すると、`build/tmp/deploy/images/raspberrypi0-wifi/` にファイルができています。
古い環境だと .rpi-sdimg という拡張子のファイルがあるようですが、いつの頃からかデフォルトでは作られなくなったようです（設定次第で作れるらしい）。

というわけで、使うのは、`core-image-base-raspberrypi0-wifi-YYYYMMDDhhmmss.rootfs.wic.bz2` みたいな名前のファイル。YYYYMMDDhhmmssにはビルド開始時刻が入るのか？ ビルド終了時刻が入るのか？（あまり気にしてない）

## SDカードに書き込む
Ubuntuからddコマンドで書き込みます。

Windows10のPCにUSBカードリーダーを差し込んで、VirtualBoxのメニューから [デバイス]→[USB]→[カードリーダーのデバイスっぽい名前のやつ] を選択して、Ubuntuから見えるようにしておきます。「ディスク」アプリで確認したところ、私の環境では /dev/sdb に割当たってました。このへんは各環境で違うと思いますが。



あと、必要か不要か分かりませんが、一応ということで、毎回SDカードのパーティションを全部初期化して、ext4 でフォーマットして書き込んでます。書き込みにも数分かかるのでやり直すのも面倒だから失敗防止のためです。

```shell
$ cp tmp/deploy/images/raspberrypi0-wifi/core-image-base-raspberrypi0-wifi-YYYYMMDDhhmmss.rootfs.wic.bz2 [どこか適当なディレクトリ]
$ cd [どこか適当なディレクトリ]
$ bunzip2 core-image-base-raspberrypi0-wifi-YYYYMMDDhhmmss.rootfs.wic.bz2
$ sudo dd if=core-image-base-raspberrypi0-wifi-YYYYMMDDhhmmss.rootfs.wic of=/dev/sdb bs=1M
```

変なことが起きると怖いので一応どこか適当なディレクトリにコピーして作業してます。
.wic.bz2 ファイルは bunzip2 で展開して、そのまま dd コマンドでSDカードに書き込んでいいようです。

# ようやく動かすよ

ビルドしてできたYoctoを書き込んだSDカードをRaspberry Pi Zero WHに差し込んでHDMI、キーボードをつなげて電源ON。

Raspiユーザーにはお馴染みの虹画面からの起動。で、起動メッセージがじゃんじゃん出てきて、、

```shell
yoctopi login:
```

ってメッセージが出てきたら成功です。piユーザか rootでログインして使い放題です。

## とりあえず gcc を使ってみる

こんな感じですかね？

```shell
$ nano hoge.c
```

```c:hoge.c
#include <stdio.h>

int main()
{
    printf("hogehoge!\n");
    return 0;
}
```

```shell
$ gcc hoge.c -o hoge
$ ./hoge
hogehoge!
```

"Hello world!" とか書いてあげない。
あ、デフォルト状態では英字キーボード配列でした。日本語キーボードつなげてると記号打ち込むのに惑わされます。

## libusb のテスト
```shell
$ nano testUsb.c
```
```c:testUsb.c
#include <stdio.h>
#include <usb.h>

int main()
{
    usb_init();
    printf("usb_init(): OK\n");
    return 0;
}
```
```shell
$ gcc testUsb.c -o testUsb -lusb
$ ./testUsb
usb_init(): OK
```

OKも何もあったもんじゃないですが、-lusb を付けずにビルドすると usb_init() がないってリンクエラーが出るので libusb もそれなりに動いてるっぽいです。

## Wi-Fi につなげてみる
local.conf の編集で connman を入れているので、これで Wi-Fi につなげてみます。
こんな感じ。

```shell
$ connmanctl
connmanctl> technologies
connmanctl> enable wifi
connmanctl> scan wifi
connmanctl> services
[スキャンしたアクセスポイントがたくさん出てくる]
connmanctl> agent on
connmanctl> connect [スキャンしたアクセスポイントのひとつを入力]
  Passphrase? [パスフレーズを入力]
connmanctl> quit
```

オープンなアクセスポイントにつなぐなら `agent on` とかいらないようです。
これでアクセスポイントにつながれば、LAN上のPCからSSHとかもつながります。
一度つなげたアクセスポイントはどこかに設定が保存されてるようで、次回からは勝手につながってました。

# まとめ
とりあえず、Raspberry Pi Zero WH 上で Yocto Project 3.1 (Dunnfell) が動きました。
Wi-Fi つながってて、C言語が動くので色々できそうですが、実際のところ何に使うかは未定です。

あと、ここで紹介した設定だと、PerlとPythonが動く予定だったのですが、Perlは動いてて、Pythonは動いていませんでした。何が悪いのかは調査中ですが、Pythonを動かす方法をご存じの方がいらっしゃいましたら教えてください。