Skip to content

Instantly share code, notes, and snippets.

@quietcricket
Last active December 11, 2019 17:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quietcricket/f0e9e2f6d71bc2407ea8e6ad54f74867 to your computer and use it in GitHub Desktop.
Save quietcricket/f0e9e2f6d71bc2407ea8e6ad54f74867 to your computer and use it in GitHub Desktop.
Setting up esp32 as a bluetooth keyboard. The BLE specifications are really complicated. Took a long time to make this work.
/*
Based on this gist https://gist.github.com/sabas1080/93115fb66e09c9b40e5857a19f3e7787
Minor modifications
*/
#include <BLEServer.h>
#include <BLEDevice.h>
#include <BLEHIDDevice.h>
#include <BLE2902.h>
BLEServer* pServer = NULL;
BLEHIDDevice* hid = NULL;
BLECharacteristic* input;
bool deviceConnected = false;
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(true);
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(false);
}
};
void createServer(void*) {
// Create the BLE Device
BLEDevice::init("TStudio2");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
hid = new BLEHIDDevice(pServer);
input = hid->inputReport(1);
hid->manufacturer()->setValue("TStudio");
hid->pnp(0x01, 0xe502, 0xa111, 0x0210); // <-- example pnp values
hid->hidInfo(0x00, 0x01);
hid->setBatteryLevel(8);
BLESecurity *pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
const uint8_t report[] = {
USAGE_PAGE(1), 0x01, // Generic Desktop Ctrls
USAGE(1), 0x06, // Keyboard
COLLECTION(1), 0x01, // Application
REPORT_ID(1), 0x01, // Report ID (1)
USAGE_PAGE(1), 0x07, // Kbrd/Keypad
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01, // 1 byte (Modifier)
REPORT_COUNT(1), 0x08,
HIDINPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position
REPORT_COUNT(1), 0x01, // 1 byte (Reserved)
REPORT_SIZE(1), 0x08,
HIDINPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
REPORT_COUNT(1), 0x06, // 6 bytes (Keys)
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65, // 101 keys
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
HIDINPUT(1), 0x00, // Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
REPORT_COUNT(1), 0x05, // 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x08, // LEDs
USAGE_MINIMUM(1), 0x01, // Num Lock
USAGE_MAXIMUM(1), 0x05, // Kana
HIDOUTPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
REPORT_COUNT(1), 0x01, // 3 bits (Padding)
REPORT_SIZE(1), 0x03,
HIDOUTPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
END_COLLECTION(0)
};
hid->reportMap((uint8_t*)report, sizeof(report));
hid->startServices();
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->setAppearance(HID_KEYBOARD);
pAdvertising->addServiceUUID(hid->hidService()->getUUID());
BLEDevice::startAdvertising();
delay(portMAX_DELAY);
}
void setup() {
Serial.begin(115200);
xTaskCreate(createServer, "server", 20000, NULL, 5, NULL);
}
void loop() {
if (deviceConnected) {
uint8_t a[] = {0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0};
input->setValue(a, sizeof(a));
input->notify();
uint8_t b[] = {0x0, 0x0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0};
input->setValue(b, sizeof(b));
input->notify();
delay(3000);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment