スマホでNintendo Switchを操作する 〜 USB GadgetでPro Controllerをシミュレート 〜
mzyy94
mzyy94
31 min read

Categories

Tags

あつまれ どうぶつの森の配信が開始されましたね。いくつか積みゲーが増え始めたNintendo Switchも、また新たにゲームが増えて稼働時間が伸びる一方です。

物をよくなくす身として、ゲームがしたいときにコントローラーが見つからないことは日常茶飯事です。 テレビやエアコンのリモコンもよく消えるので、スマートフォンから操作できるようにしています。スマート家電、文明の利器ですね。 コントローラーが見つからないとき、スマートフォンから操作はできないのでゲームはお預けです。

家電はスマホでスマートに操作できるのに、ゲームはレガシーなコントローラーを探さなきゃいけないなんて、なんてスマートじゃないのでしょう。 どうぶつたちの住む無人島に到達できやしません。

と言うことで、スマートフォンでNintendo Switchを操作出来るようにすべく、奮闘した記録です。 概要としては、Raspberry PiでNintendo Switch Pro Controllerをシミュレートし、Wi-Fi経由でスマホから操作する話です。 ちょっと分量が多いので読むのは大変かも。

Table of Contents

  1. Nintendo Switch Pro Controller
    1. リバースエンジニアリング
  2. USB Gadget API
  3. USB HID
  4. 実装調査
    1. USB GadgetでHIDシミュレート実験
  5. 挙動解析
    1. 通信内容
  6. Pro Controllerの解析
    1. HID Report Descriptorの謎
    2. Chromium nintendo_controller実装
  7. リバースエンジニアリング
    1. SwitchとPro Controllerをバイパス
    2. 入力データ
  8. Raspberry Piでシミュレート
    1. 1.3inch LCD HATでの入力
    2. スマホからの入力
  9. まとめ

Nintendo Switch Pro Controller

言わずと知れた、任天堂純正のNintendo Switch向けワイヤレスコントローラーです。Nintendo Switch本体と比べても大柄なボディは手になじみ、疲れをあまり感じさせません。 おちつきのあるダークな色合いが上品さを演出していますが、彩度が低いため、よく行方不明になります。

Amazon | 【任天堂純正品】Nintendo Switch Proコントローラー | ゲーム

Nintendo Switchは、このPro Controllerなど、任天堂製か公式ライセンス商品しかコントローラーとして認識してくれません。 2017年の年末に没頭していたSplatoon 2で、自動ドット絵作画ツールを作った時も、公式ライセンス商品であるHORIのPokken Padをシミュレートして使っていました。

ドイツのトリ in Splatoon 2 - 犬アイコンのみっきー

Pokken Padは、Arduinoベースでのシミュレートの動作実績もあるので比較的簡単にシミュレートできます。 しかしジャイロやジョイスティックがないので、多くのゲームに対応しようとするには不向きです。

今回はこのPro Controllerをなくしても大丈夫なように、シミュレートしていきます。

リバースエンジニアリング

Nintendo Switchに関するリバースエンジニアリングは発売から間も無くして賑わいをみせ、今では多くの情報がインターネットに流れています。 その代表的なものとして、Nintendo_Switch_Reverse_Engineeringといった資料群がGitHubにあります。

dekuNukem/Nintendo_Switch_Reverse_Engineering: A look at inner workings of Joycon and Nintendo Switch

ここにはJoyconやPro Controller、そしてNintendo Switch本体のリバースエンジニアリングを行った結果がいくつか載っています。 これと共に、実際のNintendo SwitchにおけるPro Controllerの挙動を突き合わせれば、シミュレートすることができる算段です。

USB Gadget API

USB Gadget APIとは、Linux KernelにおけるUSBデバイスのペリフェラル、周辺機器側として動作する機能のことです。 簡単に言うと、Raspberry Piがキーボードとかゲームパッドになるよってやつです。 ハードウェアのサポートも必要ですが、最近話題のRaspberry Pi 4や昔紹介したNanoPi NEO2などが対応しています。

