C++
ESP32
ESP-IDF
BluetoothClassic
btstack

ESP32とBluetoothコントローラーをHID(Bluetooth Classic)で接続する簡単な方法

前回の記事ではBLE(Bluetooth4)のコントローラを使用しましたが、
入手性が悪かった(Amazonでは売ってない)ので
Amazonで普通に売っているBluetooth3のコントローラーをESP32と接続します。

・ESP-IDFを導入する

こちらの記事を参考にESP-IDFを導入しましょう。

ESP-IDF ( ESP32 開発環境 ) の使い方 | mgo-tec電子工作
https://www.mgo-tec.com/esp32-idf-howto-01

・Btstackを導入する

ESP-IDFが導入出来たら任意のディレクトリ(homeディレクトリなど)で

git clone https://github.com/bluekitchen/btstack.git

を実行します。
参照:
https://bluekitchen-gmbh.com/btstack/quick_start/#getting-btstack-from-github

ダウンロードが終わったら
任意のディレクトリ/btstack/port/esp32で

./integrate_btstack.py

を実行するとexample以下にサンプルが作成されます

・コントローラーのアドレスを確認

ここで接続するコントローラーのアドレスを確認します

Bluetooth Profiles Scannerなどを使います
https://play.google.com/store/apps/details?id=com.sanji.jasper_hsieh.sdpscanner&hl=ja

DSC_0954.JPG

Discoverd ProfilesにHuman Interface Deviceが表示されることを確認します。
もし別のProfileが表示されるときはモードを変更しましょう。
たいていのコントローラーにはAndroid用、iPhone用、HID用などモードを変更する機能が内蔵されています。
確認出来たらアドレスをメモしておきます。

・hid_host_demoを使用する

/btstack/port/esp32/example/hid_host_demo/mainに移動しhid_host_demo.cを編集する

static const char * remote_addr_string = "E4:17:D8:16:47:23";

ここをメモしたアドレスに変更します。

BTキーボードを持っているならここで一度確認してみましょう。
アドレスをキーボードの物にして
キーボードを接続待機状態にしてhid_host_demoを実行すると繋がります。

DqVzl0KVsAAzZNl.jpg
(testと打ち込んだ状態)

この状態でコントローラーを接続すると
HID Connection established
と表示された後何も表示されませんが、ボタンを押すたびにpacket_handler()内のL2CAP_DATA_PACKETイベントが発生しているので処理を追加します。

        case L2CAP_DATA_PACKET:
            printf_hexdump(packet, size); // この処理を追加

そうするとボタンを押すたびに
A1 03 0F 7F 7F 7F 7F 00 00 00 00
等と表示されるのでボタンのコードを書き出しましょう。
(コントローラーによって違うと思われる)

DSC_0961.JPG

・ボタン処理を実装する

L2CAP_DATA_PACKET部分でコードを処理します。
自分は関数を作ってますがお好みでどうぞ。

呼び出し部分
        case L2CAP_DATA_PACKET:
            printf_hexdump(packet, size);
            decodeData(packet, size);

処理部分
const int INDEX_UP_DOWN = 4;
const uint8_t LEVER_UP = 0x00;    // 00000000
const uint8_t LEVER_DOWN = 0xFF;  // 11111111

const int INDEX_BUTTON = 9;
const uint8_t BUTTON_Y = 0x10;    // 00010000
const uint8_t BUTTON_A = 0x01;    // 00000001

void decodeData(const void *data, int size) {

    uint8_t upDown = ((uint8_t *)data)[INDEX_UP_DOWN];
    uint8_t button = ((uint8_t *)data)[INDEX_BUTTON];

    // 同時押し無し(十字ボタン)
    if (upDown == LEVER_UP) {
        printf("%02X ",upDown);
        printf("UP\n");
    }
    else if (upDown == LEVER_DOWN) {
        printf("%02X ",upDown);
        printf("DOWN\n");
    }

    // 同時押しあり
    if (button & BUTTON_Y) {
        printf("BUTTON Y(up)\n");
    }
    if (button & BUTTON_A) {
        printf("BUTTON A(down)\n");
    }
以下略

実際にラジコンに組み込んでみました。

以上です。

コントローラーについて

Amazonで2000円程度で売っているコントローラーで確認しています。

8Bitdo ゲームパッド (ZERO ブルー)
https://www.amazon.co.jp/dp/B071Z3XQ13

GameSir G3v ワイヤレス Bluetoothコントローラー
https://www.amazon.co.jp/dp/B01LYL229G/
※G3vは売り切れたようで類似品のG3sが表示されます。