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回転のデータが少しづつ増加していることがわかります。