Raspberry Pi 4のLinuxガジェット機能を使ってHID(Human Interface Device)マウスを実現します。ガジェットモードを動作させるに、USB OTG(USB On-The-Go)にRaspberry Piが対応している必要があります。
現在、USB OTGに対応しているのは、Raspberry Pi Zero(W/WH)、Raspberry Pi 4になります。
今回の手順はRaspberry Pi 4を元に説明を作っていますが、Raspberry Pi Zero(W/WH)でも動作します。
もくじ
USB On-The-Go(USB OTG)とは
USB OTGは、USB IF(USB Implementers Forum)が定めた規格です。
もともとUSBは、パソコン(ホスト)と、USB機器「キーボード、マウス、プリンター、デジカメなど」(デバイス)が接続して、パソコンがUSB機器を制御していました。
USB OTGの規格が誕生して、USB機器どうしを直接接続して使えるようになりました。例としてデジカメとプリンターを接続して直接印刷したり、スマホとプリンターを接続して印刷したり出来るのは、USB OTGに対応しているからです。
USB OTGに対応している機器は、状況役割によってUSBホストになったり、USBデバイスになったりします。
接続方法
Raspberry Pi 4は、下の画像にあるようにUSB Type-Cの電源コネクタとパソコンを接続します。
パソコンにUSB Type-Cがある場合は、USB Type-C to Type-Cケーブルで接続します。
パソコンにUSB Type-Cが無い場合には、USB Type-C to Type-A変換ケーブルを使って接続します。
電源はこのUSBケーブルから供給されるため、ある程度安定した電源供給が必要です。
USB Type-C to Type-Aで接続する場合、状況によってはセルフパワー付きのUSB HUBを使って接続するのも良いと思います。
Raspberry Pi Zero WHの場合、USB Micro-Bコネクタ(電源「PWR IN」ではないコネクタ「USB」の方)に接続します。
パソコンとは、USB Type-A to Micro-Bケーブルで接続されて、電源供給もこのUSBケーブル経由で供給されます。
dwc2 USBドライバの設定
「/boot/config.txt」ファイルに「dtoverlay=dwc2」を、「/etc/modules」ファイルに「dwc2」を一番最後にviやnanoなどのエディタで追記して起動時にドライバが自動でロードされるように設定します。
$ sudo nano /boot/config.txt
$ sudo nano /etc/modules
または、コマンドでターミナルから「tee」コマンドでファイルに追記してください。
$ echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt
$ echo "dwc2" | sudo tee -a /etc/modules
追記後、Raspberry Piを再起動します。
HIDマウスの設定
今回作成する、USBマウスのUSB HID report descriptorは次のようなパラメーターになっています。
パラメーターの詳細の確認は、USB Implementers Forumの「Device Class Definition for HID」、「HID Usage Tables」ドキュメントを参照してください。
USBマウスのHID report descriptor情報
USAGE_PAGE (Generic Desktop) 05 01
USAGE (Mouse) 09 02
COLLECTION (Application) A1 01
USAGE (Pointer) 09 01
COLLECTION (Physical) A1 00
USAGE_PAGE (Button) 05 09
USAGE_MINIMUM (Button 1) 19 01
USAGE_MAXIMUM (Button 5) 29 05
LOGICAL_MINIMUM (0) 15 00
LOGICAL_MAXIMUM (1) 25 01
REPORT_COUNT (5) 95 05
REPORT_SIZE (1) 75 01
INPUT (Data,Var,Abs) 81 02
REPORT_COUNT (1) 95 01
REPORT_SIZE (3) 75 03
INPUT (Cnst,Var,Abs) 81 03
USAGE_PAGE (Generic Desktop) 05 01
USAGE (X) 09 30
USAGE (Y) 09 31
USAGE (Wheel) 09 38
LOGICAL_MINIMUM (-32767) 16 01 80
LOGICAL_MAXIMUM (32767) 26 FF 7F
REPORT_SIZE (16) 75 10
REPORT_COUNT (3) 95 03
INPUT (Data,Var,Rel) 81 06
END_COLLECTION C0
END_COLLECTION C0
上記のHID report descriptor情報を使用して、次のシェルスクリプト「gadget_mouse.sh」を作成して、Raspberry Pi 4をUSBマウス「Generic USB Mouse」として動作するようにします。
作成したシェルスクリプトはUSBガジェットの作成「start」と、USBガジェットの停止「stop」の機能があります。
#!/bin/bash
GADGET="/sys/kernel/config/usb_gadget"
VID="0x1d6b" # Linux Foundation
PID="0x0104" # Multifunction Composite Gadget
DEVICE="0x0100" # v1.0.0
USB_TYPE="0x0200" # USB2
SERIAL_NUMBER="abcd1234" # serial number
MANUFACTURER="toki-blog.com" # manufacturer code
PRODUCT_NAME="Generic USB Mouse" # product name
PROTOCOL="1" # USB protocol
SUBCLASS="1" # USB subclass
REPORT_LENGTH="7" # USB report length
REPORT_DESCRIPTOR="\\x05\\x01\\x09\\x02\\xA1\\x01\\x09\\x01\\xA1\\x00\\x05\\x09\\x19\\x01\\x29\\x05\\x15\\x00\\x25\\x01\\x95\\x05\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x03\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x09\\x38\\x16\\x01\\x80\\x26\\xFF\\x7F\\x75\\x10\\x95\\x03\\x81\\x06\\xC0\\xC0"
DEVICE_NO="usb0"
CONFIG_NO="1"
MAX_POWER="250"
case "$1" in
start)
echo "Creating the USB gadget"
modprobe libcomposite # Loading composite module
echo "Creating gadget directory"
cd $GADGET
mkdir -p g1
cd g1
echo "Setting ID's"
echo $VID > idVendor
echo $PID > idProduct
echo $DEVICE > bcdDevice
echo $USB_TYPE > bcdUSB
echo "Creating strings"
mkdir -p strings/0x409
echo $SERIAL_NUMBER > strings/0x409/serialnumber
echo $MANUFACTURER > strings/0x409/manufacturer
echo $PRODUCT_NAME > strings/0x409/product
echo "Creating the functions"
mkdir -p functions/hid.$DEVICE_NO
echo $PROTOCOL > functions/hid.$DEVICE_NO/protocol
echo $SUBCLASS > functions/hid.$DEVICE_NO/subclass
echo $REPORT_LENGTH > functions/hid.$DEVICE_NO/report_length
echo -ne $REPORT_DESCRIPTOR > functions/hid.$DEVICE_NO/report_desc
echo "Creating the configurations"
mkdir -p configs/c.$CONFIG_NO/strings/0x409
echo "Config $CONFIG_NO: ECM network" > configs/c.$CONFIG_NO/strings/0x409/configuration
echo $MAX_POWER > configs/c.$CONFIG_NO/MaxPower
echo "Associating the functions with their configurations"
ln -s functions/hid.$DEVICE_NO configs/c.$CONFIG_NO/
echo "Enabling the USB gadget"
ls /sys/class/udc > UDC
echo "OK"
;;
stop)
echo "Stopping the USB gadget"
echo "Disabling the USB gadget"
cd $GADGET/g1
echo "" > UDC
echo "Cleaning up"
rm configs/c.$CONFIG_NO/hid.$DEVICE_NO
rmdir functions/hid.$DEVICE_NO
echo "Cleaning up configuration"
rmdir configs/c.$CONFIG_NO/strings/0x409
rmdir configs/c.$CONFIG_NO
echo "Clearing strings"
rmdir strings/0x409
echo "Removing gadget directory"
cd $GADGET
rmdir g1
cd /
# modprobe -r libcomposite # Remove composite module
echo "OK"
;;
*)
echo "Usage : $0 {start|stop}"
;;
esac
「gadget_mouse.sh」を作成したら、次のコマンドを実行して、USBガジェットの作成「start」します。
パラメーターの意味は、Linux USB gadget configured through configfsを参照してください。
$ chmod 777 gadget_mouse.sh
$ sudo ./gadget_mouse.sh start
実行時にエラーが出る場合、作成したファイルの改行コードが「LF」になっていているか確認しましょう。
「CRLF」の場合は、改行コードを「LF」に変更して保存します。
HIDマウスの動作確認
lsコマンドで「/dev/hidg0」を表示すると次のように表示されます。
$ ls -l /dev/hidg0
crw------- 1 root root 235, 0 5月 25 01:01 /dev/hidg0
「/dev/hidg0」のデバイスが作成されると、Windows側では「Generic USB Mouse」接続を検知してドライバーのインストールが実行されます。
正しく、Windowsで認識、動作しているかをデバイスマネージャーにて確認します。
「マウスとそのほかのポインティングデバイス」を展開すると、「HID準拠マウス」があります。下の画像の例の場合、通常のマウスと今回追加したガジェットのマウスの2つが表示されます。
「HID準拠マウス」を「右クリック」して「プロパティ」で、「HID準拠マウスのプロパティ」を表示します。
「イベント」タブを表示して、「親デバイス」の項目で今回追加した、「VID:1D6B」、「PID:0104」、「シリアル:abcd1234」の表示があれば、このデバイスが正常に動いています。
パラメーターに不備があって設定に失敗すると、下記のようにエクスクラメーションマークが表示されます。
USB機器の情報を詳しく確認する
USBView、USBDeviewでもう少し詳細に確認します。
使い方については、こちらの記事で紹介しています。
-
PCに接続したUSB機器の情報を確認する
USB機器の情報を取得するツールを紹介します。「USBView」ツールは、Windows PCに接続されているすべてのUSBデバイス情報を参照できるWindows SDKに含まれるツールです。 また、 ...
続きを見る
パラメーターの説明
今回作成したHIDマウスは、次のパラメーターで制御します。
byte | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
0 | padding | padding | padding | 進むボタン | 戻るボタン | 中ボタン | 右ボタン | 左ボタン |
1 | カーソル横移動量(LSB) | |||||||
2 | カーソル横移動量(MSB) | |||||||
3 | カーソル縦移動量(LSB) | |||||||
4 | カーソル縦移動量(MSB) | |||||||
5 | ホイール縦スクロール移動量(LSB) | |||||||
6 | ホイール縦スクロール移動量(MSB) |
- カーソル横移動量 ・・・ -32767~32767の範囲(マイナスが左移動、プラスが右移動)
- カーソル縦移動量 ・・・ -32767~32767の範囲(マイナスが上移動、プラスが下移動)
- ホイール縦スクロール移動量 ・・・ -32767~32767の範囲(マイナスが下スクロール、プラスが上スクロール)
コマンドでの動作確認
次のコマンドを入力して、パソコン側のマウスカーソルが動作するか確認します。
実行するとマウスカーソルが右に移動します。
$ sudo su
# echo -ne "\x00\xff\x00\x00\x00\x00\x00" > /dev/hidg0
Pythonのサンプルプログラム
Pythonにて制御するサンプルプログラム「mouse_sample.py」を作成します。
サンプルプログラムでは、「左クリック1回」カーソルの位置で実行して、「右にカーソル移動」をします。
from enum import IntEnum
CLICK_OFF = 0x00 # Click off
CLICK_LEFT = 0x01 # 左クリック
CLICK_RIGHT = 0x02 # 右クリック
CLICK_MIDDLE = 0x04 # 真ん中クリック
CLICK_BACK = 0x08 # 戻る
CLICK_FORWARD = 0x10 # 進む
class MouseIndex(IntEnum):
TIP_SW = 0
X_LSB = 1
X_MSB = 2
Y_LSB = 3
Y_MSB = 4
WHEEL_LSB = 5
WHEEL_MSB = 6
MAX = 7
def send_command(buffer):
cmd = bytes(buffer)
with open('/dev/hidg0', 'rb+') as fd:
fd.write(cmd)
def mouse_control(tip, x, y, wheel):
data = [0] * MouseIndex.MAX
data[MouseIndex.TIP_SW] = tip
data[MouseIndex.X_LSB] = (x & 0xff)
data[MouseIndex.X_MSB] = (x >> 8)
data[MouseIndex.Y_LSB] = (y & 0xff)
data[MouseIndex.Y_MSB] = (y >> 8)
data[MouseIndex.WHEEL_LSB] = (wheel & 0xff)
data[MouseIndex.WHEEL_MSB] = (wheel >> 8)
send_command(data)
def main():
print("Mouse sample.")
x = 0
y = 0
wheel = 0
# 左クリック
mouse_control(CLICK_LEFT, x, y, wheel)
mouse_control(CLICK_OFF, x, y, wheel)
# カーソルX移動
x = 100
mouse_control(CLICK_OFF, x, y, wheel)
if __name__ == "__main__":
main()
作成した「mouse_sample.py」を次のコマンドにて実行します。
$ sudo python3 mouse_sample.py
Raspberry Pi起動時にガジェットを有効にする方法
Raspberry Piを起動した時に、ガジェットを有効にして作成したUSBマウスとして起動するようにします。また、一般ユーザーでも作成したデバイスの使用ができるよう許可します。
例として「/home/pi/Desktop/gadgets」フォルダに、作成し「gadget_mouse.sh」ファイルを置きます。
「vi」や「nano」のエディタで「/etc/rc.local」ファイルを開いて次のスクリプトを書き込みます。
/home/pi/Desktop/gadgets/gadget_mouse.sh start
chmod -R 777 /dev/hidg0
exit 0
「exit 0」の手前にスクリプトを書き込みましょう。
まとめ
Raspberry PiのLinuxガジェット機能では色々な事ができ、今回はUSBマウスを実現しました。マウスが再現できると自動でアプリやブラウザの制御ができたりして色々アイデアが出てきます。
今後も、他のLinuxガジェット機能も試して行きます。
以上、「Raspberry Pi 4のLinux ガジェットでマウスを実現する(USB OTG)」の内容でした。