From 6d9e4a86a2caea97097f076add8bf3d10832f4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=9A=D1=83?= =?UTF-8?q?=D0=BB=D0=B8=D0=BA=D0=BE=D0=B2?= <6apmojleu@gmail.com> Date: Sun, 19 Mar 2023 20:44:36 +0000 Subject: [PATCH] Add support RGB keyboard for Lenovo IdeaPad3 --- .../Lenovo4ZoneUSBController.cpp | 81 +++++++++ .../Lenovo4ZoneUSBController.h | 59 ++++++ .../Lenovo4ZoneUSBDetect.cpp | 43 +++++ .../LenovoControllers/LenovoDevices4Zone.h | 105 +++++++++++ .../RGBController_Lenovo4ZoneUSB.cpp | 172 ++++++++++++++++++ .../RGBController_Lenovo4ZoneUSB.h | 37 ++++ OpenRGB.pro | 6 + 7 files changed, 503 insertions(+) create mode 100644 Controllers/LenovoControllers/Lenovo4ZoneUSBController.cpp create mode 100644 Controllers/LenovoControllers/Lenovo4ZoneUSBController.h create mode 100644 Controllers/LenovoControllers/Lenovo4ZoneUSBDetect.cpp create mode 100644 Controllers/LenovoControllers/LenovoDevices4Zone.h create mode 100644 Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.cpp create mode 100644 Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.h diff --git a/Controllers/LenovoControllers/Lenovo4ZoneUSBController.cpp b/Controllers/LenovoControllers/Lenovo4ZoneUSBController.cpp new file mode 100644 index 00000000..4f0707c3 --- /dev/null +++ b/Controllers/LenovoControllers/Lenovo4ZoneUSBController.cpp @@ -0,0 +1,81 @@ +/*-------------------------------------------------------------------*\ +| Lenovo4ZoneUSBController.cpp | +| | +| interface for Lenovo 4-Zones Devices | +\*-------------------------------------------------------------------*/ + +#include +#include "Lenovo4ZoneUSBController.h" +#include "LogManager.h" + +Lenovo4ZoneUSBController::Lenovo4ZoneUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid) +{ + const uint8_t sz = HID_MAX_STR; + wchar_t tmp[sz]; + + dev = dev_handle; + location = path; + pid = in_pid; + + hid_get_manufacturer_string(dev, tmp, sz); + std::wstring w_tmp = std::wstring(tmp); + name = std::string(w_tmp.begin(), w_tmp.end()); + + hid_get_product_string(dev, tmp, sz); + w_tmp = std::wstring(tmp); + name.append(" ").append(std::string(w_tmp.begin(), w_tmp.end())); + + setDeviceSoftwareMode(); +} + +Lenovo4ZoneUSBController::~Lenovo4ZoneUSBController() +{ + hid_close(dev); +} + +void Lenovo4ZoneUSBController::setMode(const KeyboardState &in_mode) +{ + uint8_t buffer[LENOVO_4_ZONE_HID_PACKET_SIZE]; + memcpy(buffer, &in_mode, LENOVO_4_ZONE_HID_PACKET_SIZE); + hid_send_feature_report(dev, buffer, LENOVO_4_ZONE_HID_PACKET_SIZE); +} + +uint16_t Lenovo4ZoneUSBController::getPid() +{ + return pid; +} + +std::string Lenovo4ZoneUSBController::getName() +{ + return name; +} + +std::string Lenovo4ZoneUSBController::getLocation() +{ + return location; +} + + +void Lenovo4ZoneUSBController::sendBasicInstruction(uint8_t ) +{ +} + +void Lenovo4ZoneUSBController::setDeviceSoftwareMode() +{ + /*---------------------------------------*\ + | this is required for the device listen | + | to the software protocol | + \*---------------------------------------*/ + sendBasicInstruction(0xB2); +} + +void Lenovo4ZoneUSBController::setDeviceHardwareMode() +{ + /*---------------------------------------*\ + |releases the device from sofware mode so | + |that onboard controlls can be used | + |this has not been shown to happen between| + |reboots | + \*---------------------------------------*/ + sendBasicInstruction(0xB1); +} diff --git a/Controllers/LenovoControllers/Lenovo4ZoneUSBController.h b/Controllers/LenovoControllers/Lenovo4ZoneUSBController.h new file mode 100644 index 00000000..632467df --- /dev/null +++ b/Controllers/LenovoControllers/Lenovo4ZoneUSBController.h @@ -0,0 +1,59 @@ +/*-------------------------------------------------------------------*\ +| Lenovo4ZoneUSBController.h | +| | +| interface for Lenovo 4-Zones Devices | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "LogManager.h" +#include "LenovoDevices4Zone.h" + +#include +#include +#include +#include +#include + +#ifndef HID_MAX_STR +#define HID_MAX_STR 255 +#endif + +#define LENOVO_4_ZONE_HID_PACKET_SIZE 33 + +class Lenovo4ZoneUSBController +{ + public: + /*--------------*\ + |ctor(s) and dtor| + \*--------------*/ + Lenovo4ZoneUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid); + ~Lenovo4ZoneUSBController(); + + void setMode(const KeyboardState &in_mode); + + /*--------------*\ + |device functions| + \*--------------*/ + uint16_t getPid(); + std::string getName(); + std::string getLocation(); + void setDeviceSoftwareMode(); + void setDeviceHardwareMode(); + + private: + /*--------------*\ + |data members | + \*--------------*/ + std::string name; + hid_device *dev; + std::string location; + uint16_t pid; + KeyboardState mode; + + /*--------------*\ + |device functions| + \*--------------*/ + void sendBasicInstruction(uint8_t instruction); +}; diff --git a/Controllers/LenovoControllers/Lenovo4ZoneUSBDetect.cpp b/Controllers/LenovoControllers/Lenovo4ZoneUSBDetect.cpp new file mode 100644 index 00000000..410b52b1 --- /dev/null +++ b/Controllers/LenovoControllers/Lenovo4ZoneUSBDetect.cpp @@ -0,0 +1,43 @@ +/*-------------------------------------------------------------------*\ +| Lenovo4ZoneUSBDetect.h | +| | +| Describes zones for Lenovo 4-Zone Device | +\*-------------------------------------------------------------------*/ + +#include "Detector.h" +#include "LogManager.h" +#include "RGBController.h" +#include "Lenovo4ZoneUSBController.h" +#include "LenovoDevices4Zone.h" +#include "RGBController_Lenovo4ZoneUSB.h" +#include + +/*-----------------------------------------------------*\ +| vendor IDs | +\*-----------------------------------------------------*/ +#define ITE_VID 0x048D + +/*-----------------------------------------------------*\ +| Interface, Usage, and Usage Page | +\*-----------------------------------------------------*/ +enum +{ + LENOVO_PAGE = 0xFF89, + LENOVO_USAGE = 0x10 +}; + +void DetectLenovo4ZoneUSBControllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + Lenovo4ZoneUSBController* controller = new Lenovo4ZoneUSBController(dev, info->path, info->product_id); + RGBController_Lenovo4ZoneUSB* rgb_controller = new RGBController_Lenovo4ZoneUSB(controller); + rgb_controller->name = name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + +REGISTER_HID_DETECTOR_PU("Lenovo Ideapad 3-15ach6", DetectLenovo4ZoneUSBControllers, ITE_VID, IDEAPAD_315ACH6, LENOVO_PAGE, LENOVO_USAGE); diff --git a/Controllers/LenovoControllers/LenovoDevices4Zone.h b/Controllers/LenovoControllers/LenovoDevices4Zone.h new file mode 100644 index 00000000..991da39b --- /dev/null +++ b/Controllers/LenovoControllers/LenovoDevices4Zone.h @@ -0,0 +1,105 @@ +/*-------------------------------------------------------------------*\ +| LenovoDevices4Zone.h | +| | +| Describes zones for Lenovo 4-Zone Device | +| | +\*-------------------------------------------------------------------*/ +#pragma once + +#include +#include "RGBControllerKeyNames.h" +#include "RGBController.h" +#include "LenovoDevices.h" + +/*-----------------------------------------------------*\ +| Keyboard product IDs | +\*-----------------------------------------------------*/ +#define IDEAPAD_315ACH6 0xC963 + +enum LENOVO_4_ZONE_EFFECT +{ + LENOVO_4_ZONE_EFFECT_STATIC = 1, + LENOVO_4_ZONE_EFFECT_BREATH = 3, + LENOVO_4_ZONE_EFFECT_WAVE = 4, + LENOVO_4_ZONE_EFFECT_SMOOTH = 6, +}; + +enum LENOVO_4_ZONE_BRIGHTNESS +{ + LENOVO_4_ZONE_BRIGHTNESS_LOW = 1, + LENOVO_4_ZONE_BRIGHTNESS_HIGH = 2, +}; + +enum LENOVO_4_ZONE_SPEED +{ + LENOVO_4_ZONE_SPEED_SLOWEST = 1, + LENOVO_4_ZONE_SPEED_SLOW = 2, + LENOVO_4_ZONE_SPEED_FAST = 3, + LENOVO_4_ZONE_SPEED_FASTEST = 4, +}; + +/// struct a USB packet for set the keyboard LEDs +class KeyboardState +{ +public: + uint8_t header[2] = {0xCC, 0x16}; + uint8_t effect = LENOVO_4_ZONE_EFFECT_STATIC; + uint8_t speed = LENOVO_4_ZONE_SPEED_SLOWEST; + uint8_t brightness = LENOVO_4_ZONE_BRIGHTNESS_LOW; + uint8_t zone0_rgb[3] = {0xFF, 0xFF, 0xFF}; + uint8_t zone1_rgb[3] = {0xFF, 0xFF, 0xFF}; + uint8_t zone2_rgb[3] = {0xFF, 0xFF, 0xFF}; + uint8_t zone3_rgb[3] = {0xFF, 0xFF, 0xFF}; + uint8_t padding = 0; + uint8_t wave_ltr = 0; + uint8_t wave_rtl = 0; + uint8_t unused[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + void Reset() + { + header[0] = 0xCC, header[1] = 0x16; + effect = LENOVO_4_ZONE_EFFECT_STATIC; + speed = LENOVO_4_ZONE_SPEED_SLOWEST; + brightness = LENOVO_4_ZONE_BRIGHTNESS_LOW; + zone0_rgb[0] = 0xFF, zone0_rgb[1] = 0xFF, zone0_rgb[2] = 0xFF; + zone1_rgb[0] = 0xFF, zone1_rgb[1] = 0xFF, zone1_rgb[2] = 0xFF; + zone2_rgb[0] = 0xFF, zone2_rgb[1] = 0xFF, zone2_rgb[2] = 0xFF; + zone3_rgb[0] = 0xFF, zone3_rgb[1] = 0xFF, zone3_rgb[2] = 0xFF; + padding = 0; + wave_ltr = 0; + wave_rtl = 0; + for(int i = 0; i < 13; ++i) + { + unused[i] = 0; + } + } + + void SetColors(std::vector group_colors) + { + zone0_rgb[0] = RGBGetRValue(group_colors[0]); + zone0_rgb[1] = RGBGetGValue(group_colors[0]); + zone0_rgb[2] = RGBGetBValue(group_colors[0]); + zone1_rgb[0] = RGBGetRValue(group_colors[1]); + zone1_rgb[1] = RGBGetGValue(group_colors[1]); + zone1_rgb[2] = RGBGetBValue(group_colors[1]); + zone2_rgb[0] = RGBGetRValue(group_colors[2]); + zone2_rgb[1] = RGBGetGValue(group_colors[2]); + zone2_rgb[2] = RGBGetBValue(group_colors[2]); + zone3_rgb[0] = RGBGetRValue(group_colors[3]); + zone3_rgb[1] = RGBGetGValue(group_colors[3]); + zone3_rgb[2] = RGBGetBValue(group_colors[3]); + } +}; + +/*-------------------------*\ +| 4-Zone keyboard | +\*-------------------------*/ + +static const lenovo_led lenovo_4_zone_leds[] +{ + {0x00, "Left side"}, + {0x01, "Left center"}, + {0x02, "Right center"}, + {0x03, "Right side"}, +}; + diff --git a/Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.cpp b/Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.cpp new file mode 100644 index 00000000..9bbc7eed --- /dev/null +++ b/Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.cpp @@ -0,0 +1,172 @@ +#include "Lenovo4ZoneUSBController.h" +#include "LenovoDevices4Zone.h" +#include "RGBController_Lenovo4ZoneUSB.h" +#include "LogManager.h" + +#include +#include +#include +#include +#include +#include + +#define LENOVO_4_ZONE_NUM_LEDS 4 + +RGBController_Lenovo4ZoneUSB::RGBController_Lenovo4ZoneUSB(Lenovo4ZoneUSBController* controller_ptr) +{ + controller = controller_ptr; + + name = controller->getName(); + type = DEVICE_TYPE_KEYBOARD; + vendor = "Lenovo"; + + + description = "Lenovo 4-Zone device"; + + mode Direct; + Direct.name = "Direct"; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS; + Direct.color_mode = MODE_COLORS_PER_LED; + Direct.brightness_min = 1; + Direct.brightness_max = 2; + + modes.push_back(Direct); + + mode Breath; + Breath.name = "Breathing"; + Breath.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_HAS_SPEED; + Breath.color_mode = MODE_COLORS_PER_LED; + Breath.brightness_min = 1; + Breath.brightness_max = 2; + Breath.speed_min = 1; + Breath.speed_max = 4; + + modes.push_back(Breath); + + mode Wave; + Wave.name = "Rainbow Wave"; + Wave.flags = MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_DIRECTION_LR; + Wave.color_mode = MODE_COLORS_RANDOM; + Wave.brightness_min = 1; + Wave.brightness_max = 2; + Wave.speed_min = 1; + Wave.speed_max = 4; + Wave.direction = MODE_DIRECTION_LEFT | MODE_DIRECTION_RIGHT; + modes.push_back(Wave); + + mode Smooth; + Smooth.name = "Spectrum Cycle"; + Smooth.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_HAS_SPEED; + Smooth.color_mode = MODE_COLORS_RANDOM; + Smooth.brightness_min = 1; + Smooth.brightness_max = 2; + Smooth.speed_min = 1; + Smooth.speed_max = 4; + modes.push_back(Smooth); + + + SetupZones(); + + // Reset colors to white + colors[0] = 0xFFFFFFFF; + colors[1] = 0xFFFFFFFF; + colors[2] = 0xFFFFFFFF; + colors[3] = 0xFFFFFFFF; +} + +RGBController_Lenovo4ZoneUSB::~RGBController_Lenovo4ZoneUSB() +{ + controller->setDeviceHardwareMode(); + + delete controller; +} + +void RGBController_Lenovo4ZoneUSB::SetupZones() +{ + zone new_zone; + new_zone.name = ZONE_EN_KEYBOARD; + new_zone.type = ZONE_TYPE_LINEAR; + new_zone.leds_count = LENOVO_4_ZONE_NUM_LEDS; + new_zone.leds_max = new_zone.leds_count; + new_zone.leds_min = new_zone.leds_count; + + new_zone.matrix_map = NULL; + + + zones.push_back(new_zone); + + for(unsigned int led_idx = 0; led_idx < LENOVO_4_ZONE_NUM_LEDS; led_idx++ ) + { + led new_led; + new_led.name = lenovo_4_zone_leds[led_idx].name; + new_led.value = lenovo_4_zone_leds[led_idx].led_num; + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_Lenovo4ZoneUSB::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_Lenovo4ZoneUSB::UpdateSingleLED(int /*led*/) +{ +} + +void RGBController_Lenovo4ZoneUSB::UpdateZoneLEDs(int /*zone*/) +{ +} + +void RGBController_Lenovo4ZoneUSB::DeviceUpdateLEDs() +{ + state.SetColors(colors); + controller->setMode(state); +} + +void RGBController_Lenovo4ZoneUSB::DeviceUpdateMode() +{ + state.Reset(); + state.SetColors(colors); + + switch (active_mode) + { + case 0: + state.effect = LENOVO_4_ZONE_EFFECT_STATIC; + break; + case 1: + state.effect = LENOVO_4_ZONE_EFFECT_BREATH; + break; + case 2: + state.effect = LENOVO_4_ZONE_EFFECT_WAVE; + state.wave_ltr = modes[active_mode].direction?0:1; + state.wave_rtl = modes[active_mode].direction?1:0; + break; + case 3: + state.effect = LENOVO_4_ZONE_EFFECT_SMOOTH; + break; + } + + if(active_mode != (LENOVO_4_ZONE_EFFECT_STATIC - 1)) // mode number from 0, but in mode from 1 + { + state.speed = modes[active_mode].speed; + } + state.brightness = modes[active_mode].brightness; + + controller->setMode(state); +} + +void RGBController_Lenovo4ZoneUSB::DeviceSaveMode() +{ + /*---------------------------------------------------------*\ + | This device does not support saving or multiple modes | + \*---------------------------------------------------------*/ +} diff --git a/Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.h b/Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.h new file mode 100644 index 00000000..ca377c5a --- /dev/null +++ b/Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.h @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------*\ +| RGBController_Lenovo4ZoneUSB.h | +| | +| interface for Lenovo 4-Zones Devices | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "LenovoDevices.h" +#include "Lenovo4ZoneUSBController.h" +#include "RGBController.h" + +#include + +#define NA 0xFFFFFFFF + +class RGBController_Lenovo4ZoneUSB : public RGBController +{ +public: + RGBController_Lenovo4ZoneUSB(Lenovo4ZoneUSBController* controller_ptr); + ~RGBController_Lenovo4ZoneUSB(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + void DeviceSaveMode(); + +private: + KeyboardState state; + + Lenovo4ZoneUSBController *controller; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index c1ec2e88..7debd644 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -482,8 +482,11 @@ HEADERS += Controllers/LEDStripController/LEDStripController.h \ Controllers/LEDStripController/RGBController_LEDStrip.h \ Controllers/LenovoControllers/LenovoDevices.h \ + Controllers/LenovoControllers/LenovoDevices4Zone.h \ Controllers/LenovoControllers/LenovoUSBController.h \ + Controllers/LenovoControllers/Lenovo4ZoneUSBController.h \ Controllers/LenovoControllers/RGBController_LenovoUSB.h \ + Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.h \ Controllers/LenovoMotherboardController/LenovoMotherboardController.h \ Controllers/LenovoMotherboardController/RGBController_LenovoMotherboard.h \ Controllers/LexipMouseController/LexipMouseController.h \ @@ -1087,8 +1090,11 @@ SOURCES += Controllers/LEDStripController/LEDStripControllerDetect.cpp \ Controllers/LEDStripController/RGBController_LEDStrip.cpp \ Controllers/LenovoControllers/LenovoUSBController.cpp \ + Controllers/LenovoControllers/Lenovo4ZoneUSBController.cpp \ Controllers/LenovoControllers/LenovoUSBDetect.cpp \ + Controllers/LenovoControllers/Lenovo4ZoneUSBDetect.cpp \ Controllers/LenovoControllers/RGBController_LenovoUSB.cpp \ + Controllers/LenovoControllers/RGBController_Lenovo4ZoneUSB.cpp \ Controllers/LenovoMotherboardController/LenovoMotherboardController.cpp \ Controllers/LenovoMotherboardController/LenovoMotherboardControllerDetect.cpp \ Controllers/LenovoMotherboardController/RGBController_LenovoMotherboard.cpp \