bullseyeベースのRaspberry Pi OSからWiring Piが無くなった、その対処方法(raspi-gpio コマンド)

:::note warn
**《2024年6月 更新》**
Raspberry Pi 5 では `pinctrl` コマンドを使う必要があります。
詳しくは、[Raspberry Pi 5 におけるGPIO操作は `pinctrl` を使う (raspi-gpio後継コマンド)](https://qiita.com/ma2shita/items/d745a8f89c673fd74a5e) をご覧ください。
:::

## 論よりコード

`raspi-gpio` コマンドを使いましょう。

```bash
$ raspi-gpio get
BANK0 (GPIO 0 to 27):
GPIO 0: level=1 fsel=0 func=INPUT
GPIO 1: level=1 fsel=0 func=INPUT
《省略》

$ raspi-gpio get 6 | awk -v RS=" " -F "=" -v k="level" '$1==k {print $2}'
1
```

## Wiring Pi は deprecated (非推奨) です

Raspberry Pi の GPIO 操作でお世話になる「[Wiring Pi](http://wiringpi.com/)」は、Bullseye ベースの Rasbpberry Pi OS のリポジトリから無くなり、インストールが失敗します。

```console
$ sudo apt install wiringpi
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package wiringpi
```

Wiring Pi は[2019年に開発停止を表明](http://wiringpi.com/wiringpi-deprecated/)しており、それがいよいよ反映された形です。
ちなみに Buster ベースの Raspberry Pi OS であれば `apt install wiringpi` でインストールできますが、**今後は `raspi-gpio` に一本化したほうが良さそうです。**

ちなみに、Bullseye ベース、Buster ベースの Rasbpberry Pi OS については [「Raspberry Pi OS」、2種類が提供へ--Buster版とBullseye版](https://japan.zdnet.com/article/35180661/) や、 [Bullseye – the new version of Raspberry Pi OS](https://www.raspberrypi.com/news/raspberry-pi-os-debian-bullseye/) をご覧ください。


## raspi-gpio コマンド

Wiring Pi が提供する `gpio` コマンドの互換プロダクトは無いようです。ただ、コマンドラインツール自体は `raspi-gpio` が存在しています。
`raspi-gpio` は Bullseye ベース、Buster ベース、両方の Rapsberry Pi に標準インストール済みです。

以下 `raspi-gpio` の help です。

```console
$ raspi-gpio help

WARNING! raspi-gpio set writes directly to the GPIO control registers
ignoring whatever else may be using them (such as Linux drivers) -
it is designed as a debug tool, only use it if you know what you
are doing and at your own risk!

The raspi-gpio tool is designed to help hack / debug BCM283x GPIO.
Running raspi-gpio with the help argument prints this help.
raspi-gpio can get and print the state of a GPIO (or all GPIOs)
and can be used to set the function, pulls and value of a GPIO.
raspi-gpio must be run as root.
Use:
  raspi-gpio get [GPIO]
OR
  raspi-gpio set <GPIO> [options]
OR
  raspi-gpio funcs [GPIO]
OR
  raspi-gpio raw

GPIO is a comma-separated list of pin numbers or ranges (without spaces),
e.g. 4 or 18-21 or 7,9-11
Note that omitting [GPIO] from raspi-gpio get prints all GPIOs.
raspi-gpio funcs will dump all the possible GPIO alt funcions in CSV format
or if [GPIO] is specified the alternate funcs just for that specific GPIO.
Valid [options] for raspi-gpio set are:
  ip      set GPIO as input
  op      set GPIO as output
  a0-a5   set GPIO to alternate function alt0-alt5
  pu      set GPIO in-pad pull up
  pd      set GPIO pin-pad pull down
  pn      set GPIO pull none (no pull)
  dh      set GPIO to drive to high (1) level (only valid if set to be an output)
  dl      set GPIO to drive low (0) level (only valid if set to be an output)
Examples:
  raspi-gpio get              Prints state of all GPIOs one per line
  raspi-gpio get 20           Prints state of GPIO20
  raspi-gpio get 20,21        Prints state of GPIO20 and GPIO21
  raspi-gpio set 20 a5        Set GPIO20 to ALT5 function (GPCLK0)
  raspi-gpio set 20 pu        Enable GPIO20 ~50k in-pad pull up
  raspi-gpio set 20 pd        Enable GPIO20 ~50k in-pad pull down
  raspi-gpio set 20 op        Set GPIO20 to be an output
  raspi-gpio set 20 dl        Set GPIO20 to output low/zero (must already be set as an output)
  raspi-gpio set 20 ip pd     Set GPIO20 to input with pull down
  raspi-gpio set 35 a0 pu     Set GPIO35 to ALT0 function (SPI_CE1_N) with pull up
  raspi-gpio set 20 op pn dh  Set GPIO20 to ouput with no pull and driving high
```

### ピンの指定方法

`raspi-gpio` のピンの指定方法は BMC ピン番号です。
`gpio` コマンド使えていた Wiring Pi 独自ピン番号は使えません。`gpio -g ...` で指定していたピン番号であれば、そのまま `raspi-gpio` の引数に使えます。

Wiring Pi 独自ピンと BMC ピンの対比は [KSY さんのこのページ](https://raspberry-pi.ksyic.com/bypass/files/GPIO.svgz#PinN)が大変便利です。

### コマンド対応表

| | Wriring Pi | raspi-gpio |
|-|------------|------------|
| GPIO 全てを読む | `gpio readall` | `raspi-gpio get` |
| BMC ピン 6 番を読む | `gpio -g read 6` | `raspi-gpio get 6` | 

### 出力フォーマット比較

`gpio` と `raspi-gpio` は、出力フォーマットにかなりの差があります。

#### `gpio readall` と `raspi-gpio get`

```console
$ gpio readall
 +-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 0 | IN   | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | IN   | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+
```

```console
$ raspi-gpio get
BANK0 (GPIO 0 to 27):
GPIO 0: level=1 fsel=0 func=INPUT
GPIO 1: level=1 fsel=0 func=INPUT
GPIO 2: level=1 fsel=0 func=INPUT
GPIO 3: level=1 fsel=0 func=INPUT
GPIO 4: level=1 fsel=0 func=INPUT
GPIO 5: level=1 fsel=0 func=INPUT
GPIO 6: level=1 fsel=0 func=INPUT
GPIO 7: level=1 fsel=0 func=INPUT
GPIO 8: level=1 fsel=0 func=INPUT
GPIO 9: level=0 fsel=0 func=INPUT
GPIO 10: level=0 fsel=0 func=INPUT
GPIO 11: level=0 fsel=0 func=INPUT
GPIO 12: level=0 fsel=0 func=INPUT
GPIO 13: level=0 fsel=0 func=INPUT
GPIO 14: level=0 fsel=0 func=INPUT
GPIO 15: level=1 fsel=0 func=INPUT
GPIO 16: level=0 fsel=0 func=INPUT
GPIO 17: level=0 fsel=0 func=INPUT
GPIO 18: level=0 fsel=0 func=INPUT
GPIO 19: level=0 fsel=0 func=INPUT
GPIO 20: level=0 fsel=0 func=INPUT
GPIO 21: level=0 fsel=0 func=INPUT
GPIO 22: level=0 fsel=0 func=INPUT
GPIO 23: level=0 fsel=0 func=INPUT
GPIO 24: level=0 fsel=0 func=INPUT
GPIO 25: level=0 fsel=0 func=INPUT
GPIO 26: level=0 fsel=0 func=INPUT
GPIO 27: level=0 fsel=0 func=INPUT
BANK1 (GPIO 28 to 45):
GPIO 28: level=1 fsel=0 func=INPUT
GPIO 29: level=0 fsel=1 func=OUTPUT
GPIO 30: level=0 fsel=7 alt=3 func=CTS0
GPIO 31: level=0 fsel=7 alt=3 func=RTS0
GPIO 32: level=1 fsel=7 alt=3 func=TXD0
GPIO 33: level=1 fsel=7 alt=3 func=RXD0
GPIO 34: level=0 fsel=7 alt=3 func=SD1_CLK
GPIO 35: level=1 fsel=7 alt=3 func=SD1_CMD
GPIO 36: level=1 fsel=7 alt=3 func=SD1_DAT0
GPIO 37: level=1 fsel=7 alt=3 func=SD1_DAT1
GPIO 38: level=1 fsel=7 alt=3 func=SD1_DAT2
GPIO 39: level=1 fsel=7 alt=3 func=SD1_DAT3
GPIO 40: level=0 fsel=4 alt=0 func=PWM0
GPIO 41: level=0 fsel=4 alt=0 func=PWM1
GPIO 42: level=0 fsel=4 alt=0 func=GPCLK1
GPIO 43: level=0 fsel=4 alt=0 func=GPCLK2
GPIO 44: level=1 fsel=0 func=INPUT
GPIO 45: level=1 fsel=0 func=INPUT
BANK2 (GPIO 46 to 53):
GPIO 46: level=1 fsel=0 func=INPUT
GPIO 47: level=1 fsel=1 func=OUTPUT
GPIO 48: level=0 fsel=4 alt=0 func=SD0_CLK
GPIO 49: level=1 fsel=4 alt=0 func=SD0_CMD
GPIO 50: level=1 fsel=4 alt=0 func=SD0_DAT0
GPIO 51: level=1 fsel=4 alt=0 func=SD0_DAT1
GPIO 52: level=1 fsel=4 alt=0 func=SD0_DAT2
GPIO 53: level=1 fsel=4 alt=0 func=SD0_DAT3
```

※出力結果には "GPIO: xx" って出てますけど、これは BMC のピン番号です。そのため、この出力で実質使えるのは GPIO 0 ~ 27 ということになります。

#### `gpio -g read 6` と `raspi-gpio get 6`

```bash
$ gpio -g read 6
1
# OR => 0
```

```bash
$ raspi-gpio get 6
GPIO 6: level=0 fsel=0 func=INPUT
# Or => GPIO 6: level=1 fsel=0 func=INPUT
```
`level= ` の値が `gpio read` で返されていた時の値となります。~~使いづらい...~~

#### `raspi-gpio get` の出力を `gpio read` 互換にする

GNU awk の力を借りると、`gpio read` の出力と互換が取れます。

```bash
$ gpio -g read 6
1
$ raspi-gpio get 6 | awk -v RS=" " -F "=" -v k="level" '$1==k {print $2}'
1
```

- `-v RS=" "`: key-value 間の区切り文字 (今回は空白)
- `-F "="`: key と value の区切り文字 (今回は =)
- `-v k="level"`: 探したい key 名 (今回は level)
- `$1==k`: 読み込んだkeyが `-v k=` で指定した変数と一致したか？
- `{print $2}`: \$2=value を表示 ($1はkey)

`-F` `-v RS=` をうまく使えば `key1=value1, key2=value2, key3=value3` みたいな文字列から値だけ切り出すのも一発です。覚えておいて損は無いかと。

```bash
$ echo -n 'key1=value1, key2=value2, key3=value3' | awk -v RS=", " -F "=" -v k="key1" '$1==k {print $2}'
value1
$ echo -n 'key1=value1, key2=value2, key3=value3' | awk -v RS=", " -F "=" -v k="key3" '$1==k {print $2}'
value3
```

### ところで、今後も大丈夫なの？

まあ Raspberry Pi のなかのひと(Serge-san)がメンテしてるので、長いこと使えるんじゃないでしょうか。しらんけど。

```bash
$ apt-cache show raspi-gpio | grep Maintainer
Maintainer: Serge Schneider <serge@raspberrypi.org>
```

## あとがき

よいお年を！

### 参考資料

- [「Raspberry Pi OS」、2種類が提供へ--Buster版とBullseye版](https://japan.zdnet.com/article/35180661/)
- [Bullseye – the new version of Raspberry Pi OS](https://www.raspberrypi.com/news/raspberry-pi-os-debian-bullseye/)
- [wiringPi – deprecated…](http://wiringpi.com/wiringpi-deprecated/)
- [wiringpi is missing from bullseye. how do i install it? - Raspberry Pi Stack Exchange](https://raspberrypi.stackexchange.com/questions/133251/wiringpi-is-missing-from-bullseye-how-do-i-install-it)

EoT