メカトロ講座04 USBシリアル変換のデバイス名を対応させる

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 16.04 |
| 変換IC | FT231X |

# 概要
ロボットを作っているとUSBシリアルを多用します。基本的にシリアルポートはUbuntuからはttyUSB0、ttyUSB1...という名前で割り当てられますが、これでは複数のUSBシリアルを接続しても認識される順番によって名前の割り当てが違ってしまいます。複数のUSBシリアルを使うが、先につながっているものが違うので、各々を区別したいという時のために、物理的なアダプタとデバイスファイル名を1対1で対応させる方法を説明します。

# USBデバイスの識別方法
USBデバイスの識別手段として以下のようなものの候補が挙げられます。

| 方法 | 説明 |
|:-:|:-:|
| Vendor ID | 製造メーカーを表す16進数4桁のコードで一意に管理されています |
| Device ID | 製品を表す16進数4桁のコードで一意に管理されています |
| シリアルNo. | デバイスごとに割り当てられている番号です |
| マニュファクチャ名 | 数文字の名前です。 |
| プロダクト説明 | 十数文字の名前です。 |
| 物理的な差し込み位置 | USBのポート番号で特定します |

一番大切なのは Vendor IDとDevice IDです。これは公式に管理されています。大体のデバイスはこれらによって一意に認識できます。正当な方法は自分でこの値を取得して、目的に応じてこれらの値を割り当てることですが、これは少々大げさな異なります。windowsでもubuntuでもこれらの値を見てデバイスドライバを割り当てているので、この値を変えるとデバイスドライバを自分で設定しないといけません。このために今回の複数のUSBシリアルを識別したいという目的とは外れます。
シリアルNoはデバイスごとに違う値なので、少々細かすぎます。また差し込み位置は将来的に変わることも考えられるので使いたくありません。
今回は「マニュファクチャ名」と「プロダクト説明」を使って識別します。

# USBシリアル変換ICの書き換え
今回はFTDIのチップを使うことを前提にします。FTDIのチップはWindowsのソフトであるFT_Progを使って書き換えができます。サイトのリンクを参考に置いておきます。
USBシリアル変換を挿して、FT_Progを起動したらメニューバーの「DEVICE」の「Scan and Parse」を選んでください。以下のように識別結果が出てきます。左側のウィンドウで「USB String Descriptors」を選択して、右側のウィンドウで「Manufacture」と「Product Description」の項目を書き換えましょう。私は「SRS」、「Adapter」と書き換えました。最後にメニューバーの「雷のマーク」を押して書き込みます。

![hard_ftdi_rewrite.png](https://qiita-image-store.s3.amazonaws.com/0/254442/e60aad0c-66ce-c7f6-505e-9f968c33bebe.png)

ちなみにVendor IDとDevice IDを書き換えるとWindowsでFTDIのデバイスと認識できなくなり、FT_Progでアクセスできなくなります。これを解決するためにはWindows用のデバイスドライバを製作する必要があります。

# usbの情報の確認

USBシリアル変換をUbuntuに挿します。`ls /dev/ttyUSB0`が見えればOKです。
以下のコマンドでUSBデバイスの詳細が見えます。`ATTRS{manufacturer}=="SRS"`と`ATTRS{product}=="Adapter"`の項目を確認します。

```shell:usbデバイスの情報の表示コマンド
udevadm info -a -n ttyUSB0 
```

```shell:usbデバイスの情報の表示の結果（一部）
 looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.2':
    KERNELS=="2-2.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{bMaxPower}=="90mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bcdDevice}=="1000"
    ATTRS{bmAttributes}=="a0"
    ATTRS{busnum}=="2"
    ATTRS{configuration}==""
    ATTRS{devnum}=="12"
    ATTRS{devpath}=="2.2"
    ATTRS{idProduct}=="6015"
    ATTRS{idVendor}=="0403"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="SRS"
    ATTRS{maxchild}=="0"
    ATTRS{product}=="Adapter"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="unknown"
    ATTRS{serial}=="DN3RJZ4W"
    ATTRS{speed}=="12"
    ATTRS{urbnum}=="18"
    ATTRS{version}==" 2.00"
```


# udevの設定

最後にudevの設定をします。以下のようなファイルを製作します。製作後USBデバイスを抜き差しします。

```text:/etc/udev/rules.d/80-srs.rules
# udev rule for FT231X (Dual USB-UART/FIFO IC)
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{manufacturer}=="SRS", ATTRS{product}=="Adapter", SYMLINK+="srs"
```

# 結果の確認
最後に`/dev/srs`という名前でアクセスできるようになったことを確認します。

```shell:デバイスの確認
$ll /dev/srs
```

```shell:デバイスの確認の結果
lrwxrwxrwx 1 root root 7 Jan  7 23:24 /dev/srs -> ttyUSB0
```

# 参考
[USBのベンダーIDとプロダクトIDの話](https://qiita.com/gpsnmeajp/items/8eb8ecf0541032f6de0e)
[FT_Prog](https://www.ftdichip.com/Support/Utilities.htm#FT_PROG)
[FTDI用のudevルール](http://yura2.hateblo.jp/entry/2016/07/26/FTDI_FT2232C%E7%94%A8%E3%81%AEudev%E3%83%AB%E3%83%BC%E3%83%AB)

# 目次ページへのリンク
[ROS講座の目次へのリンク](https://qiita.com/srs/items/5f44440afea0eb616b4a)