USB Gadget API for Linux — The Linux Kernel documentation

USB Gadgetを作成する方法としては、カーネルモジュールをロードする方法や、configfsを用いてファイルシステムベースで定義する方法があります。

また、上記ドキュメントに例として挙げられているように、以下のようなUSBデバイスをシミュレートできます。

  • networking subsystem (for network gadgets, like the CDC Ethernet Model gadget driver)
  • data capture drivers, perhaps video4Linux or a scanner driver; or test and measurement hardware.
  • input subsystem (for HID gadgets)
  • sound subsystem (for audio gadgets)
  • file system (for PTP gadgets)
  • block i/o subsystem (for usb-storage gadgets)
  • … and more

このうち、コントローラーなどはinput subsystem (for HID gadgets)にあたり、USB HIDプロトコルをシミュレートする必要があります。 裏を返せば、USB GadgetでPro ControllerのUSB HIDプロトコルをシミュレートできれば、技術的には問題は解決です。

USB HID

USB HIDプロトコルは、簡単にいえばキーボードやマウス、コントローラーなど、USB経由でやり取りする入力機器のデータのプロトコルを、HID Report Descriptorと言う定義情報を通して定義する物です。 入力機器のデータのやり取りは、一般的なUSBデバイスと同じく、USB Request Block (URB)で行い、それの各ビットが入力情報の何を指しているかを定義しています。

定義はUsage itemと言う形で記され、そのUsage、すなわち用途については、以下のUSB-IFの公式ドキュメントに記載があります。 実際にPro ControllerのHID Report Descriptorを調べたりしたとき、この情報は必要となってきます。

HID Usage Tables 1.12 | USB-IF

実装調査

Raspbianでlsusbを用いてUSB Device decriptorを調査するところから始めます。

pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.19.97-v7l+ #1294 SMP Thu Jan 30 13:21:14 GMT 2020 armv7l GNU/Linux

pi@raspberrypi:~ $ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 057e:2009 Nintendo Co., Ltd 
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

pi@raspberrypi:~ $ lsusb -d 057e: -v 2> /dev/null
Bus 001 Device 003: ID 057e:2009 Nintendo Co., Ltd 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x057e Nintendo Co., Ltd
  idProduct          0x2009 
  bcdDevice            2.00
  iManufacturer           1 Nintendo Co., Ltd.
  iProduct                2 Pro Controller
  iSerial                 3 000000000001
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0029
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     203
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               8
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               8
Device Status:     0x0001
  Self Powered

肝心なHID Report Descriptorは** UNAVAILABLE **となっていて、lsusbでは取得できませんでした。そのため、usbhid-dumpを用います。 usbhid-dumpsudo apt-get install -y hidrdで入ります。

pi@raspberrypi:~ $ sudo usbhid-dump -d057e
001:004:000:DESCRIPTOR         1583574828.992958
 05 01 15 00 09 04 A1 01 85 30 05 01 05 09 19 01
 29 0A 15 00 25 01 75 01 95 0A 55 00 65 00 81 02
 05 09 19 0B 29 0E 15 00 25 01 75 01 95 04 81 02
 75 01 95 02 81 03 0B 01 00 01 00 A1 00 0B 30 00
 01 00 0B 31 00 01 00 0B 32 00 01 00 0B 35 00 01
 00 15 00 27 FF FF 00 00 75 10 95 04 81 02 C0 0B
 39 00 01 00 15 00 25 07 35 00 46 3B 01 65 14 75
 04 95 01 81 02 05 09 19 0F 29 12 15 00 25 01 75
 01 95 04 81 02 75 08 95 34 81 03 06 00 FF 85 21
 09 01 75 08 95 3F 81 03 85 81 09 02 75 08 95 3F
 81 03 85 01 09 03 75 08 95 3F 91 83 85 10 09 04
 75 08 95 3F 91 83 85 80 09 05 75 08 95 3F 91 83
 85 82 09 06 75 08 95 3F 91 83 C0

USB GadgetでHIDシミュレート実験

