Help us understand the problem. What is going on with this article?

ESP32とBluetoothコントローラーをBLE HIDで接続する方法

More than 1 year has passed since last update.

※Arduino-ESP32 1.0.2当時の情報です※

ESP32とBluetoothコントローラーをBLE HIDで接続する方法(ESP32 1.0.3編) - Qiita
https://qiita.com/coppercele/items/57354f3e5a50ec7e0573
が最新ですのでご覧ください

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

Bluetooth 3.0(Bluetooth classic)で接続する場合はこちらへ

ESP32とBluetoothコントローラーをHID(Bluetooth Classic)で接続する簡単な方法 - Qiita
https://qiita.com/coppercele/items/b1df50cea8fa883fc692

コントローラーのHIDを確認

まずコントローラーのHIDがどうなっているのかを確認しましょう。

Androidならこのアプリを使ってHuman Interface DeviceのReport部分を確認します。

BLE Tool - Google Play のアプリ
https://play.google.com/store/apps/details?id=com.cozyoz.bletool

discriptors.gif

ここでReportが一個だけならBLE UUIDの変更のみでつながります(多分)
Reportが複数ある場合は以下の手順が必要です。

BLE_clientの編集

ESP32ライブラリのBLE_clientを使用します。

BLE UUIDをHIDとReportの物に変更します。

// UUID HID
static BLEUUID serviceUUID("00001812-0000-1000-8000-00805f9b34fb");
// UUID Report Charcteristic
static BLEUUID charUUID("00002a4d-0000-1000-8000-00805f9b34fb");

BLERemoteServiceの編集

ESP32ライブラリ内のBLERemoteService.cppを編集します

このアプリを使うとArduino C++スケッチを編集してスケッチの送信まで出来るので便利です。
http://eclipse.baeyens.it/stable.php?OS=Windows

void BLERemoteService::retrieveCharacteristics()メソッド内のMapにCharacteristicを格納する部分を変更します。
std::map m_characteristicMapByHandleというキーがhandleになっているMapがある(現状使われていない)ので
こちらにもCharacteristicを追加するようにします。

m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic));

m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic));
m_characteristicMapByHandle.insert(std::pair<uint16_t, BLERemoteCharacteristic*>(result.char_handle, pNewRemoteCharacteristic));

BLERemoteService::getCharacteristic(UUID)と
BLERemoteService::getCharacteristics()はm_characteristicMapByHandleに
対応していないのでBLERemoteService::getCharacteristics()をコピーして
BLERemoteService::getCharacteristicsByHandle()を追加します。

std::map<uint16_t, BLERemoteCharacteristic *> * BLERemoteService::getCharacteristicsByHandle() {

    if (!m_haveCharacteristics) {
        retrieveCharacteristics();
    }
    ESP_LOGD(LOG_TAG, "<< getCharacteristicsByHandle() for service: %s", getUUID().toString().c_str());
    return &m_characteristicMapByHandle;
} // getCharacteristicsByHandle

BLE_clientの編集

BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid)
はCharacteristicが複数ある事を想定していないので
std::map * BLERemoteService::getCharacteristicsByHandle()
でCharacteristicのMapを丸ごと取得してCharacteristic UUIDとPropertyなどを確認してNotifyに登録します。

BLE_client.connectToServer()内

    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.println(charUUID.toString().c_str());
      return false;
    }
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    std::string value = pRemoteCharacteristic->readValue();
    Serial.print("The characteristic value was: ");
    Serial.println(value.c_str());
   pRemoteCharacteristic->registerForNotify(notifyCallback);



    std::map<uint16_t, BLERemoteCharacteristic *> * pCharacteristicMap;
    pCharacteristicMap = pRemoteService->getCharacteristicsByHandle();
    // CharacteristicのMapを取得
    Serial.print("Number of Charactirstic: ");
    Serial.println(pCharacteristicMap->size());

    for (auto itr = pCharacteristicMap->begin();
            itr != pCharacteristicMap->end(); ++itr) {
        Serial.print("first(Handle): ");
        Serial.print(itr->first);
        Serial.print(" second(UUID):");
        Serial.println(itr->second->getUUID().toString().c_str());

        if (charUUID.toString() == itr->second->getUUID().toString()) {
        // Characteristic UUIDをチェック
            Serial.print("CharUUID matched: ");
            Serial.println(itr->second->getUUID().toString().c_str());

            Serial.print("Correct : ");
            pRemoteCharacteristic = itr->second;
                // Notifyに登録
                pRemoteCharacteristic->registerForNotify(notifyCallback);

        }

    }

まずは複数あるPropertyを全部Notifyに登録します。
不都合があればHandleを調べて除外しましょう。

接続がうまくいくとボタンを押すたびにnotifyCallback()が実行されてデータが送られてきます。
Notify callback for characteristic 00002a4d-0000-1000-8000-00805f9b34fb of data length 2
Data : 0000

自分が使ってるコントローラーは16bitでデータを送ってくるのでこのように処理しています。

        // *pDataはuint8_t*
        int data = *pData;
        data = data << 8;
        data += *(pData + 1);
        // 16bit intに結合

        sprintf(str, "%04x", data);
        Serial.print(str);
        Serial.print(" ");
        // 以下キーコード別の処理
        decodeData(data);
const uint16_t LEVER_UP = 0x0040;    // 00000000 01000000
const uint16_t LEVER_DOWN = 0x0080;  // 00000000 10000000

static void decodeData(int data) {
    if (data & LEVER_UP) {
        if (data & LEVER_DOWN) {
            Serial.println("DOWN");
        }
        else {
            Serial.println("UP");
        }
    }
    else if (leftMoving) {
        leftStop();
    }
    if (data & LEVER_LEFT) {
        if (data & LEVER_RIGHT) {
            Serial.println("RIGHT");
        }
        else {
            Serial.println("LEFT");
        }
    }
    if (data & BUTTON_A) {
        Serial.println("A");
    }
    if (data & BUTTON_B) {
        Serial.println("B");
    }
以下略

以上です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away