Raspberry Pi 3 model B で PS3 コントローラー (Dualshock3) を Bluetooth で使う

# はじめに
すんなり行かなかったので、備忘のためにまとめます。誰かの助けになれば幸いです。

# 使ったもの
- Raspberry Pi 3 Model B
    - Raspberry Pi OS
        - Distributor ID:	Raspbian
        - Description:	Raspbian GNU/Linux 10 (buster)
        - Release:	10
        - Codename:	buster
- PS3 コントローラ (Dualshock3)
    - ハードオフで 800円 くらい
    - 似たもので sixaxis というのがあるが、Dualshock3 の振動ないバージョンだと思う

# 事前準備
もろもろ apt-get でインストールしていくので予め update しておく

```
$ sudo apt-get update && sudo apt-get upgrade
```

# sixpair のインストール
sixpair はコマンドラインペアリングツールとのこと。通常の Bluetooth デバイスは、デバイスとホストとの間のリンクを一度確立すると、ホストはこの以前に記憶された情報を用いて接続を開始することができますが、今回のケース (PS3 コントローラー) の場合、実際にはプロセスを開始するのはコントローラー側なので、事前にセットアップを行う必要があります。PS3 コントローラと接続する Bluetooth ホスト（今回でいうとラズパイ）を、予め PS3 コントローラーに指示する必要があるらしい。

まず `libusb-dev` をインストールする。たぶん後述する sixpair のコンパイルに必要なんだと思う。
>libusb-dev は、ユーザ空間の USB プログラミングライブラリ。Linux カーネルの内部に関する知識を必要とせずに、USB アプリケーションをプログラミングするためのライブラリ


```
$ sudo apt-get install libusb-dev
```
続いて、ペアリング用ツールである `sixpair` をインストールする。
下記のようにしてソースコードをダウンロードし、コンパイルする。

```
$ wget http://www.pabr.org/sixlinux/sixpair.c
$ gcc -o sixpair sixpair.c -lusb
```
ここで、PS3 コントローラーをラズパイに USB で有線接続し、sixpair を実行する。

```
$ sudo ./sixpair 
Current Bluetooth master: aa:aa:aa:aa:aa:aa　←PS3 コントローラがホストだと思っている相手のアドレス
Setting master bd_addr to bb:bb:bb:bb:bb:bb　←このコマンドを実行しているラズパイのアドレス
```
上記のように、アドレスが異なる場合、再度同じコマンド実行

```
$ sudo ./sixpair 
Current Bluetooth master: bb:bb:bb:bb:bb:bb　←PS3 コントローラがホストだと思っている相手がラズパイになった
Setting master bd_addr to bb:bb:bb:bb:bb:bb　←このコマンドを実行しているラズパイのアドレス
```
これで、有線ペアリングは完了。

#QtSixA のインストール
次に [qtsixa](https://ja.osdn.net/projects/sfnet_qtsixa/) をビルド、インストールする。
>!QtSixA は、Sixaxis ジョイスティック マネージャーです。PS3 ハードウェア (Sixaxis/!DualShock3 とキーパッド) をLinux 互換マシンに接続できます。現在 Sixaxis ボタン、軸、加速度センサーおよび Led をサポートします。

QtSixA 自体は GUI ツールですが、今回はこれに含まれている `sixad` というデーモンを使うことになります。
いくつかライブラリが不足するので（あとからわかるのだが）、先にインストールします。

```
--- pyuic4 ---
$ sudo apt-get install -y python-qt4 pyqt4-dev-tools qt4-designer
--- jack.h ---
$ sudo apt-get install -y libjack-jackd2-dev
--- bluetooth.h ---
$ sudo apt-get install -y libbluetooth-dev
--- 念の為これも ---
$ sudo apt-get install -y bluez bluez-hcidump joystick
```
次に、`qtsixa` のソースを github からクローンする (wget でもいいかもしれないが）

```
$ git clone https://github.com/falkTX/qtsixa.git
$ cd qtsixa
$ make
$ sudo make install
...中略...
Installation is Complete!
```
注意！　ここで、`python` コマンドが python3 系だと make がうまく通らないようなので、エイリアス修正等で python2 系にしておく。

続いて無線ペアリングに移るが、その前に、bluetooth が起動していなければいけないので、念の為確認する。

```bash
$ hciconfig
hci0:	Type: Primary  Bus: UART
	BD Address: B8:27:EB:66:17:67  ACL MTU: 1021:8  SCO MTU: 64:1
	DOWN 
	RX bytes:654 acl:0 sco:0 events:33 errors:0
	TX bytes:419 acl:0 sco:0 commands:33 errors:0
```
上記のように、`DOWN` になっている場合、下記のようにして起動する。
**注意！　`piscan` をつけるのがポイント。こうすることで `UP RUNNING PSCAN ISCAN` 状態になる。`UP RUNNING PSCAN ISCAN` なっていないと、無線でペアリングできない（ここでずいぶんハマった）**

```bash
$ sudo hciconfig hci0 up piscan
$ hciconfig
hci0:	Type: Primary  Bus: UART
	BD Address: B8:27:EB:66:17:67  ACL MTU: 1021:8  SCO MTU: 64:1
	UP RUNNING PSCAN ISCAN 
	RX bytes:1315 acl:0 sco:0 events:67 errors:0
	TX bytes:843 acl:0 sco:0 commands:67 errors:0
```

つづいて、無線でペアリングする。USBケーブルを抜いて、PS3 コントローラを無線状態にし、下記コマンドを実行。

```bash
$ sudo sixad -start &
sixad-bin[5850]: started
sixad-bin[5850]: sixad started, press the PS button now
```

上記のようになったら PS3 コントローラーの PS ボタンを押す。以下のメッセージが出て、PS3 コントローラーがブルブルと震えればペアリング成功。

```
sixad-sixaxis[6027]: Connected 'PLAYSTATION(R)3 Controller (aa:aa:aa:aa:aa:aa)' [Battery 04]
```
sixad をとめたい時は

```bash
$ /usr/bin/sixad --stop
```

これで PS3 コントローラの操作をラズパイが解釈できるようになったので、これを使ってラズパイラジコンを作ります！（つづく）

#2 回目以降のラズパイ起動時の設定

## 起動時に発見可能にする
PSCAN, ISCAN フラグをタイムアウトで落とさないようにするため、main.conf に下記を追記する。
※セキュリティの観点で理想的ではないので、自己責任で

```bash
$ vi /etc/bluetooth/main.conf
```
```main.conf
[General]
DiscoverableTimeout=0
Discoverable=true
~中略~
[Policy]
AutoEnable=true
```

## rc.local に記述しラズパイ起動時に自動実行

bluetooth の起動、sixad の起動を、シェルスクリプトに記述し、rc.local で起動時に自動起動するようにする

```bash
$ sudo vi /etc/rc.local
```


```bash:rc.local
〜中略〜
sudo chmod 755 /usr/lib/bluetooth/bluetoothd
sudo systemctl start bluetooth
sudo sixad -start &

exit 0
```
※なぜか、bluetoothd の実行権限(x)がラズパイ再起動時に取れてしまう現象が時折発生するので、美しくはないが起動時に毎回 chmod するようにして暫定対処。
※当初、ラズパイで　rc.local が実行できなかった。調べると [ここ](https://peacejet.hatenablog.com/entry/2017/07/08/000907) にあるように、`raspi-config` で　Boot Options で Wait for Network at boot を はい にしておかないと実行できないらしい。ハマりポイント。


<details>
<summary>**systemctlで起動する方法試みたがうまく行かず挫折。一応残しておく（クリックで開く）**</summary>
<div>

## sixad デーモン自動起動
ラズパイ起動時に sixad デーモンが立ち上がるようにする

```
$ sudo systemctl enable sixad
```
自動起動を解除するときは下記のようにする

```
$ sudo systemctl disable sixad
```

##ラズパイ起動時に bluetooth を ON にする

```
$ sudo systemctl enable bluetooth.service
```

以下は参考。
当初、なぜか `systemctl` で bluetooth を ON にしようとすると、下記のようにエラーが出た。

```bash
$ sudo systemctl status bluetooth.service 
● bluetooth.service - Bluetooth service
   Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Sat 2020-10-03 21:06:02 JST; 25s ago
     Docs: man:bluetoothd(8)
  Process: 1371 ExecStart=/usr/lib/bluetooth/bluetoothd (code=exited, status=203/EXEC)
 Main PID: 1371 (code=exited, status=203/EXEC)

10月 03 21:06:02 raspberrypi systemd[1]: Starting Bluetooth service...
10月 03 21:06:02 raspberrypi systemd[1371]: bluetooth.service: Failed to execute command: Permission denied
10月 03 21:06:02 raspberrypi systemd[1371]: bluetooth.service: Failed at step EXEC spawning /usr/lib/bluetooth/bluetoothd: Permission denied
10月 03 21:06:02 raspberrypi systemd[1]: bluetooth.service: Main process exited, code=exited, status=203/EXEC
10月 03 21:06:02 raspberrypi systemd[1]: bluetooth.service: Failed with result 'exit-code'.
10月 03 21:06:02 raspberrypi systemd[1]: Failed to start Bluetooth service.
```
よく見ると `/usr/lib/bluetooth/bluetoothd` がパーミッションなしで Fail しているようで、確認するとたしかに 644 だったので実行権限がない。何も考えず 777 を与えることで解消。するかと思われた、が、ラズパイを reboot すると上記 bluetoothd の権限が 644 に戻っているではありませんか。。。755 にしてもだめ（そうだろう）。644 に戻っちゃう時と、戻らないとき (755 のまま) の時がある。なぜなのかわからない・・・

# sixad と bluetooth.service の起動順番
上述のように、sixad と bluetooth.service を `systemctl enable ○○` で起動時から有効にしたが、PS3 コントローラーの PS ボタンを押してもペアリングされない。どうも、bluetooth.service のあとに sixad が起動しないとダメっぽい。サービス Unit の自動起動の順序を確認する

```bash
$ sudo systemctl list-dependencies
default.target
● ├─lightdm.service
● ├─raspi-config.service
● ├─rng-tools.service
● ├─sixad.service
● ├─systemd-update-utmp-runlevel.service
● ├─udisks2.service
● └─multi-user.target
●   ├─avahi-daemon.service
●   ├─console-setup.service
〜以下省略〜
```
また、下記コマンドでは実際にサービス Unit がどういう順で起動してどれくらい時間がかかったを HTML ファイルで出力できる。

```bash
systemd-analyze plot > hoge.html
```
適当にブラウザで開くと下記のようなグラフが得られる。
![unitstart.html.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186524/25eadcd2-bea7-c544-132c-1dd9688686fe.png)

これによると、たしかに sixad が bluetooth.service よりも先に起動している。よって、起動順を変えたい。
[こちらを参考](https://www.excellence-blog.com/2016/12/20/linux%E3%81%A7%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E8%B5%B7%E5%8B%95%E9%A0%86/)に、サービス定義ファイルに起動順番の依存関係を記述することで設定できそうだが、sixad のサービス定義ファイルが存在しないので、どうすればいいのか悩み中（後日記載予定）。
　ー＞[こちら](https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff)を参考にし、`$ sudo sixad -start &` を実行するシェルスクリプトを作り、`sixad_start.service` としてサービス登録してもいいかもしれない


～～～展開ここまで～～～ 

</div>
</details>

#その他
##インストール済みパッケージの確認
apt-get でたくさんパッケージをインストールしたので、何をインストールしたかわからなくなった時は、

```bash
$ sudo dpkg -l
```
で確認

##PS3 コントローラーの入力確認
有線または無線で PS3 コントローラーとラズパイがペアリングされていれば、下記のコマンドで、コントローラー操作があれば文字化けした文字がダーっと表示される

```
$ cat /dev/input/js0
```
コントローラーが複数ペアリングされているときは、js1, js2, ... と増える

##起動中のデーモン確認
意図したデーモンが起動しているか（今回でいうと `sixad` が起動しているか）は下記コマンドで確認

```bash
$ service --status-all
```
たくさん出てくると思うので必要に応じ `grep` で

```bash
$ service --status-all | grep six
 [ ? ]  rng-tools
 [ + ]  sixad
```

##サービス自動起動設定確認

```bash
(例) $ systemctl is-enabled sixad
enabled
```