RaspberryPi
IoT
TWE-Lite
SORACOM

デバイス名を固定する

More than 3 years have passed since last update.

背景

Raspberry Piで、通信用の3Gモデムと振動センサのTWE-Liteを同時に利用したかったんです。
IMG_1251.JPG

Raspberry Piに、3Gモデムだけを差すと、/dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2のデバイスが現れます。TWE-Liteだけを差すと、/dev/ttyUSB0が現れます。
両方差すと、認識された順にデバイス名が作成されます。例えば、3Gモデム=>TWE-Liteの順だと、以下のようになります。

3Gモデム:/dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2
TWE-Lite:/dev/ttyUSB3

困ったこと

では、両方差したまま、電源を入れるとどうなるでしょうか。
以下のどちらかのパターンになるのですが、認識された順に番号は振られるので、どちらになるかはわかりません。

3Gが先パターン
3Gモデム:/dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2
TWE-Lite:/dev/ttyUSB3
TWE-Liteが先パターン
TWE-Lite:/dev/ttyUSB0
3Gモデム:/dev/ttyUSB1, /dev/ttyUSB2, /dev/ttyUSB3

電源投入の度にデバイス名が変更になると、プログラムの中にあるシリアルポートを指定する箇所を、毎回修正する必要があります。
そのため、デバイス名を固定してみようと思いました。

/dev/ttyUSB2 => /dev/ttyUSB_3GModem
/dev/ttyUSB3 => /dev/ttyUSB_TWELite

#TWE-Liteを抜いておいて、RPiが起動し終えたら、USBに差し戻すという方法もありますが、面倒ですよね。

方法

デバイス名を固定するには、/etc/udev/rules.d/99-local.rulesに以下の情報を追記すればよいです。ファイル名は任意です。

/etc/udev/rules.d/99-local.rules
#for 3GModem
##<FS01BU>
#KERNEL=="ttyUSB*",  ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceNumber}=="02", SYMLINK+="ttyUSB_3GModem"
##</FS01BU>

##<ZTE MF112>
#KERNEL=="ttyUSB*",  ATTRS{bNumEndpoints}=="03", ATTRS{bInterfaceNumber}=="02", SYMLINK+="ttyUSB_3GModem"
##</ZTE MF112>

#for TWI-LITE
KERNEL=="ttyUSB*",  ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="ttyUSB_TWELite"

udevファイルを書き換えたら、ls -la /dev/ttyUSB*とコマンドを打って確かめましょう。
3GModem, TWE-Liteの抜き差ししたり、RPiを再起動したりしても、ttyUSB_3GModem, ttyUSB_TWELiteが現れて、適切なデバイスにエイリアスを張っていることが確認できると思います。

pi@raspi-010:~$ ls -la /dev/ | grep USB -2
crw-------  1 pi   tty     204,  64 Sep 28 13:36 ttyAMA0
crw-rw---T  1 root dialout   5,   3 Jan  1  1970 ttyprintk
crw-rw---T  1 root dialout 188,   0 Jan  1  1970 ttyUSB0
crw-rw---T  1 root dialout 188,   1 Sep 28 13:34 ttyUSB1
crw-rw---T  1 root dialout 188,   2 Sep 28 13:34 ttyUSB2
crw-rw---T  1 root dialout 188,   3 Sep 28 13:34 ttyUSB3
lrwxrwxrwx  1 root root           7 Sep 28 13:34 ttyUSB_3GModem -> ttyUSB3
lrwxrwxrwx  1 root root           7 Jan  1  1970 ttyUSB_TWELite -> ttyUSB0
crw------T  1 root root     10, 223 Jan  1  1970 uinput
crw-rw-rw-  1 root root      1,   9 Jan  1  1970 urandom

もっと詳しく

VenderId, ProductIdを知るためには、lsusbで知ることができます。

もし、FS01BU・MF112以外の3Gモデムを利用する場合には、自分でudev設定ファイルを修正する必要があります。
修正に必要な情報は下記のコマンドをデバイス毎に打つことで取得できます。それぞれを比較し、ユニークな値を指定します。

sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/ttyUSB0)
sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/ttyUSB1)
sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/ttyUSB2)
sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/ttyUSB3)

下記の画像は、3Gモデム(MF112)のデバイスに対してudevadm infoをかけた結果を比較したものです。
3Gモデムはデバイスが3つあり、MF112は一番番号の大きなデバイスを通信に使用します。
ググると、デバイス名の固定には、ATTRS{idVendor}ATTRS{idProduct}の属性を用いるのですが、3Gモデムはどれも共通なので、これらの属性は使えません。そのため、ATTRS{bNumEndpoints}ATTRS{bInterfaceNumber}を利用します。

image

下記のように、ATTRS{idVendor}ATTRS{idProduct}ATTRS{bNumEndpoints}ATTRS{bInterfaceNumber}を指定したこともありましたが、これはなぜかうまくいきませんでした。ATTRS{idVendor}ATTRS{idProduct}ATTRS{bNumEndpoints}が同じ階層にない属性であるためかと思っています。

KERNEL=="ttyUSB*",  ATTRS{idVendor}=="19d2", ATTRS{idProduct}=="0016", ATTRS{bNumEndpoints}=="03", SYMLINK+="ttyUSB_3GModem"

参考

とても参考になりました。ありがとうございます。
https://wiki.archlinux.org/index.php/Udev
http://itkobo-z.jp/wp/archives/218