この結果より、configfsを用いてUSB Gadgetを構成し、Pro Controllerをシミュレートします。 configfsを用いたUSBデバイスのUSB Gadget APIでの実装方法は、Linuxの公式ドキュメントにて説明されています。

Linux USB gadget configured through configfs — The Linux Kernel documentation

また、HID Report Descriptorはreport_descに記すと以下のドキュメントにあります。

Linux USB HID gadget driver — The Linux Kernel documentation

これらを参考にした以下のShell Scriptで、Raspberry PiをPro Controllerを模したUSB Gadgetにできます。

Raspbianでは、dwc2モジュールをロードしておくため、/boot/config.txtにdtoverlay=dwc2を、/etc/modulesにdwc2libcompositeを追記する必要があります。

firmware/README at 1.20200212 · raspberrypi/firmware

Raspberry Pi 4をUSB 2.0 Type-CケーブルでmacOSにつなげた状態でこれを実行すると、以下のようにPro Controllerっぽく認識してくれます。 そしてRaspberry Pi側には、/dev/hidg0 といったスペシャルファイルが出来上がります。

macOS USB Pro Controller detected

あとは、/dev/hidg0 に書き込むデータを準備するまでです。

挙動解析

実際にコントローラーからどういったデータが送られているか、挙動をみてみるのが手っ取り早いので、さくっとみてみます。 手元で動かしているMacBook ProとPro ControllerをUSB Type-Cケーブルで接続します。Pro⇄Pro。

macOSで手軽にコントローラーの挙動を調査する方法として、パッと思いついたのがHTML5のGamepad API。 モダンブラウザではHTML5 APIの一つとしてGamepad APIをサポートしているので、HTML5 Gamepad Testerでみてみました。

chrome screen shot

ChromeではちゃんとGamepad APIで認識しているようです。

通信内容

一般的なUSB接続で、またまた一般的なURBでやり取りしているため、一般的なパケットキャプチャーソフトウェアでキャプチャできます。 Wiresharkの出番です。

macOSではいとも簡単にUSBデバイスキャプチャができるので、公式Wikiを参考にsudo ifconfig XHC20 upでXHCインターフェースを有効にし、XHC20インターフェースを対象にキャプチャしてみます。

CaptureSetup/USB - The Wireshark Wiki

USBケーブルを繋げてすぐにMacとPro Controllerが通信を始め、しばらくの手続きののちに、入力データらしき物を返し続けるようになりました。

wireshark screen shot

このとき通信を行っていたのはGoogle Chromeで、Gamepad APIの初期化をUSBデバイス認識時に行っているようでした。

キャプチャしたデータを見てわかったこととして、入力データの通信内容がHID Report Descriptorに記されている定義と違う謎があると言うことです。 いったいどんな謎があるのでしょうか。。深掘りしてみます。

Pro Controllerの解析

HID Report Descriptorの謎

先のusbhid-dumpでダンプしたHID Report Descriptorの内容を、先ほど紹介したHID Usage Tablesで内容を確認すると、一般的なコントローラーとは大きく違うことがわかってきました。 ダンプした内容はUSB-IFのドキュメントを参照して一つ一つデコードして見てみるもよしですが、コピペでデコードしてくれるWebサービスがあるので、それを使ってみてみます。

USB Descriptor and Request Parser

デコードした結果は、以下のようになっています。

入力機器からのデータを示すInputの他にOutputがあるのに加え、一番気になるのは、0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) の部分です。独自のデータ定義が含まれていることを指しています。 これは単純に入力情報だけをUSB Gadget経由で送出していればいいわけではなく、一筋縄ではいかないことを意味しています。

InputとOutputは各Report IDを持つ入出力が何を示すかを記しています。Report IDとは、URBパケットのヘッダを除くデータの1バイト目のことです。 Input、すなわちPro Controllerからのデータを示すReport IDは、0x81, 0x21, 0x30の3つがあり、Output、すなわちNintendo SwitchからPro Controllerに送られるデータのReport IDは、0x01, 0x10, 0x80, 0x82の4つがあることがわかります。

