M5Stackをゲームコントローラーにする方法

## [GameControllerizer](https://sites.google.com/view/gamecontrollerizer)って？
GameControllerize（以下G.C)は、専用基板とビジュアルプログラミング環境からなるミドルウエアで、デジタルゲームへの操作入力を自在にハックできます。
基本的には、Node-Redや、MakeCodeで開発が可能ですが、UARTでも直接制御が可能なので、備忘録としてまとめてます。


### [G.C専用基板](https://sites.google.com/view/gamecontrollerizer/board)について
汎用タイプと、micro:bit専用タイプの２種類が存在しています。
汎用基板は、Raspberry Pi Zeroとマウントできる作りになっており、Groveコネクタも装備されています。
今回は、このGrove端子を用いてM5Stackと連携します。


| 汎用タイプ　（GC-GP）  | micro:bit専用タイプ　（GC-MB） |
|---|---|
| <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/e91064c2-bc30-33d6-fb30-dc44de060734.png" width="60%"/> |  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/53812a50-38d8-b562-2767-ebbbadda0c06.png" width="60%"/> |

※参照）https://sites.google.com/view/gamecontrollerizer/board より


### UART Protocol

#### コマンド情報

UARTで制御するためのコマンドの一部を以下に掲載します。
他にもあるのですが、使ったことないので今回は割愛

基本的には、
**1byte**目の種類、コマンド設定
**2 byte**目の間隔
**3 / 4byte**目の制御情報の合計`4byte`のデータを送信します。

| Byte  | 説明 |
|---|---|
|1| 制御コマンド （ [7:4] デバイス種類  / [3:0] 指定コマンド )|
|2| 間隔|
|3| 操作情報　|
|4| 操作情報　|


##### 制御コマンド
制御コマンドは、以下のデバイス種類と、どのキーを操作するかの指定コマンドを組み合わせて利用します。
例えばゲームパッドで十字キーの場合は、`0xC0`
ボタンの場合は、 `0xC1`が制御コマンドになります。

###### デバイス種類

G.Cがシュミレートするデバイスの種類を設定します。

| 値  | 説明 |
|---|---|
| 0xC| ゲームパッド |

###### 指定コマンド
どのボタンを操作するかを指定します。
ここでは説明しませんが、アナログのスティックも制御可能です。

| 値  | 説明 |
|---|---|
| 0x0 | 十字キー上書き |
| 0x1 | ボタン上書き |
| 0x2 | ボタン設定 |
| 0x3 | ボタン解除 |

 **上書き**と、**設定**の違いについて
`ボタン設定(0x2)`は、ボタンひとつひとつに対して`ON`を設定することができます。
`OFF`にする場合は`ボタン解除(0x3)`を指定します。
`ボタン上書き(0x1)`は、すべてのボタンに対して`ON/OFF`を設定します。

				
##### 間隔

どれだけボタンを押し続けるかを設定するためのパラメータです。
格闘コマンドのように時間差でボタンを入力が必要な場合は、`Push(1~127)`　の時間の制御を
十字キーや、ボタンを同時押ししたい場合は、`Chain(0)`を
ずっと押し続けたい場合は、`Hold(-1)`を設定します。

ちなみに、`Push(1~127)`を使用する場合、最低でも2~3を使用しないと反応しないゲームがほとんどのようです

| 値  | 情報 |説明 |
|---|---|---|
| 1~127| Push| 指定期間だけ適用して、次の処理に移る |
| -1| Hold | 次のコマンドが来るまで押し続ける|
| 0 | Chain | これ以降のPush/Holdがきた時点で適用される |


##### 操作情報(十字キー）

十字キーの場合に使用する、各位置対応する以下の値を3byte目に設定します。
4byte目は設定する情報がないので`０`を設定。

>注意： 十字キーに同時押しは存在しません。ひとつのキーのみ設定可能
> 一般的な十字キーの場合、物理的な制約で右ボタンと左ボタンは同時に押せない

 <table>
    <tr>
      <td>7 </td>
      <td>8</td>
      <td>9</td>
    </tr>
    <tr>
      <td>4</td>
      <td>5</td>
      <td>6</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>

 </table>


##### 操作情報（ボタン）
ボタンは、最大16個のボタンまで制御可能です。
ただし、デバイス側で認識するボタンがない場合は、入力が無視されます。

