Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

JetsonでのUSBケーブル挿抜検知(udev)

先日JetsonでのOTGデバイスモードへ切り替えるための方法をまとめました。
elsammit-beginnerblg.hatenablog.com
f:id:Elsammit:20210130222442p:plain

今回はUSBケーブルを挿抜検知についてまとめたいと思います。
挿抜検知のために使用するのはデバイス管理ツールudevです。

udevは初めて使用したので良く分からず苦労しました。。。
今後、こんな苦労しないようにしっかりまとめておこうと思います!!



■udevとは?

udevとは、、、
新しいデバイスがコンピュータに接続もしくは接続解除された時に、udevは事前に定義したルールを実行することでデバイスを管理します。
参考:https://hogetech.info/2020/10/04/udev-%E5%85%A5%E9%96%80/

事前に定義したルールですが、例えば

/lib/udev/rules.d

配下に***.rulesが格納されているかと思います。
こちらが事前に定義したルール群になります。

■事前定義ルールの書き方
例えば、

/lib/udev/rules.d/61-gdm.rules

を見てみます。
すると、こちらのような文があるかと思います。

ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", RUN+="/usr/lib/gdm3/gdm-disable-wayland"

こちらが各デバイスを検知した時のルールになっております。

前半に検知するデバイスの情報や条件を記載し、後半に実行したいコマンドやLinkなどを行います。
今回の場合、

ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100"
|

がデバイス情報や条件を記載された項目。
そしてこちらが、実行したい処理になります。

RUN+="/usr/lib/gdm3/gdm-disable-wayland"

さらに、情報や条件指定、実行処理にはATTR{}やRUNが記載されております。
こちらは割当キー(ATTR)と演算子(==など)と呼ばれるものでこちらで条件指定を行います。
ルールで使用出来るキーはこちらに記載されております。
https://docs.oracle.com/cd/E39368_01/admin/about-udev-rules.html

ATTRSが便利なのですが、良く分からなかったので補足しておきます。
ATTRS{file名}でファイル内の文字列を抽出することが出来ます。
例えば、hogeというファイルに

ABCD

と記載されていたとします。
この場合、ルールを

ATTRS{hoge} == ”ABCD” RUN+="hogehoge.sh"

と記載した場合、デバイス情報として合致するためhogehoge.shが実行されることになります。

一方、hoge

ABCD
EFGH

とした場合、

ATTRS{hoge} == "ABCD" RUN+="hogehoge.sh"

はABCDとは不一致となるためhogehoge.shは実行されません。

こちらの条件式ですが、ワイルドカードも指定できます。
このためhoge

ABCD
EFGH

とし、

ATTRS{hoge} == "ABCD*" RUN+="hogehoge.sh"

とした場合、ワイルドカード含めて合致しますので、hogehoge.shが実行されます。

■JetsonでのUSBケーブル挿抜検知
今回USBケーブル挿抜検知を行う構成ですが、こちらになります。
f:id:Elsammit:20210209221708p:plain

まず、USBケーブル挿抜に動作するドライバやシステム名、条件を確認します。
こちらのコマンドを実行してください。

udevadm monitor --env

待機状態になったことを確認して、USBケーブルを挿抜します。
すると、
【USBケーブル挿入時】

ACTION=change
DEVPATH=/devices/external-connection/external-connection:extcon@1/extcon/extcon0
DEVTYPE=extcon0
NAME=external-connection:extcon@1
SEQNUM=7234
STATE=USB=1
USB_HOST=0
SUBSYSTEM=extcon
USEC_INITIALIZED=4596876
net.ifnames=0

【USBケーブル抜時】

ACTION=change
DEVPATH=/devices/external-connection/external-connection:extcon@1/extcon/extcon0
DEVTYPE=extcon0
NAME=external-connection:extcon@1
SEQNUM=7397
STATE=USB=0
USB_HOST=0
SUBSYSTEM=extcon

といった結果が得られます。
※SEQNUMは環境によって値が変わります。

この結果から、
SUBSYSTEMはextconであることが分かりました。
また、挿抜時のACTIONはchangeであることも分かります。

ここで挿抜時のフラグ・トリガですが、

挿入時
STATE=USB=1

抜時
STATE=USB=0

が該当します。
ただ、、、先ほど記載した割当キーには"STATE"はありません。。
じゃあ、この文字列は何なのか??

どうやら、

/devices/external-connection/external-connection:extcon@1/extcon/extcon0

配下に格納された、stateファイルの中身が、

挿入時
STATE=USB=0
USB_HOST=0

抜時
STATE=USB=0
USB_HOST=0

であることが分かりました。

ファイル内を確認して文字列が合致するかをチェックする割当キーはATTRS{file}でしたね。
さらにシステム名はSUBSYSTEM=extconであることが分かりました。
では、これらの情報からudevのルールを作成します。
今回のUSBケーブル挿抜検知用のルールファイルを新規に作成します。

/lib/udev/rules.d

配下に数値から始まるルールファイルを作成します。
例えば、

10-hogehoge.rules

です。
そしたら、ファイルをオープンし、

挿入時
SUBSYSTEM=="extcon", ACTION=="change", ATTRS{state}=="USB=1*" , RUN+="スクリプトファイル名"

抜時
SUBSYSTEM=="extcon", ACTION=="change", ATTRS{state}=="USB=0*" , RUN+="スクリプトファイル名"

を記載します。
ATTRS{state}=="USB=0*"やATTRS{state}=="USB=1*"は先ほど記載しました通り、
stateファイル内のUSB=1やUSB=0が切り替わるので文字列が合致するかを比較。
以降のHOST_USB~~は挿抜しても変化しないためワイルドカード(*)を指定しております。

最後に自分が実行したい実行ファイルを、

RUN+="スクリプトファイル名"

と指定します。

これで、再起動させた後にUSBケーブルを挿抜すると設定した実行ファイルが自動実行されます。

■最後に
udevルールの作成はとても難しいですよね。
理解するのにかなり苦しみました。。。
ただ、苦しんだ分理解が進んだので、次回はより簡単にスクリプト作成することが出来る気がします!!


■参考
https://docs.oracle.com/cd/E39368_01/admin/about-udev-rules.html
https://qiita.com/hana_shin/items/16c457eed20e8822cab8