WSL2 から Bluetooth クラシックの SPP（Serial Port Profile）を使う

WSL2 から Bluetooth クラシックの SPP (Serial Port Profile) を使おうとしたら、意外と苦労したのでやり方を残しておきます。

# Bluetooth クラシックの SPP (Serial Port Profile)
バージョン3.0 以前の Bluetooth (Bluetoothクラシック) は、標準的にUART相当の双方向通信を行う機能が存在します。それが SPP (Serial Port Profile) です。SPP は、PCと一度ペアリングをしてしまえば、OSの備えている "Bluetooth標準シリアルポート" から通信する非常に便利な機能です。

Windows であればデバイスマネージャーで次のように確認することができます。

![2024-08-11-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/8a798bfa-66a4-c6a5-a5ae-0eddf5f6b22d.png)

この SPP はどういうわけか バージョン4.0以降の Bluetooth、通称 BLE (Bluetooth Low Energy) には引き継がれませんでした。BLEデバイスは、OSの備えている "Bluetooth標準シリアルポート" を使うことはできません。BLEの場合は、各BLEデバイスの提供している独自プロファイルで通信することになります。

# Windows11 で Bluetooth SPP とのペアリング
ここはちょっとハマりポイントです。Windows11 のデフォルト設定では ”Bluetooth SPP デバイス”が見つからずペアリングできません。しかし、Bluetooth設定の 「Bluetoothデバイスの検出」を「規定」から「詳細」に変えるだけでペアリングできるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/8e50c278-ebf3-a9a3-2903-5f1cc2f3b719.png)

今回は、Bluetooth デバイスに秋月電子で売っている「RN-42」を使用しました。いまとなっては数少ない技適取得済の Bluetoothクラシックデバイスなので製造終了にならないことを祈るばかりです。

https://akizukidenshi.com/catalog/g/g108690/

ペアリングをすると、なぜか私の環境では "Bluetooth標準シリアルポート" が二つ現れるのですが、理由はよくわかっていません。どちらか試してみて使えるほうを選択してください。

# WSL2 と "Bluetooth標準シリアルポート" と接続する
WSL2 から Bluetooth のハードウェアを直接触ることができません。USBシリアルの場合は Microsoft から usbipd というツールが提供されていますが、"Bluetooth標準シリアルポート" はUSBインターフェースではないので使うことができません。ということで、usbipd に代わる WSL2 と Bluetooth を橋渡しをするツールを準備する必要があります。

## CommTunnel のセットアップ
いろいろ調べたのですが、唯一手掛かりが得られたのは、ここのやりとり。

https://github.com/microsoft/WSL/issues/6692

この中で、次のコメントが目を引きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/04189743-89d2-37bd-c91b-4a2fda00e309.png)

"CommTunnnel" を検索してみたところ、は次のサイトにあったのでダウンロードをしてみました。

https://download.cnet.com/comm-tunnel/3000-2085_4-75328593.html

インストーラは特になく解凍するだけです。起動すると次のような画面が出てきます。"TCPポート"と"Bluetooth標準シリアルポート"を紐づける画面が現れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/101f0e78-3d9e-dee6-3850-7fb13dc78373.png)

「Endpoint1」には「Bluetooth標準シリアルポート」のCOMポートを設定します。「Endpoint2-1」には、転送元のTCPポートを設定します。今回はポート番号「2101」としました。”Start”ボタンを押すと、この二つのエンドポイントが接続され、次のようなメッセージが出てきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/eee25883-9e47-87fb-141d-ca88b505bcd8.png)

## WSL2 側のセットアップ
ここまでで、ようやく usbipd 相当のツールのセットアップが完了しました。次はこのコネクションをWSL2 から使えるようにします。

### WSL2 と Windows の通信用 TCP アドレスの確認
最初に WSL と Windows の間でやりとりしている TCPアドレスを PowerShell もしくは、コマンドプロンプトで確認します。

```console
PS: C:\Users> ipconfig
イーサネット アダプター vEthernet (WSL (Hyper-V firewall)):

   接続固有の DNS サフィックス . . . . .:
   リンクローカル IPv6 アドレス. . . . .: fe80::beff:876d:a747:71bf%46
   IPv4 アドレス . . . . . . . . . . . .: 172.23.208.1
   サブネット マスク . . . . . . . . . .: 255.255.240.0
   デフォルト ゲートウェイ . . . . . . .:
```

私の環境の場合、172.23.208.1 がWSL2との通信に使われているTCPアドレスになります。

### socat のインストールと起動
WSL2 が CommTunnel とシリアル通信するために "socat" というツールを使います。次のような通信スタックを構築します。

**[/dev/virtualcomm0]** 
　　**⇅**
**[tcp4:172.23.208.1:2101]**
　　**⇅**
**[CommTunnel]**
　　**⇅**
**[Bluetooth標準シリアルポート]**

socat をWSL2のコンソールでインストールし、次のコマンドを使って `/dev/virtualcomm0` と `tcp4:172.23.208.1:2101` を紐づけます。

```terminal
$ sudo apt-get install 
$ sudo socat pty,link=/dev/virtualcom0,raw,group-late=dialout,mode=660 tcp4:172.23.208.1:2101
```

`/virtualcom0` 以降のオプションで、一般ユーザーから `/dev/virtualcom0` にアクセスできるようになります。

### 動作確認をする
WSL2 側は screen を立ち上げて Bluetooth との送受信を行います。また、Bluetooth 側は制御用のシリアルポートをパソコンにつなげて「TeraTerm」で動作確認を行います。

screen を立ち上げます。
```terminal
$ screen /dev/virtualcom0
```

TeraTerm と WSL2 の screen と通信を行います。少し関係性が分かりにくいので図にしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/649ca8e0-7f3f-2ed7-84f2-a870b66e1691.png)

このときに CommTunnel の画面を見ると、通信しているのが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/19f67a81-2866-eeb2-6f26-2cf869c0d981.png)


# 所感
WSL2からSPPを使うという人が意外と世の中にほとんどいないことが分かり調査に苦労しました。ComTunnel の使い方についてもほとんどドキュメントがなく、”こんなもんだろう”と思って使ってみたらうまく行ったのはラッキーでした。socat はTCP通信の転送にはよく使われているので知っていましたが、シリアルの転送にも使えるというのは目からうろこでした。こんな芸当ができるのは、POSIX OS ならではですね。

#参考文献
https://unix.stackexchange.com/questions/374916/how-to-use-virtual-serial-port-without-root-privileges