diff --git a/mouse/ESP32-BLE-Mouse-master.zip b/mouse/ESP32-BLE-Mouse-master.zip index 70c4ff4..1b62808 100644 Binary files a/mouse/ESP32-BLE-Mouse-master.zip and b/mouse/ESP32-BLE-Mouse-master.zip differ diff --git a/mouse/LedControl.cpp b/mouse/LedControl.cpp new file mode 100644 index 0000000..b2f046e --- /dev/null +++ b/mouse/LedControl.cpp @@ -0,0 +1,120 @@ +#include "LedControl.h" +#include + +void LedControl::begin() { + rgbLed.begin(); + loadSettings(); + applyColor(); +} + +// Вспомогательная функция для создания дескриптора с описанием +BLEDescriptor* createUserDescription(const char* description) { + BLEDescriptor* desc = new BLEDescriptor(BLEUUID((uint16_t)0x2901)); + desc->setValue(description); + return desc; +} + +// Вспомогательная функция для создания дескриптора формата uint8 +BLEDescriptor* createPresentationFormatDescriptor() { + // Формат Presentation Format Descriptor (0x2904) + // Format: uint8 (0x04), Exponent: 0, Unit: unitless (0x2700), Namespace: Bluetooth SIG (1), Description: 0 + uint8_t presentationFormat[7] = { + 0x04, // Format: uint8 + 0x00, // Exponent + 0x00, 0x27, // Unit (unitless) - обратите внимание на порядок байт: младший сначала + 0x01, // Namespace (Bluetooth SIG) + 0x00, 0x00 // Description + }; + BLEDescriptor* desc = new BLEDescriptor(BLEUUID((uint16_t)0x2904)); + desc->setValue(presentationFormat, sizeof(presentationFormat)); + return desc; +} +void LedControl::setupBLEService(BLEServer *server) { + BLEService *colorService = server->createService(COLOR_SERVICE_UUID); + + // --- Красный --- + BLECharacteristic *rChar = colorService->createCharacteristic( + COLOR_CHAR_R_UUID, + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE + ); + rChar->setAccessPermissions(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE); + rChar->setValue(currentR); + rChar->setCallbacks(new ColorCallbacks(this, 0)); + // rChar->addDescriptor(createUserDescription("Red")); + + // --- Зелёный --- + BLECharacteristic *gChar = colorService->createCharacteristic( + COLOR_CHAR_G_UUID, + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE + ); + gChar->setAccessPermissions(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE); + gChar->setValue(currentG); + gChar->setCallbacks(new ColorCallbacks(this, 1)); + // gChar->addDescriptor(createUserDescription("Green")); + + // --- Синий --- + BLECharacteristic *bChar = colorService->createCharacteristic( + COLOR_CHAR_B_UUID, + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE + ); + bChar->setAccessPermissions(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE); + bChar->setValue(currentB); + bChar->setCallbacks(new ColorCallbacks(this, 2)); + // bChar->addDescriptor(createUserDescription("Blue")); + + // --- Яркость --- + BLECharacteristic *brChar = colorService->createCharacteristic( + COLOR_CHAR_BRIGHTNESS_UUID, + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE + ); + brChar->setAccessPermissions(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE); + brChar->setValue(currentBrightness); + brChar->setCallbacks(new ColorCallbacks(this, 3)); + // brChar->addDescriptor(createUserDescription("Brightness")); + + colorService->start(); + + BLEAdvertising *advertising = BLEDevice::getAdvertising(); + advertising->addServiceUUID(COLOR_SERVICE_UUID); +} + + +void LedControl::loadSettings() { + preferences.begin(LED_NAMESPACE, true); + currentR = preferences.getUChar("r", 0); + currentG = preferences.getUChar("g", 0); + currentB = preferences.getUChar("b", 0); + currentBrightness = preferences.getUChar("br", 0); + preferences.end(); +} + +void LedControl::saveSettings() { + preferences.begin(LED_NAMESPACE, false); + preferences.putUChar("r", currentR); + preferences.putUChar("g", currentG); + preferences.putUChar("b", currentB); + preferences.putUChar("br", currentBrightness); + preferences.end(); +} + +void LedControl::applyColor() { + rgbLed.setPixelColor(0, rgbLed.Color(currentR, currentG, currentB)); + rgbLed.setBrightness(correctedBrightness(currentBrightness)); + rgbLed.show(); +} + +uint8_t LedControl::correctedBrightness(uint8_t percent) { + if (percent > 100) percent = 100; + const float gamma = 2.2f; + return pow(percent / 100.0f, gamma) * 255; +} +void LedControl::forceColor(uint8_t r, uint8_t g, uint8_t b) +{ + currentR = r; + currentG = g; + currentB = b; + rgbLed.setPixelColor(0, rgbLed.Color(r, g, b)); + rgbLed.setBrightness(correctedBrightness(currentBrightness)); + rgbLed.show(); + saveSettings(); // если хочешь сразу сохранять +} diff --git a/mouse/LedControl.h b/mouse/LedControl.h new file mode 100644 index 0000000..77f55f7 --- /dev/null +++ b/mouse/LedControl.h @@ -0,0 +1,81 @@ +#ifndef LED_CONTROL_H +#define LED_CONTROL_H + +#include +#include +#include +#include +#include +#include + +#define LED_NAMESPACE "led" +#define COLOR_SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0" +#define COLOR_CHAR_R_UUID "12345678-1234-5678-1234-56789abcdef1" +#define COLOR_CHAR_G_UUID "12345678-1234-5678-1234-56789abcdef2" +#define COLOR_CHAR_B_UUID "12345678-1234-5678-1234-56789abcdef3" +#define COLOR_CHAR_BRIGHTNESS_UUID "12345678-1234-5678-1234-56789abcdef4" + +class LedControl { +public: + LedControl(Adafruit_NeoPixel &led) + : rgbLed(led) {} + + void begin(); + void setupBLEService(BLEServer *server); + void applyColor(); + void forceColor(uint8_t r, uint8_t g, uint8_t b); + +private: + Adafruit_NeoPixel &rgbLed; + Preferences preferences; + + int currentR = 0, currentG = 0, currentB = 0, currentBrightness = 50; + BLECharacteristic *colorCharacteristic = nullptr; + + void loadSettings(); + void saveSettings(); + uint8_t correctedBrightness(uint8_t percent); + +class ColorCallbacks : public BLECharacteristicCallbacks { +public: + ColorCallbacks(LedControl *parent, uint8_t paramId) + : _parent(parent), _paramId(paramId) {} + + void onWrite(BLECharacteristic *characteristic) override { + String value = characteristic->getValue(); + if (value.length() >= 1) { + uint8_t val = static_cast(value[0]); + switch (_paramId) { + case 0: _parent->currentR = val; break; + case 1: _parent->currentG = val; break; + case 2: _parent->currentB = val; break; + case 3: _parent->currentBrightness = val; break; + } + characteristic->setValue(&val, 1); + _parent->applyColor(); + _parent->saveSettings(); + + Serial.printf("Set param %d = %d\n", _paramId, val); + } + } + + void onRead(BLECharacteristic *characteristic) override { + uint8_t val = 0; + switch (_paramId) { + case 0: val = _parent->currentR; break; + case 1: val = _parent->currentG; break; + case 2: val = _parent->currentB; break; + case 3: val = _parent->currentBrightness; break; + } + characteristic->setValue(&val, 1); // Обновляем значение характеристики перед чтением + + Serial.printf("Read param %d value: %d\n", _paramId, val); + } + +private: + LedControl *_parent; + uint8_t _paramId; +}; + +}; +#endif diff --git a/mouse/mouse.ino b/mouse/mouse.ino index 45318e7..e6fcd9e 100644 --- a/mouse/mouse.ino +++ b/mouse/mouse.ino @@ -1,13 +1,21 @@ #include #include "EspUsbHost.h" +#include +#define LED_PIN 21 // GPIO пин светодиода (скорее всего 48) +#define NUM_LEDS 1 // Один RGB светодиод #define SHOW_REAL_BATTERY -#define DISABLE_USB - +// #define RGB_LED +// #define DISABLE_USB BleMouse bleMouse("Ball Mouse"); +#ifdef RGB_LED +Adafruit_NeoPixel rgbLed(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); +LedControl ledControl(rgbLed); +#endif //RGB_LED + #ifdef SHOW_REAL_BATTERY #define BATTERY_UPDATE_INTERVAL 5000 // например, 30000 мс = 30 секунд #define BATTERY_ADC_PIN 6 @@ -51,17 +59,44 @@ MyEspUsbHost usbHost; #endif //DISABLE_USB void setup() { - Serial.begin(115200); - delay(500); - + // Serial.begin(115200); +#ifdef RGB_LED + // Запуск мыши — зелёный + ledControl.begin(); + ledControl.forceColor(0, 255, 0); // Зеленый +#endif//RGB_LED +#ifdef RGB_LED + // Инициализация BLE - красный + ledControl.forceColor(255, 0, 0); // Красный +#endif//RGB_LED + // Запуск BLE мыши (HID) + bleMouse.init(); + // Создаём BLE-сервер для подстветки + BLEServer *server = BLEDevice::createServer(); +#ifdef RGB_LED + // Настройка кастомного сервиса цвета + ledControl.setupBLEService(server); + // Добавляем UUID нашего сервиса в рекламу (важно до start) + BLEAdvertising *advertising = BLEDevice::getAdvertising(); + advertising->addServiceUUID(COLOR_SERVICE_UUID); +#endif//RGB_LED + // Запуск BLE мыши (HID) bleMouse.begin(); - Serial.println("BLE Mouse started"); + // BLE готов — красный +#ifdef RGB_LED + // USB — синий + ledControl.forceColor(0, 0, 255); // Синий +#endif//RGB_LED #ifndef DISABLE_USB usbHost.begin(); - Serial.println("USB Host started"); -#endif //DISABLE_USB +#endif + +#ifdef RGB_LED + // Загрузка сохранённого цвета + ledControl.applyColor(); +#endif//RGB_LED } void loop() { @@ -84,4 +119,4 @@ void loop() { } } #endif -} +} \ No newline at end of file