Input Report ID 0x30にだけ、詳細にどのビットがどの入力を示すかが定義されています。 正しくデコードできていないところをHIDの仕様を元に正すと、下表の通りに入力データの各ビットの値をコントローラの各入力として定義していることがわかりました。

Usage Usage Logical Min/Max Report Size(bits) Report Count
09 Button 0/1 1 10
09 Button 0/1 1 4
- (blank) -/- 1 2
010001 Pointer 0/65534 16 4
010030 X (ditto) (ditto)  
010031 Y (ditto) (ditto)  
010032 Z (ditto) (ditto)  
010035 Rz (ditto) (ditto)  
010039 Hat switch 0/7 4 1
09 Button 0/1 1 4

これを噛み砕くと、0x30で始まるURBのデータは、

  • 先頭から10ビットは各種ボタン(A/B/X/Y/L/R/L2/R2/L3/R3かな?)
  • 続く4ビットも各種ボタン(-/+/capture/homeかな?)
  • 2ビット飛んで
  • 左右のJoyスティックのX軸Y軸それぞれを16bitのunsgined short型で4つ
  • 十字キーの入力を0-7までの45度ずつで示して
  • 謎のボタン4つ

となるはずですが、Wiresharkで観測したデータはこの通りではありませんでした。

一つ例をあげるとこんな感じです。

0000   30 df 91 00 80 00 31 28 7c dc 37 7b 0a 00 00 00
0010   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

これを先ほどまとめたUsageの表の通りにバイナリ表現にして分解して、愚直に解釈しいくと、以下のようになっていると読み取れます。

Bits Usage Description
1101111110 Button ABXYLRなどのボタンが8つ同時に押されてる
0100 Button ボタンが1つ押されてる
0000000010000000 Pointer X スティックが少し倒されてる
0000000000110001 Pointer Y スティックが少し倒されてる
0010100001111100 Pointer Z スティックが結構倒されてる
1101110000110111 Pointer Rz スティックがものすごく倒されてる
0111 Hat switch 十字キーが315度の位置に入力されている
1011 Button 謎のボタンが3つ押されてる

はい。こんな入力してません。何かがおかしい。

解決の糸口を探すため、何かしらの実装をみてみる必要があります。

Chromium nintendo_controller実装

ChromeでHTML5 Gamepad Testerをみたときは左右のJoyスティックの座標を正しく認識していましたが、この状態でSafariでも見てみるとどうでしょう。

safari screen shot

Joyスティックは正しく表示されない上に、何も操作していなくてもボタンが押されているような挙動をしています。

これはどういうことかと言うと、Chromeの大元となるChromiumの実装には、nintendo_controller.ccといった、Pro Controllerを含む任天堂製のコントローラーのためのドライバーが、ブラウザのレイヤーで実装されているからでした。

対してSafariのベースであるWebKitにはこういった実装がないため、先に示したHID Report Descriptorを愚直に解釈し、その入力値をコントローラー入力としてAPIに出していたためにおかしな挙動をしていたのです。

chromium/nintendo_controller.cc at 8dda15b2f1c013956e1e7cd75223d617af694694 · chromium/chromium

このコードから、大まかな初期化処理を行う必要性がわかります。さらに、後述しますが、コントローラーの入力データの謎フォーマットも解けるのです。

まずは、初期化処理を、キャプチャしたデータを元に解析していきます。

リバースエンジニアリング

ChromiumのGemapad APIの実装がどういったやり取りを行っていたかを、Nintendo_Switch_Reverse_Engineeringを参考に紐解いていきます。 WiresharkでキャプチャしたURB Interruptで送受信されているデータは、大まかに以下の5つのパターンでした

  • 80 0Xで始まるChromiumからの要求(Output Report)
  • 81 0Xで始まるPro Controllerからの応答(Input Report)
  • 01 XXで始まるChromiumからの要求(Output Report)
  • 21 XXで始まるPro Controllerからの応答(Input Report)
  • 30 XXで始まるPro Controllerからの応答(Input Report)

