Created
January 15, 2025 00:04
-
-
Save morganabc/da35d7a3b045d59741e328a7867a14ea to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "BLEDevice.h" | |
| #include "BLEHIDDevice.h" | |
| #include "HIDTypes.h" | |
| #define DEVICE_NAME "ESP32 Mouse" | |
| #define BLE_MANUFACTURER "TinyUSB" | |
| BLEHIDDevice* hid; | |
| BLECharacteristic* input; | |
| BLECharacteristic* output; | |
| bool isBleConnected = false; | |
| #define MOUSE_LEFT 1 | |
| #define MOUSE_RIGHT 2 | |
| #define MOUSE_MIDDLE 4 | |
| struct InputReport { | |
| uint8_t buttons; | |
| int8_t x; | |
| int8_t y; | |
| int8_t w; | |
| int8_t hw; | |
| }; | |
| void setup() { | |
| Serial.begin(115200); | |
| Serial2.begin(115200, SERIAL_8N1, 22, 23); | |
| xTaskCreate(bluetoothTask, "bluetooth", 20000, NULL, 5, NULL); | |
| } | |
| void loop() { | |
| while (Serial2.available()) { | |
| String uartData = Serial2.readStringUntil('\n'); | |
| if (uartData.startsWith("REPORT: ")) { | |
| int r, m, l, w, x, y; | |
| sscanf(uartData.c_str(), "REPORT: BTN %d %d %d WHEEL %d X %d Y %d", &l, &m, &r, &w, &x, &y); | |
| uint8_t button = 0; | |
| if (r) button |= MOUSE_RIGHT; | |
| else button &= ~MOUSE_RIGHT; | |
| if (m) button |= MOUSE_MIDDLE; | |
| else button &= ~MOUSE_MIDDLE; | |
| if (l) button |= MOUSE_LEFT; | |
| else button &= ~MOUSE_LEFT; | |
| InputReport report = { | |
| .buttons = button, | |
| .x = x, | |
| .y = y, | |
| .w = w, | |
| .hw = 0 | |
| }; | |
| if (isBleConnected) { | |
| input->setValue((uint8_t*)&report, sizeof(report)); | |
| input->notify(); | |
| } | |
| } | |
| // Serial.println(uartData); | |
| } | |
| } | |
| static const uint8_t _hidReportDescriptor[] = { | |
| USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) | |
| USAGE(1), 0x02, // USAGE (Mouse) | |
| COLLECTION(1), 0x01, // COLLECTION (Application) | |
| USAGE(1), 0x01, // USAGE (Pointer) | |
| COLLECTION(1), 0x00, // COLLECTION (Physical) | |
| // ------------------------------------------------- Buttons (Left, Right, Middle, Back, Forward) | |
| USAGE_PAGE(1), 0x09, // USAGE_PAGE (Button) | |
| USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (Button 1) | |
| USAGE_MAXIMUM(1), 0x05, // USAGE_MAXIMUM (Button 5) | |
| LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) | |
| LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) | |
| REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) | |
| REPORT_COUNT(1), 0x05, // REPORT_COUNT (5) | |
| HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;5 button bits | |
| // ------------------------------------------------- Padding | |
| REPORT_SIZE(1), 0x03, // REPORT_SIZE (3) | |
| REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) | |
| HIDINPUT(1), 0x03, // INPUT (Constant, Variable, Absolute) ;3 bit padding | |
| // ------------------------------------------------- X/Y position, Wheel | |
| USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) | |
| USAGE(1), 0x30, // USAGE (X) | |
| USAGE(1), 0x31, // USAGE (Y) | |
| USAGE(1), 0x38, // USAGE (Wheel) | |
| LOGICAL_MINIMUM(1), 0x81, // LOGICAL_MINIMUM (-127) | |
| LOGICAL_MAXIMUM(1), 0x7f, // LOGICAL_MAXIMUM (127) | |
| REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) | |
| REPORT_COUNT(1), 0x03, // REPORT_COUNT (3) | |
| HIDINPUT(1), 0x06, // INPUT (Data, Variable, Relative) ;3 bytes (X,Y,Wheel) | |
| // ------------------------------------------------- Horizontal wheel | |
| USAGE_PAGE(1), 0x0c, // USAGE PAGE (Consumer Devices) | |
| USAGE(2), 0x38, 0x02, // USAGE (AC Pan) | |
| LOGICAL_MINIMUM(1), 0x81, // LOGICAL_MINIMUM (-127) | |
| LOGICAL_MAXIMUM(1), 0x7f, // LOGICAL_MAXIMUM (127) | |
| REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) | |
| REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) | |
| HIDINPUT(1), 0x06, // INPUT (Data, Var, Rel) | |
| END_COLLECTION(0), // END_COLLECTION | |
| END_COLLECTION(0) // END_COLLECTION | |
| }; | |
| class BleHIDCallbacks : public BLEServerCallbacks { | |
| void onConnect(BLEServer* server) { | |
| isBleConnected = true; | |
| BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); | |
| cccDesc->setNotifications(true); | |
| Serial.println("CONNECTED"); | |
| } | |
| void onDisconnect(BLEServer* server) { | |
| isBleConnected = false; | |
| BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); | |
| cccDesc->setNotifications(false); | |
| Serial.println("DISCONNECTED"); | |
| } | |
| }; | |
| void bluetoothTask(void*) { | |
| BLEDevice::init(DEVICE_NAME); | |
| BLEServer* server = BLEDevice::createServer(); | |
| server->setCallbacks(new BleHIDCallbacks()); | |
| hid = new BLEHIDDevice(server); | |
| input = hid->inputReport(0); | |
| hid->manufacturer()->setValue(BLE_MANUFACTURER); | |
| hid->pnp(0x02, 0xe502, 0xa111, 0x0210); | |
| hid->hidInfo(0x00, 0x02); | |
| BLESecurity* security = new BLESecurity(); | |
| security->setAuthenticationMode(ESP_LE_AUTH_BOND); | |
| hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor)); | |
| hid->startServices(); | |
| hid->setBatteryLevel(100); | |
| BLEAdvertising* advertising = server->getAdvertising(); | |
| advertising->setAppearance(HID_MOUSE); | |
| advertising->addServiceUUID(hid->hidService()->getUUID()); | |
| advertising->addServiceUUID(hid->deviceInfo()->getUUID()); | |
| advertising->addServiceUUID(hid->batteryService()->getUUID()); | |
| advertising->start(); | |
| Serial.println("BLE READY"); | |
| delay(portMAX_DELAY); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment