LoginSignup
21
15

More than 3 years have passed since last update.

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

Last updated at Posted at 2018-10-07

※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");
    }
以下略

以上です。

21
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
15