※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
ここで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");
}
以下略
#ESP32 とBTゲームパッドをBLE HIDで接続してラジコンを直接操作することに成功しました\(^o^)/
— もけ@ムギ㌠ (@coppercele) 2018年10月4日
HIDで直接通信してるのでシンプルに通信できるのがいい感じ!#arduino pic.twitter.com/TS8BR4nHn6
以上です。