Edited at

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


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

以上です。