0~7番目のボタンの状態を3byte目に、 8~15番目のボタンの状態を4byte目に設定します。
また、設定の意味は、指定コマンドにより変わってきます。

**設定 / 解除モード時**
設定モード時、各ビットで**１**の箇所のボタンが`ON`になります。０の場所は状態の変更はありません。
解除モード時、各ビットで**１**の箇所のボタンが`OFF`になります。０の場所は状態の変更はありません。
　 　
**上書き時**
各ビット毎が**１**の場合、ボタンが`ON`、**0**の場合は、ボタンの`OFF`が設定されます。 

例）
12番目のボタンと、3番目のボタンをONにする場合
3byte目: 0x04(00000100)
4byte目: 0x08（00001000）


## 十字キーを制御してみる

ゲームパッドで十字キーを制御してみます。

ここでは、右キーを押し続けるコマンドを作ってみたいと思います。

まず1byte目には、ゲームパッドの十字キーを制御する `0xC0`が設定します。
2byte目は、ボタンの押し方です。押し続けるので、`-1`を設定
3byte目には、十字キーの方向が設定され、右の場合は、 `6`が設定されてます。
4byte目は、設定項目がないので、`0`を設定します。

実際のコードにする以下になります。
```C
  //Groveポートの制御開始
  Serial2.begin(115200, SERIAL_8N1, 32, 33);

  // コマンド作成　
  byte cmd[4];
  cmd[0] = 0xc0;  // 十字キー制御
  cmd[1] = -1;    // 状態を維持
  cmd[2] = 6;     // 右キー
  cmd[3] = 0;     // 設定なし

  // G.Cにコマンド送信
  Serial2.write(cmd, 4);
```


## ボタンを制御してみる

次にボタンを制御してみます。

ここでは、２つのボタン（1番と２番のボタン）を同時に押してみたいと思います。

まず1byte目には、ゲームパッドの十字キーを制御する `0xC1`が設定します。

2byte目は、ボタンの押し方です。押し続けるので、`-1`を設定
3byte目には、`0x03 (00000011）`を設定
＊上書きなので、０の項目はボタンが`OFF`に設定されます。
＊もし設定の場合は、指定された項目のみ`ON`になります（0は変化なし）

4byte目は、今回は、設定項目がないので、`0`を設定します。

実際のコードにする以下になります。
```C
  //Groveポートの制御開始
  Serial2.begin(115200, SERIAL_8N1, 32, 33);

  // コマンド作成　
  byte cmd[4];
  cmd[0] = 0xc1;  // 十字キー制御
  cmd[1] = -1;    // 状態を維持
  cmd[2] = 3;     // 1番と2番ボタンをON、3~7番ボタンはOFF
  cmd[3] = 0;     // 8~16番ボタンをOFF

  // G.Cにコマンド送信
  Serial2.write(cmd, 4);
```

## 　ボタンと十字キーを同時に制御してみる

最後に十字キーとボタンを制御してみます。

基本的には先ほど同じように十字キーと、ボタンの制御コマンドを作成します。
しかし別々にG.Cにデータを送る必要があるため同時に送る場合は、`間隔をChain（0)`にする必要があります。
そして有効にしたいコマンドで、間隔のパラメータを指定します。


```C
  //Groveポートの制御開始
  Serial2.begin(115200, SERIAL_8N1, 32, 33);

  // 十字キーのコマンド作成　
  byte cmd[4];
  cmd[0] = 0xc0; // 十字キー制御
  cmd[1] = 0;    // Chain状態に設定
  cmd[2] = 6;    // 右キー
  cmd[3] = 0;
  // G.Cにコマンド送信
  Serial2.write(cmd, 4);

  // ボタン用のコマンド作成　
  cmd[0] = 0xc1;  // 十字キー制御
  cmd[1] = -1;    // 状態を維持
  cmd[2] = 1;     // 1番をON、2~7番ボタンはOFF
  cmd[3] = 0;     // 8~16番ボタンをOFF
  // G.Cにコマンド送信
  Serial2.write(cmd, 4);

```


## 最後に
触りだけの説明でしたが、簡単に使えることは気づいていただけたのではないかなと思います。
UARTで直接制御しましたが、ビジュアルプログラミングでも簡単に利用できます。

GameControllerizerを使えば手軽に独自のゲームコントローラーを作ることができます。
あとはアイデア次第、興味があればぜひ使ってみてください。

https://protopedia.net/material/445