「RapberryPi Zero WをUSBマウスに」でRapberryPi Zero WのUSBマウスを作成しましたが、今回はゲームパッドを作成し、接続されたパソコン側でゲームパッドからデータを入力します。
RapberryPi Zero Wをゲームパッドに
HIDリポートディスクリプタは、HID Descriptor Toolを使用します。「HID Descriptor Tool」からHID Descriptor Tool「dt2_4.zip」をダウンロード・インストールし、入出力するHIDリポートディスクリプタを定義していきます。次にHID Descriptor ToolでゲームパッドのHIDリポートディスクリプタを定義した画面を示します。
入力したHIDリポートディスクリプタを次に示します。ボタンは3個、3ビットで、-32767~32767のx回転、y回転、z回転のそれぞれ16ビットデータのトータル7バイトをゲームパッドから入力できるようにしました。
char ReportDescriptor[54] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x05, // USAGE (Game Pad) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x33, // USAGE (Rx) 0x09, 0x34, // USAGE (Ry) 0x09, 0x35, // USAGE (Rz) 0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767) 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) 0x75, 0x10, // REPORT_SIZE (16) 0x95, 0x03, // REPORT_COUNT (3) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xc0, // END_COLLECTION 0xc0 // END_COLLECTION };
「RapberryPi Zero WをUSBマウスに」のシェル「hid.sh」で作成したUSBマウスのHIDリポートディスクリプタを、19行目のようにHID Descriptor Toolで作成したゲームパッドのHIDリポートディスクリプタに書き換え、製品名称を13行目のような「TomoSoft USB Game Pad」に変更します。
hid.sh
#!/bin/bash modprobe libcomposite cd /sys/kernel/config/usb_gadget/ mkdir -p g1 cd g1 echo 0x1d6b > idVendor # Linux Foundation echo 0x0104 > idProduct # Multifunction Composite Gadget echo 0x0100 > bcdDevice # v1.0.0 echo 0x0200 > bcdUSB # USB2 mkdir -p strings/0x409 echo "S/N 000-00" > strings/0x409/serialnumber echo "tomosoft.jp" > strings/0x409/manufacturer echo "TomoSoft USB Game Pad" > strings/0x409/product N="usb0" mkdir -p functions/hid.$N echo 1 > functions/hid.$N/protocol echo 1 > functions/hid.$N/subclass echo 8 > functions/hid.$N/report_length echo -ne \\x05\\x01\\x09\\x04\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x33\\x09\\x34\\x09\\x35\\x16\\x01\\x80\\x26\\xff\\x7f\\x75\\x10\\x95\\x03\\x81\\x06\\xc0\\xc0 > functions/hid.usb0/report_desc C=1 mkdir -p configs/c.$C/strings/0x409 echo "Config $C: ECM network" > configs/c.$C/strings/0x409/configuration echo 250 > configs/c.$C/MaxPower ln -s functions/hid.$N configs/c.$C/ # End functions ls /sys/class/udc > UDC
HIDデバイス(ゲームパッド)の設定確認
パソコンで「コントロールパネル」から「デバイスとプリンター」を選択すると、次のようにゲームパッド「TomoSoft USB Game Pad」が表示されます。
ゲームパッド「TomoSoft USB Game Pad」を右クリックし、表示されたメニューから「ゲームコントローラの設定」を選択し、表示されたダイアログの「プロパティ」ボタンを押すと、つぎのようにHIDリポートディスクリプタが表示されます。
RapberryPi Zero WでのPythonスクリプトの作成
RapberryPi Zero Wで次ののゲームパッドPythonスクリプト「GamepadExample.py」を作成します。8行目で7バイトのデータを作成します。
GamepadExample.py
#!/usr/bin/env python3 def write_report(report): with open('/dev/hidg0', 'rb+') as fd: fd.write(report.encode()) def main(): write_report(chr(1)+chr(0x02)+chr(0)+chr(0x03)+chr(0)+chr(0x04)+chr(0)) if __name__ == "__main__": main()
パソコンでのゲームパッドデータ入力ソフトの作成
ゲームパッドデータ入力ソフトはC#言語で作成し、「MightyDevices/MightyHID」で「MightyHID」のソースコードはそのまま、「MightyHIDTest」のソースコードを次のように書き換えます。
- 13行目で接続されているHID機器を取得します。
- 28行目で4番目に接続されているHID機器からのデータを受信できるようにOpenします。4番目としたのはゲームパッドが4番目の機器として接続されていることが、あらかじめわかっているためです。
- 30行目でゲームパッドからのデータを入力します。
using System; using Mighty.HID; namespace MightyHIDTest { class Program { static void Main(string[] args) { /* hello, world! */ Console.WriteLine("List of USB HID devices:"); /* browse for hid devices */ var devs = HIDBrowse.Browse(); /* display VID and PID for every device found */ foreach (var dev in devs) { Console.WriteLine("VID = " + dev.Vid.ToString("X4") + " PID = " + dev.Pid.ToString("X4") + " Product: " + dev.Product); } /* try to connect to first device */ if (devs.Count > 0) { /* new device */ HIDDev dev = new HIDDev(); /* connect */ dev.Open(devs[3]); byte[] report = new byte[10]; dev.Read(report); Console.WriteLine("input: " + report[0] + " " + report[1] + " " + report[2] + " " + report[3] + " " + report[4] + " " + report[5]+ " " + report[6] + " " + report[7]); } } } }
ゲームパッドの動作確認
パソコンでプログラムを実行すると次のデータが表示されます。RapberryPi Zero Wで作成したゲームパッドは最下段「VID = 1D6B PID = 0104 Product: TomoSoft USB Game Pad」に表示されています。
List of USB HID devices: VID = 1395 PID = 0025 Product: Sennheiser USB headset VID = 046D PID = C246 Product: G300s Optical Gaming Mouse VID = 08BB PID = 2704 Product: USB Audio DAC VID = 1D6B PID = 0104 Product: TomoSoft USB Game Pad
RapberryPi Zero Wで作成したPythonスクリプト「 GamepadExample.py」を実行して、ゲームパッドのデータをパソコンに送信します。
$ sudo python3 GamepadExample.py
ゲームパッドから送信されたHIDリポートディスクリプタが、次のようにパソコンの表示に追加されます。この値は、作成したPythonスクリプトで設定した値となります。ただし、最初の1バイトについては、制御情報(??)を付与するために追加されるようです。
input: 0 1 2 0 3 0 4 0
ゲームパッドからのHIDリポートディスクリプタが、次のように「ゲームコントローラの設定」で表示されたダイアログの「プロパティ」に表示されます。1番目のボタンが赤く点灯し、x回転、y回転、z回転のデータが少しづつ増加していることがわかります。