diff --git a/BleConnectionStatus.cpp b/BleConnectionStatus.cpp deleted file mode 100644 index 1b8bcad..0000000 --- a/BleConnectionStatus.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "BleConnectionStatus.h" - -BleConnectionStatus::BleConnectionStatus(void) { -} - -void BleConnectionStatus::onConnect(BLEServer* pServer) -{ - this->connected = true; - BLE2902* desc = (BLE2902*)this->inputKeyboard->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); - desc->setNotifications(true); - - desc = (BLE2902*)this->inputMediaKeys->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); - desc->setNotifications(true); -} - -void BleConnectionStatus::onDisconnect(BLEServer* pServer) -{ - this->connected = false; - BLE2902* desc = (BLE2902*)this->inputKeyboard->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); - desc->setNotifications(false); - - desc = (BLE2902*)this->inputMediaKeys->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); - desc->setNotifications(false); - pAdvertising->start(); -} diff --git a/BleConnectionStatus.h b/BleConnectionStatus.h deleted file mode 100644 index 67cd42a..0000000 --- a/BleConnectionStatus.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ESP32_BLE_CONNECTION_STATUS_H -#define ESP32_BLE_CONNECTION_STATUS_H -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include -#include "BLE2902.h" -#include "BLECharacteristic.h" - -class BleConnectionStatus : public BLEServerCallbacks -{ -public: - BleConnectionStatus(void); - bool connected = false; - void onConnect(BLEServer* pServer); - void onDisconnect(BLEServer* pServer); - BLECharacteristic* inputKeyboard; - BLECharacteristic* outputKeyboard; - BLECharacteristic* inputMediaKeys; - BLEAdvertising *pAdvertising; -}; - -#endif // CONFIG_BT_ENABLED -#endif // ESP32_BLE_CONNECTION_STATUS_H diff --git a/BleKeyboard.cpp b/BleKeyboard.cpp index 007ce05..8b77b98 100644 --- a/BleKeyboard.cpp +++ b/BleKeyboard.cpp @@ -1,14 +1,19 @@ +#if defined(USE_NIMBLE) +#include +#include +#include +#include +#else #include #include #include #include "BLE2902.h" #include "BLEHIDDevice.h" +#endif // USE_NIMBLE #include "HIDTypes.h" #include #include "sdkconfig.h" -#include "BleConnectionStatus.h" -#include "KeyboardOutputCallbacks.h" #include "BleKeyboard.h" #if defined(CONFIG_ARDUHAL_ESP_LOG) @@ -89,17 +94,47 @@ static const uint8_t _hidReportDescriptor[] = { END_COLLECTION(0) // END_COLLECTION }; -BleKeyboard::BleKeyboard(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) : hid(0) -{ - this->deviceName = deviceName; - this->deviceManufacturer = deviceManufacturer; - this->batteryLevel = batteryLevel; - this->connectionStatus = new BleConnectionStatus(); -} +BleKeyboard::BleKeyboard(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) + : hid(0) + , deviceName(std::string(deviceName).substr(0, 15)) + , deviceManufacturer(std::string(deviceManufacturer).substr(0,15)) + , batteryLevel(batteryLevel) {} void BleKeyboard::begin(void) { - xTaskCreate(this->taskServer, "server", 20000, (void *)this, 5, NULL); + BLEDevice::init(deviceName); + BLEServer* pServer = BLEDevice::createServer(); + pServer->setCallbacks(this); + + hid = new BLEHIDDevice(pServer); + inputKeyboard = hid->inputReport(KEYBOARD_ID); // <-- input REPORTID from report map + outputKeyboard = hid->outputReport(KEYBOARD_ID); + inputMediaKeys = hid->inputReport(MEDIA_KEYS_ID); + + outputKeyboard->setCallbacks(this); + + hid->manufacturer()->setValue(deviceManufacturer); + + hid->pnp(0x02, 0xe502, 0xa111, 0x0210); + hid->hidInfo(0x00, 0x01); + + BLESecurity* pSecurity = new BLESecurity(); + + pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND); + + hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor)); + hid->startServices(); + + onStarted(pServer); + + advertising = pServer->getAdvertising(); + advertising->setAppearance(HID_KEYBOARD); + advertising->addServiceUUID(hid->hidService()->getUUID()); + advertising->setScanResponse(false); + advertising->start(); + hid->setBatteryLevel(batteryLevel); + + ESP_LOGD(LOG_TAG, "Advertising started!"); } void BleKeyboard::end(void) @@ -107,7 +142,7 @@ void BleKeyboard::end(void) } bool BleKeyboard::isConnected(void) { - return this->connectionStatus->connected; + return this->connected; } void BleKeyboard::setBatteryLevel(uint8_t level) { @@ -121,45 +156,13 @@ void BleKeyboard::setName(std::string deviceName) { this->deviceName = deviceName; } -void BleKeyboard::taskServer(void* pvParameter) { - BleKeyboard* bleKeyboardInstance = (BleKeyboard *) pvParameter; //static_cast(pvParameter); - BLEDevice::init(bleKeyboardInstance->deviceName); - BLEServer *pServer = BLEDevice::createServer(); - pServer->setCallbacks(bleKeyboardInstance->connectionStatus); - - bleKeyboardInstance->hid = new BLEHIDDevice(pServer); - bleKeyboardInstance->inputKeyboard = bleKeyboardInstance->hid->inputReport(KEYBOARD_ID); // <-- input REPORTID from report map - bleKeyboardInstance->outputKeyboard = bleKeyboardInstance->hid->outputReport(KEYBOARD_ID); - bleKeyboardInstance->inputMediaKeys = bleKeyboardInstance->hid->inputReport(MEDIA_KEYS_ID); - bleKeyboardInstance->connectionStatus->inputKeyboard = bleKeyboardInstance->inputKeyboard; - bleKeyboardInstance->connectionStatus->outputKeyboard = bleKeyboardInstance->outputKeyboard; - bleKeyboardInstance->connectionStatus->inputMediaKeys = bleKeyboardInstance->inputMediaKeys; - - bleKeyboardInstance->outputKeyboard->setCallbacks(new KeyboardOutputCallbacks()); - - bleKeyboardInstance->hid->manufacturer()->setValue(bleKeyboardInstance->deviceManufacturer); - - bleKeyboardInstance->hid->pnp(0x02, 0xe502, 0xa111, 0x0210); - bleKeyboardInstance->hid->hidInfo(0x00,0x01); - - BLESecurity *pSecurity = new BLESecurity(); - - pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND); - - bleKeyboardInstance->hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor)); - bleKeyboardInstance->hid->startServices(); - - bleKeyboardInstance->onStarted(pServer); - - bleKeyboardInstance->connectionStatus->pAdvertising = pServer->getAdvertising(); - bleKeyboardInstance->connectionStatus->pAdvertising->setAppearance(HID_KEYBOARD); - bleKeyboardInstance->connectionStatus->pAdvertising->addServiceUUID(bleKeyboardInstance->hid->hidService()->getUUID()); - bleKeyboardInstance->connectionStatus->pAdvertising->setScanResponse(false); - bleKeyboardInstance->connectionStatus->pAdvertising->start(); - bleKeyboardInstance->hid->setBatteryLevel(bleKeyboardInstance->batteryLevel); - - ESP_LOGD(LOG_TAG, "Advertising started!"); - vTaskDelay(portMAX_DELAY); //delay(portMAX_DELAY); +/** + * @brief Sets the waiting time (in milliseconds) between multiple keystrokes in NimBLE mode. + * + * @param ms Time in milliseconds + */ +void BleKeyboard::setDelay(uint32_t ms) { + this->_delay_ms = ms; } void BleKeyboard::sendReport(KeyReport* keys) @@ -168,7 +171,11 @@ void BleKeyboard::sendReport(KeyReport* keys) { this->inputKeyboard->setValue((uint8_t*)keys, sizeof(KeyReport)); this->inputKeyboard->notify(); - } +#if defined(USE_NIMBLE) + // vTaskDelay(delayTicks); + this->delay_ms(_delay_ms); +#endif // USE_NIMBLE + } } void BleKeyboard::sendReport(MediaKeyReport* keys) @@ -177,7 +184,11 @@ void BleKeyboard::sendReport(MediaKeyReport* keys) { this->inputMediaKeys->setValue((uint8_t*)keys, sizeof(MediaKeyReport)); this->inputMediaKeys->notify(); - } +#if defined(USE_NIMBLE) + //vTaskDelay(delayTicks); + this->delay_ms(_delay_ms); +#endif // USE_NIMBLE + } } extern @@ -466,3 +477,31 @@ size_t BleKeyboard::write(const uint8_t *buffer, size_t size) { } return n; } + +void BleKeyboard::onConnect(BLEServer* pServer) { + this->connected = true; +} + +void BleKeyboard::onDisconnect(BLEServer* pServer) { + this->connected = false; +#if !defined(USE_NIMBLE) + advertising->start(); +#endif // !USE_NIMBLE +} + +void BleKeyboard::onWrite(BLECharacteristic* me) { + uint8_t* value = (uint8_t*)(me->getValue().c_str()); + (void)value; + ESP_LOGI(LOG_TAG, "special keys: %d", *value); +} + +void BleKeyboard::delay_ms(uint64_t ms) { + uint64_t m = esp_timer_get_time(); + if(ms){ + uint64_t e = (m + (ms * 1000)); + if(m > e){ //overflow + while(esp_timer_get_time() > e) { } + } + while(esp_timer_get_time() < e) {} + } +} \ No newline at end of file diff --git a/BleKeyboard.h b/BleKeyboard.h index 678886d..4fdeaa5 100644 --- a/BleKeyboard.h +++ b/BleKeyboard.h @@ -3,9 +3,26 @@ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) -#include "BleConnectionStatus.h" +#if defined(USE_NIMBLE) + +#include "NimBLECharacteristic.h" +#include "NimBLEHIDDevice.h" + +#define BLEDevice NimBLEDevice +#define BLEServerCallbacks NimBLEServerCallbacks +#define BLECharacteristicCallbacks NimBLECharacteristicCallbacks +#define BLEHIDDevice NimBLEHIDDevice +#define BLECharacteristic NimBLECharacteristic +#define BLEAdvertising NimBLEAdvertising +#define BLEServer NimBLEServer + +#else + #include "BLEHIDDevice.h" #include "BLECharacteristic.h" + +#endif // USE_NIMBLE + #include "Print.h" @@ -86,19 +103,25 @@ typedef struct uint8_t keys[6]; } KeyReport; -class BleKeyboard : public Print +class BleKeyboard : public Print, public BLEServerCallbacks, public BLECharacteristicCallbacks { private: - BleConnectionStatus* connectionStatus; BLEHIDDevice* hid; BLECharacteristic* inputKeyboard; BLECharacteristic* outputKeyboard; BLECharacteristic* inputMediaKeys; - KeyReport _keyReport; - MediaKeyReport _mediaKeyReport; - static void taskServer(void* pvParameter); + BLEAdvertising* advertising; + KeyReport _keyReport; + MediaKeyReport _mediaKeyReport; + std::string deviceName; + std::string deviceManufacturer; + uint8_t batteryLevel; + bool connected = false; + uint32_t _delay_ms = 7; + void delay_ms(uint64_t ms); + public: - BleKeyboard(std::string deviceName = "ESP32 BLE Keyboard", std::string deviceManufacturer = "Espressif", uint8_t batteryLevel = 100); + BleKeyboard(std::string deviceName = "ESP32 Keyboard", std::string deviceManufacturer = "Espressif", uint8_t batteryLevel = 100); void begin(void); void end(void); void sendReport(KeyReport* keys); @@ -114,11 +137,13 @@ public: bool isConnected(void); void setBatteryLevel(uint8_t level); void setName(std::string deviceName); - uint8_t batteryLevel; - std::string deviceManufacturer; - std::string deviceName; + void setDelay(uint32_t ms); protected: virtual void onStarted(BLEServer *pServer) { }; + virtual void onConnect(BLEServer* pServer) override; + virtual void onDisconnect(BLEServer* pServer) override; + virtual void onWrite(BLECharacteristic* me) override; + }; #endif // CONFIG_BT_ENABLED diff --git a/KeyboardOutputCallbacks.cpp b/KeyboardOutputCallbacks.cpp deleted file mode 100644 index 286ce41..0000000 --- a/KeyboardOutputCallbacks.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "KeyboardOutputCallbacks.h" - -#if defined(CONFIG_ARDUHAL_ESP_LOG) - #include "esp32-hal-log.h" - #define LOG_TAG "" -#else - #include "esp_log.h" - static const char* LOG_TAG = "BLEDevice"; -#endif - -KeyboardOutputCallbacks::KeyboardOutputCallbacks(void) { -} - -void KeyboardOutputCallbacks::onWrite(BLECharacteristic* me) { - uint8_t* value = (uint8_t*)(me->getValue().c_str()); - ESP_LOGI(LOG_TAG, "special keys: %d", *value); -} - diff --git a/KeyboardOutputCallbacks.h b/KeyboardOutputCallbacks.h deleted file mode 100644 index bce158e..0000000 --- a/KeyboardOutputCallbacks.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ESP32_BLE_KEYBOARD_OUTPUT_CALLBACKS_H -#define ESP32_BLE_KEYBOARD_OUTPUT_CALLBACKS_H -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include -#include "BLE2902.h" -#include "BLECharacteristic.h" - -class KeyboardOutputCallbacks : public BLECharacteristicCallbacks -{ -public: - KeyboardOutputCallbacks(void); - void onWrite(BLECharacteristic* me); -}; - -#endif // CONFIG_BT_ENABLED -#endif // ESP32_BLE_KEYBOARD_OUTPUT_CALLBACKS_H diff --git a/README.md b/README.md index 44429e8..eb7ab98 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,48 @@ Instead of `BleKeyboard bleKeyboard;` you can do `BleKeyboard bleKeyboard("Bluet The third parameter is the initial battery level of your device. To adjust the battery level later on you can simply call e.g. `bleKeyboard.setBatteryLevel(50)` (set battery level to 50%). By default the battery level will be set to 100%, the device name will be `ESP32 Bluetooth Keyboard` and the manufacturer will be `Espressif`. +## NimBLE-Mode +The NimBLE mode enables a significant saving of RAM and FLASH memory. + +### Comparison (SendKeyStrokes.ino at compile-time) + +**Standard** +``` +RAM: [= ] 9.3% (used 30548 bytes from 327680 bytes) +Flash: [======== ] 75.8% (used 994120 bytes from 1310720 bytes) +``` + +**NimBLE mode** +``` +RAM: [= ] 8.3% (used 27180 bytes from 327680 bytes) +Flash: [==== ] 44.2% (used 579158 bytes from 1310720 bytes) +``` + +### Comparison (SendKeyStrokes.ino at run-time) + +| | Standard | NimBLE mode | difference +|---|--:|--:|--:| +| `ESP.getHeapSize()` | 296.804 | 321.252 | **+ 24.448** | +| `ESP.getFreeHeap()` | 143.572 | 260.764 | **+ 117.192** | +| `ESP.getSketchSize()` | 994.224 | 579.264 | **- 414.960** | + +### How to activate NimBLE mode? + +ArduinoIDE: Before including the library, insert the line `#define USE_NIMBLE` +```C++ +#define USE_NIMBLE +#include +``` + +PlatformIO: Change your `platformio.ini` to the following settings +```ini +lib_deps = + NimBLE-Arduino + +build-flags = + -D USE_NIMBLE +``` + ## Credits Credits to [chegewara](https://github.com/chegewara) and [the authors of the USB keyboard library](https://github.com/arduino-libraries/Keyboard/) as this project is heavily based on their work! Also, credits to [duke2421](https://github.com/T-vK/ESP32-BLE-Keyboard/issues/1) who helped a lot with testing, debugging and fixing the device descriptor!