これらをchromium/nintendo_controller.ccNintendo_Switch_Reverse_Engineering/USB-HID-Notes.mdを元に解き明かしていくと、次のようになっていることがわかりました。

  • 80 0X: ChromiumからのUSB HID初期化要求
    • X=1: Macアドレス要求
    • X=2: ハンドシェイク
    • X=3: baudrate設定
    • X=4: USB HID通信開始
  • 81 0X: Pro ControllerからのUSB HID初期化応答
  • 01 XX: ChromiumからのUART要求
    • XX: カウンター
  • 21 XX: Pro ControllerからのUART応答+コントローラー入力
  • 30 XX: Pro Controllerからのコントローラー入力

UART要求に関しては、11バイト目からNintendo_Switch_Reverse_Engineering/bluetooth_hid_subcommands_notes.mdに記載のサブコマンドを送ることで、値の取得や設定を行っていました。

SwitchとPro Controllerをバイパス

次のようにRaspberry Pi 4とNintendo Switch、そしてPro Controllerを配線します。

bypass pro controller

Raspberry Pi 4には、ヒートシンク機能付きケースを付けてあります。 数あるヒートシンク機能付きケースの中でも、HATを固定できるねじ穴が上に出てるのがこの製品にした決め手です。

Amazon | Geekworm Raspberry pi 4(ラズベリーパイ4モデルB) CNC超薄型アルミ合金パッシブ冷却金属ケース、ラズパイ4モデルBのみに適用 | Geekworm | ベアボーンPC 通販

このとき、Raspberry Pi 4に接続したPro Controllerは、hidrawデバイスとして/dev/hidraw0にスペシャルファイルができます。 これに対してHIDのデータをファイルとして読み書きできます。

pi@raspberrypi:~ $ sudo dmesg | grep -A7 057e
[ 7201.091044] usb 1-1.3: New USB device found, idVendor=057e, idProduct=2009, bcdDevice= 2.00
[ 7201.091060] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 7201.091074] usb 1-1.3: Product: Pro Controller
[ 7201.091087] usb 1-1.3: Manufacturer: Nintendo Co., Ltd.
[ 7201.091099] usb 1-1.3: SerialNumber: 000000000001
[ 7201.112454] input: Nintendo Co., Ltd. Pro Controller as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.0/0003:057E:2009.0002/input/input1
[ 7201.114447] hid-generic 0003:057E:2009.0002: input,hidraw0: USB HID v1.11 Joystick [Nintendo Co., Ltd. Pro Controller] on usb-0000:01:00.0-1.3/input0

この/dev/hidraw0とconfigfsで作った/dev/hidg0を相互に繋げると、Nintendo SwitchとPro Controllerでやり取りする通信の間に割り込む事ができます。 割り込んで、URBデータをダンプしてみます。

これをroot権限で実行すると、Nintendo SwitchとPro Controllerの間でやり取りしているデータが流れてきます。 30 XXで始まるPro Controllerからの入力データが多すぎるので、それを非表示にして、初期化処理に絞ってみてみます。

この結果をNintendo_Switch_Reverse_Engineeringの資料を元にデコードすると、次のようにやり取りしていることがわかりました。 SPIの部分は、Nintendo_Switch_Reverse_Engineering/spi_flash_notes.mdを参考にしました。

Command SubCommand Description
08 05 - Disable USB HID Joystick report
08 01 - Request Mac Address
08 02 - Handshake
01 XX 03 [UART] Set input report mode: 48
08 04 - Enable USB HID Joystick report
01 XX 48 [UART] Enable vibration: False
01 XX 02 [UART] Request device info
01 XX 08 [UART] Set shipment low power state
01 XX 10 [SPI] “Serial number” Len: 16
01 XX 10 [SPI] “Controller Color” Len: 13
01 XX 01 [UART] Bluetooth manual pairing
01 XX 03 [UART] Set input report mode: 48
01 XX 04 [UART] Trigger buttons elapsed time
01 XX 10 [SPI] “Factory Sensor and Stick parameter” Len: 24
01 XX 10 [SPI] “Stick Data” Len: 18
01 XX 10 [SPI] “Analog sticks Calibration” Len: 24
01 XX 10 [SPI] “Factory configuration & calibration 2” Len: 25
01 XX 10 [SPI] “6-Axis Calibration” Len: 24
01 XX 40 [UART] Enable IMU: True
01 XX 48 [UART] Enable vibration: True
01 XX 21 [UART] Set NFC/IR MCU configuration: 33
01 XX 30 [UART] Set player lights: 1

最低限、初期化処理でこれらのやり取りが完了できれば、Pro ControllerとしてNintendo Switchが認識してくれるでしょう。

ダンプしたデータを流用し、対応する応答が返せるようにします。

入力データ

初期化処理の次は、入力データを紐解きます。 Pro Controllerからのボタンの入力データは、08 04 Enable USB HID Joystick reportがSwitchからPro Controllerに送られると、一秒間におよそ80回の周期で30 XXで始まるURBをPro Controllerが送りつけてくるようになります。

この30 XXで始まるデータは、前途の通りHID Report Descriptorで通知されている通りではないので、どういった定義で値が意味をなしているかを通信からは断定できません。 ですが、先のchromiumのnintendo_controllerのソースコードに、どのビットがどのボタンであるかなど、定義を読み取るれる実装がありました。

Bytes/Bits 7 6 5 4 3 2 1 0
0x00 0x30
0x01 timestamp
0x02 connection_info battery_level
0x03 ZR R SR(right) SL(right) A B X Y
0x04 Grip (none) Cap Home ThumbL ThumbR + -
0x05 ZL L SL(left) SR(left) Left Right Up Down
0x06 analog[0]
0x07 analog[1]
0x08 analog[2]
0x09 analog[3]
0x0a analog[4]
0x0b analog[5]

Raspberry Piでシミュレート

ここまで集めた情報でPro Controllerをシミュレートするに必要なものは揃いました。 これを元に、Raspberry Pi 4でPro Controllerをシミュレートできるかどうかを試してみます。

1.3inch LCD HATでの入力

まずは小さい構成で動くかどうかです。 入力はWavesharkのディスプレイ付きHATのボタン入力を使います。

1.3inch IPS LCD display HAT for Raspberry Pi, 240x240 pixels, SPI interface

connect Raspberry Pi to Switch

パッドの上下左右の入力はそのまま十字キーへ、押し込みを+、KEY1,KEY2,KEY3を順にA,B,Homeに割り当てます。 ついでにコントローラーの色を変えられるっぽかったので、Raspberry Piカラーにしてみました。 上の写真にも写ってる通り、USB接続として認識されたコントローラーのボディがラズベリーカラーで、ボタンが葉っぱグリーンになってます。

動かしてみると、期待通りちゃんとコントローラーとして認識され、操作できました。

Input from Raspberry Pi

スマホからの入力

あとはWi-Fi経由でスマホをRaspberry Piに接続し、入力をエミュレートすれば良いだけです。

バックエンドの言語はCで、ライブラリは、スマホとの通信にh2owslayを、JSONパーサーにjansson、USB Gadgetの作成と接続にlibusbgxを、USB Gadgetの監視にlibeventを用いました。 フロントエンドはHTML5+JavaScriptで、全画面表示のためにPWA技術を、コントローラーの描画にpixi.jsを用いました。

バックエンドをGoやRustなどのモダン言語を使わなかったのは、ちょっとまだ追加で実装したいものがある関係で、あえてCを選んだが故です。 ソースコードの公開も、その追加実装が終わってからかなぁと。暫しお待ちを。

追記(2020/05/09) やっぱりCで書くの辛くなってきたのでGoで書き直した。 mzyy94/nscon: Nintendo Switch Controller simulator written in go

実際に動作している様子がこちら。

まとめ

これでコントローラーが見つからなくてもスマホがあればどうぶつの森ができるようになりました。やったね。 まあスマホもよくなくすんですけど。