From fd3434b833fc5585ae8156054d4675466164ff45 Mon Sep 17 00:00:00 2001 From: vassilios Date: Fri, 10 Nov 2023 13:48:30 +0000 Subject: [PATCH] Changing current files to accomodate latest legion generation. --- Controllers/LenovoControllers/LenovoDevices.h | 18 +- .../LenovoRGBController_Gen7_8.cpp | 627 ++++++++++++++++++ .../LenovoRGBController_Gen7_8.h | 52 ++ .../LenovoUSBController_Gen7_8.cpp | 300 +++++++++ .../LenovoUSBController_Gen7_8.h | 97 +++ .../LenovoControllers/LenovoUSBDetect.cpp | 25 +- .../RGBController_LenovoUSB.cpp | 8 +- 7 files changed, 1104 insertions(+), 23 deletions(-) create mode 100644 Controllers/LenovoControllers/LenovoRGBController_Gen7_8.cpp create mode 100644 Controllers/LenovoControllers/LenovoRGBController_Gen7_8.h create mode 100644 Controllers/LenovoControllers/LenovoUSBController_Gen7_8.cpp create mode 100644 Controllers/LenovoControllers/LenovoUSBController_Gen7_8.h diff --git a/Controllers/LenovoControllers/LenovoDevices.h b/Controllers/LenovoControllers/LenovoDevices.h index 96221f38..b9514066 100644 --- a/Controllers/LenovoControllers/LenovoDevices.h +++ b/Controllers/LenovoControllers/LenovoDevices.h @@ -25,6 +25,7 @@ #define LEGION_Y760 0xC968 #define LEGION_Y760S 0xC967 #define LEGION_7GEN7 0xC978 +#define LEGION_7GEN8 0xC988 enum LENOVO_KEYBOARD { @@ -1710,7 +1711,7 @@ static lenovo_zone lenovo_legion_Y740_15_kbd_iso | Legion 7 gen7: 4 zones | \*--------------------------------------------------------*/ -static const unsigned int legion_7gen7_ansi_leds_map[] = +static const unsigned int legion7_gen7and8_ansi_leds_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, NA, 30, 31, 32, 33, NA, 34, 35, 36, 37, 38, 39, 40, 41, NA, 42, 43, 44, 45, 46, 47, 48, 49, 50, NA, 51, 52, 53, 54, NA, @@ -1722,7 +1723,7 @@ static const unsigned int legion_7gen7_ansi_leds_map[] = /*---------------------*\ | zone 1, keyboard ANSI | \*---------------------*/ -const lenovo_led legion_7gen7_ansi_leds[] +const lenovo_led legion7_gen7and8_ansi_leds[] { //row 1 {0x01, KEY_EN_ESCAPE},//0 @@ -1840,7 +1841,7 @@ const lenovo_led legion_7gen7_ansi_leds[] {0xA1, KEY_EN_RIGHT_ARROW},//100 }; -const lenovo_led legion_7gen7_neon_leds[] +const lenovo_led legion7_gen7and8_neon_leds[] { {0xF5, "Neon group 1"},//0 {0xF6, "Neon group 2"},//1 @@ -1874,15 +1875,15 @@ const lenovo_led legion_7gen7_logo_leds[] /*------*\ |keyboard| \*------*/ -static lenovo_zone lenovo_legion_7gen7_kbd_ansi +static lenovo_zone legion7_gen7and8_kbd_ansi { "Keyboard", ZONE_TYPE_MATRIX, 0, 7, 20, - legion_7gen7_ansi_leds_map, - legion_7gen7_ansi_leds, + legion7_gen7and8_ansi_leds_map, + legion7_gen7and8_ansi_leds, 0, 100, }; @@ -1922,7 +1923,7 @@ static lenovo_zone lenovo_legion_7gen7_vents /*------*\ |neon | \*------*/ -static lenovo_zone lenovo_legion_7gen7_neon +static lenovo_zone legion7_gen7and8_neon { "Neon", ZONE_TYPE_LINEAR, @@ -1930,9 +1931,8 @@ static lenovo_zone lenovo_legion_7gen7_neon 1, 10, NULL, - legion_7gen7_neon_leds, + legion7_gen7and8_neon_leds, 0, 9, }; - #endif diff --git a/Controllers/LenovoControllers/LenovoRGBController_Gen7_8.cpp b/Controllers/LenovoControllers/LenovoRGBController_Gen7_8.cpp new file mode 100644 index 00000000..59983f24 --- /dev/null +++ b/Controllers/LenovoControllers/LenovoRGBController_Gen7_8.cpp @@ -0,0 +1,627 @@ +#include "LenovoRGBController_Gen7_8.h" +#include "LenovoDevices.h" +#include + +using namespace std; + +LenovoRGBController_Gen7_8::LenovoRGBController_Gen7_8(LenovoGen7And8USBController* controller_ptr) +{ + controller = controller_ptr; + + mode Screw; + Screw.name = "Screw Rainbow"; + Screw.value = LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW; + Screw.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_DIRECTION_LR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Screw.speed_min = 0x01; + Screw.speed_max = 0x03; + Screw.speed = 2; + Screw.color_mode = MODE_COLORS_NONE; + Screw.brightness_min = 0; + Screw.brightness_max = 9; + Screw.brightness = brightness; + Screw.direction = MODE_DIRECTION_RIGHT; + modes.push_back(Screw); + + mode Rainbow; + Rainbow.name = "Rainbow Wave"; + Rainbow.value = LENOVO_LEGION_GEN7_8_MODE_RAINBOW_WAVE; + Rainbow.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_DIRECTION_LR | + MODE_FLAG_HAS_DIRECTION_UD | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Rainbow.speed_min = 0x01; + Rainbow.speed_max = 0x03; + Rainbow.speed = 2; + Rainbow.color_mode = MODE_COLORS_NONE; + Rainbow.brightness_min = 0; + Rainbow.brightness_max = 9; + Rainbow.brightness = brightness; + Rainbow.direction = MODE_DIRECTION_RIGHT; + modes.push_back(Rainbow); + + mode ColorChange; + ColorChange.name = "Color Change"; + ColorChange.value = LENOVO_LEGION_GEN7_8_MODE_COLOR_CHANGE; + ColorChange.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + ColorChange.speed_min = 0x01; + ColorChange.speed_max = 0x03; + ColorChange.speed = 2; + ColorChange.colors_min = 1; + ColorChange.colors_max = 4; + ColorChange.colors.resize(4); + ColorChange.colors[0] = 0xFFF500; + ColorChange.color_mode = MODE_COLORS_RANDOM; + ColorChange.brightness_min = 0; + ColorChange.brightness_max = 9; + ColorChange.brightness = brightness; + modes.push_back(ColorChange); + + mode ColorPulse; + ColorPulse.name = "Color Pulse"; + ColorPulse.value = LENOVO_LEGION_GEN7_8_MODE_COLOR_PULSE; + ColorPulse.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + ColorPulse.speed_min = 0x01; + ColorPulse.speed_max = 0x03; + ColorPulse.speed = 2; + ColorPulse.colors_min = 1; + ColorPulse.colors_max = 4; + ColorPulse.colors.resize(4); + ColorPulse.colors[0] = 0xFFF500; + ColorPulse.color_mode = MODE_COLORS_RANDOM; + ColorPulse.brightness_min = 0; + ColorPulse.brightness_max = 9; + ColorPulse.brightness = brightness; + modes.push_back(ColorPulse); + + mode ColorWave; + ColorWave.name = "Color Wave"; + ColorWave.value = LENOVO_LEGION_GEN7_8_MODE_COLOR_WAVE; + ColorWave.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_DIRECTION_LR | + MODE_FLAG_HAS_DIRECTION_UD | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + ColorWave.speed_min = 0x01; + ColorWave.speed_max = 0x03; + ColorWave.speed = 2; + ColorWave.colors_min = 1; + ColorWave.colors_max = 4; + ColorWave.colors.resize(4); + ColorWave.colors[0] = 0xFFF500; + ColorWave.color_mode = MODE_COLORS_RANDOM; + ColorWave.brightness_min = 0; + ColorWave.brightness_max = 9; + ColorWave.brightness = brightness; + ColorWave.direction = MODE_DIRECTION_RIGHT; + modes.push_back(ColorWave); + + mode Smooth; + Smooth.name = "Smooth"; + Smooth.value = LENOVO_LEGION_GEN7_8_MODE_SMOOTH; + Smooth.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Smooth.speed_min = 0x01; + Smooth.speed_max = 0x03; + Smooth.speed = 2; + Smooth.colors_min = 1; + Smooth.colors_max = 4; + Smooth.colors.resize(4); + Smooth.colors[0] = 0xFFF500; + Smooth.color_mode = MODE_COLORS_RANDOM; + Smooth.brightness_min = 0; + Smooth.brightness_max = 9; + Smooth.brightness = brightness; + modes.push_back(Smooth); + + mode Rain; + Rain.name = "Rain"; + Rain.value = LENOVO_LEGION_GEN7_8_MODE_RAIN; + Rain.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Rain.speed_min = 0x01; + Rain.speed_max = 0x03; + Rain.speed = 2; + Rain.colors_min = 1; + Rain.colors_max = 4; + Rain.colors.resize(4); + Rain.colors[0] = 0xFFF500; + Rain.color_mode = MODE_COLORS_RANDOM; + Rain.brightness_min = 0; + Rain.brightness_max = 9; + Rain.brightness = brightness; + modes.push_back(Rain); + + mode Ripple; + Ripple.name = "Ripple"; + Ripple.value = LENOVO_LEGION_GEN7_8_MODE_RIPPLE; + Ripple.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Ripple.speed_min = 0x01; + Ripple.speed_max = 0x03; + Ripple.speed = 2; + Ripple.colors_min = 1; + Ripple.colors_max = 4; + Ripple.colors.resize(4); + Ripple.colors[0] = 0xFFF500; + Ripple.color_mode = MODE_COLORS_RANDOM; + Ripple.brightness_min = 0; + Ripple.brightness_max = 9; + Ripple.brightness = brightness; + modes.push_back(Ripple); + + mode AudioBounce; + AudioBounce.name = "Audio Bounce Lighting"; + AudioBounce.value = LENOVO_LEGION_GEN7_8_MODE_AUDIO_BOUNCE; + AudioBounce.flags = MODE_FLAG_HAS_BRIGHTNESS; + AudioBounce.color_mode = MODE_COLORS_NONE; + AudioBounce.brightness_min = 0; + AudioBounce.brightness_max = 9; + AudioBounce.brightness = brightness; + modes.push_back(AudioBounce); + + mode AudioRipple; + AudioRipple.name = "Audio Ripple Lighting"; + AudioRipple.value = LENOVO_LEGION_GEN7_8_MODE_AUDIO_RIPPLE; + AudioRipple.flags = MODE_FLAG_HAS_BRIGHTNESS; + AudioRipple.color_mode = MODE_COLORS_NONE; + AudioRipple.brightness_min = 0; + AudioRipple.brightness_max = 9; + AudioRipple.brightness = brightness; + modes.push_back(AudioRipple); + + mode Static; + Static.name = "Static"; + Static.value = LENOVO_LEGION_GEN7_8_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Static.color_mode = MODE_COLORS_PER_LED; + Static.brightness_min = 0; + Static.brightness_max = 9; + Static.brightness = brightness; + modes.push_back(Static); + + mode Type; + Type.name = "Type Lighting"; + Type.value = LENOVO_LEGION_GEN7_8_MODE_TYPE; + Type.flags = MODE_FLAG_HAS_SPEED | + MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | + MODE_FLAG_HAS_RANDOM_COLOR | + MODE_FLAG_HAS_BRIGHTNESS | + MODE_FLAG_AUTOMATIC_SAVE; + Type.speed_min = 0x01; + Type.speed_max = 0x03; + Type.speed = 2; + Type.colors_min = 1; + Type.colors_max = 4; + Type.colors.resize(4); + Type.colors[0] = 0xFFF500; + Type.color_mode = MODE_COLORS_RANDOM; + Type.brightness_min = 0; + Type.brightness_max = 9; + Type.brightness = brightness; + modes.push_back(Type); + + mode Direct; + Direct.name = "Direct"; + Direct.value = LENOVO_LEGION_GEN7_8_MODE_DIRECT; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | + MODE_FLAG_HAS_BRIGHTNESS; + Direct.color_mode = MODE_COLORS_PER_LED; + Direct.brightness_min = 0; + Direct.brightness_max = 9; + Direct.brightness = brightness; + modes.push_back(Direct); + + + name = controller->getName(); + type = DEVICE_TYPE_KEYBOARD; + vendor = "Lenovo"; + + switch (controller->getPid()) + { + case LEGION_7GEN7: + description = "Lenovo Legion 7 Generation 7"; + break; + + case LEGION_7GEN8: + description = "Lenovo Legion 7 Generation 8"; + break; + } + + brightness = controller->getCurrentBrightness(); + profile_id = controller->getCurrentProfileId(); + + SetupZones(); + + /*-----------------*\ + | Initiliaze Static | + \*-----------------*/ + // ToDo: Commented causes a crash. (???) + active_mode = 10; + ReadDeviceSettings(); + last_mode = active_mode; +} + +LenovoRGBController_Gen7_8::~LenovoRGBController_Gen7_8() +{ + delete controller; +} + + +void LenovoRGBController_Gen7_8::SetupZones() +{ + vector lenovo_zones; + lenovo_zones.push_back(legion7_gen7and8_kbd_ansi); + lenovo_zones.push_back(legion7_gen7and8_neon); + + if (controller->getPid() == LEGION_7GEN7) + { + lenovo_zones.push_back(lenovo_legion_7gen7_logo); + lenovo_zones.push_back(lenovo_legion_7gen7_vents); + } + + for(unsigned int i = 0; i < lenovo_zones.size(); i++) + { + zone new_zone; + new_zone.name = lenovo_zones[i].name; + new_zone.type = lenovo_zones[i].type; + new_zone.leds_count = lenovo_zones[i].end - lenovo_zones[i].start + 1; + new_zone.leds_max = new_zone.leds_count; + new_zone.leds_min = new_zone.leds_count; + + LOG_DEBUG("[Lenovo Gen7/8 Controller] adding zone: %s with %u LEDs", new_zone.name.c_str(), new_zone.leds_count); + + if(lenovo_zones[i].type == ZONE_TYPE_MATRIX) + { + new_zone.matrix_map = new matrix_map_type; + new_zone.matrix_map->height = lenovo_zones[i].height; + new_zone.matrix_map->width = lenovo_zones[i].width; + new_zone.matrix_map->map = new unsigned int[new_zone.matrix_map->height * new_zone.matrix_map->width]; + + if(lenovo_zones[i].matrix_map != NULL) + { + new_zone.matrix_map->map = (unsigned int *) lenovo_zones[i].matrix_map; + } + } + else + { + new_zone.matrix_map = NULL; + } + + zones.push_back(new_zone); + + for(unsigned int led_idx = lenovo_zones[i].start; led_idx <= lenovo_zones[i].end; led_idx++ ) + { + led new_led; + new_led.name = lenovo_zones[i].leds[led_idx].name; + new_led.value = lenovo_zones[i].id << 8 | lenovo_zones[i].leds[led_idx].led_num ; + leds.push_back(new_led); + + /*---------------------------------------------------------*\ + | create led id to index map for fast look up | + \*---------------------------------------------------------*/ + led_id_to_index[new_led.value]=leds.size() - 1; + } + } + + SetupColors(); +} + +void LenovoRGBController_Gen7_8::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void LenovoRGBController_Gen7_8::UpdateSingleLED(int led) +{ + DeviceUpdateLEDs(); +} + +void LenovoRGBController_Gen7_8::UpdateZoneLEDs(int led) +{ + DeviceUpdateLEDs(); +} + +void LenovoRGBController_Gen7_8::DeviceUpdateMode() +{ + uint8_t hw_profile_id = controller->getCurrentProfileId(); + if(hw_profile_id != profile_id) { + profile_id = hw_profile_id; + ReadDeviceSettings(); + last_mode = active_mode; + } + + if(brightness != modes[active_mode].brightness) + { + brightness = modes[active_mode].brightness; + controller->setBrightness(brightness); + for(mode &m : modes) + { + m.brightness = brightness; + } + } + + if(last_mode != active_mode){ + + if(modes[last_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT) + { + controller->setLedsDirectOff(profile_id); + } + + + if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT) + { + controller->setLedsDirectOn(profile_id); + controller->setLedsByGroup(profile_id, GetLedGroups()); + } + + last_mode = active_mode; + } + + if(modes[active_mode].value != LENOVO_LEGION_GEN7_8_MODE_DIRECT) + { + DeviceUpdateLEDs(); + } +} + +void LenovoRGBController_Gen7_8::DeviceUpdateLEDs() +{ + if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT) + { + controller->setLedsDirect(leds, colors); + } + else + { + controller->setLedsByGroup(profile_id, GetLedGroups()); + } + +} + +void LenovoRGBController_Gen7_8::ReadDeviceSettings() +{ + vector current_settings = controller->getProfileSettings(profile_id); + if(current_settings.size()>0) + { + for(int i = 0; i0) + { + for(uint16_t led_id : lg.leds) + { + if(auto search = led_id_to_index.find(led_id); search != led_id_to_index.end()) + { + colors[search->second] = lg.colors[0]; + } + } + } + } + break; + + case MODE_COLORS_MODE_SPECIFIC: + for(size_t j=0; j LenovoRGBController_Gen7_8::GetLedGroups() +{ + std::unordered_map> led_map; + + if(modes[active_mode].color_mode == MODE_COLORS_PER_LED && + modes[active_mode].value != LENOVO_LEGION_GEN7_8_MODE_DIRECT) + { + for(size_t i = 0; i < leds.size(); i++) + { + led_map[colors[i]].push_back(leds[i].value); + } + } + else + { + size_t start = 0; + size_t end = leds.size(); + + /*---------------------------------------------------------*\ + | Riplle and Type only apply to keyboard | + \*---------------------------------------------------------*/ + if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_RIPPLE || + modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_TYPE) + { + for(const zone &z : zones) + { + if(z.name == "Keyboard") + { + start = z.start_idx; + end = start + z.leds_count; + } + } + + } + + for(size_t i = start; i < end; i++) + { + led_map[0x00].push_back(leds[i].value); + } + } + + vector led_groups; + for(const auto &pair : led_map) + { + if(pair.first == 0x00 && led_map.size() != 1) + { + continue; + } + + led_group group; + group.mode = modes[active_mode].value; + group.speed = modes[active_mode].speed; + group.spin = 0x00; + group.direction = 0x00; + + switch(modes[active_mode].direction) + { + case MODE_DIRECTION_UP: + group.direction = 0x01; + break; + + case MODE_DIRECTION_DOWN: + group.direction = 0x02; + break; + + case MODE_DIRECTION_LEFT: + if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW) + { + group.spin = 0x02; + } + else + { + group.direction = 0x03; + } + break; + + case MODE_DIRECTION_RIGHT: + if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW) + { + group.spin = 0x01; + } + else + { + group.direction = 0x04; + } + break; + } + + switch(modes[active_mode].color_mode) + { + default: + case MODE_COLORS_NONE: + group.color_mode = 0x00; + break; + + case MODE_COLORS_RANDOM: + group.color_mode = 0x01; + break; + + case MODE_COLORS_MODE_SPECIFIC: + group.color_mode = 0x02; + for(RGBColor c : modes[active_mode].colors) + { + if(c) + { + group.colors.push_back(c); + } + } + + if(group.colors.size() == 0) + { + group.colors.push_back(0xFFF500); + } + break; + + case MODE_COLORS_PER_LED: + group.color_mode = 0x02; + group.colors.push_back(pair.first); + break; + } + + group.leds = pair.second; + + led_groups.push_back(group); + } + + return led_groups; +} diff --git a/Controllers/LenovoControllers/LenovoRGBController_Gen7_8.h b/Controllers/LenovoControllers/LenovoRGBController_Gen7_8.h new file mode 100644 index 00000000..ab4d5cb2 --- /dev/null +++ b/Controllers/LenovoControllers/LenovoRGBController_Gen7_8.h @@ -0,0 +1,52 @@ +#ifndef RGBCONTROLLER_LENOVO_GEN7USB_H +#define RGBCONTROLLER_LENOVO_GEN7USB_H + +#pragma once + +#include "RGBController.h" +#include "LenovoGen7And8USBController.h" + +enum +{ + LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW = 0x01, + LENOVO_LEGION_GEN7_8_MODE_RAINBOW_WAVE = 0x02, + LENOVO_LEGION_GEN7_8_MODE_COLOR_CHANGE = 0x03, + LENOVO_LEGION_GEN7_8_MODE_COLOR_PULSE = 0x04, + LENOVO_LEGION_GEN7_8_MODE_COLOR_WAVE = 0x05, + LENOVO_LEGION_GEN7_8_MODE_SMOOTH = 0x06, + LENOVO_LEGION_GEN7_8_MODE_RAIN = 0x07, + LENOVO_LEGION_GEN7_8_MODE_RIPPLE = 0x08, + LENOVO_LEGION_GEN7_8_MODE_AUDIO_BOUNCE = 0x09, + LENOVO_LEGION_GEN7_8_MODE_AUDIO_RIPPLE = 0x0A, + LENOVO_LEGION_GEN7_8_MODE_STATIC = 0x0B, + LENOVO_LEGION_GEN7_8_MODE_TYPE = 0x0C, + LENOVO_LEGION_GEN7_8_MODE_DIRECT = 0x0D, +}; + +class LenovoRGBController_Gen7_8 : public RGBController +{ +public: + LenovoRGBController_Gen7_8(LenovoGen7And8USBController* controller_ptr); + ~LenovoRGBController_Gen7_8(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + LenovoGen7And8USBController* controller; + std::vector GetLedGroups(); + void ReadDeviceSettings(); + std::unordered_map led_id_to_index; + int last_mode = 0; + uint8_t brightness = 0x00; + uint8_t profile_id = 0x01; +}; + +#endif // RGBCONTROLLER_LENOVO_GEN7USB_H diff --git a/Controllers/LenovoControllers/LenovoUSBController_Gen7_8.cpp b/Controllers/LenovoControllers/LenovoUSBController_Gen7_8.cpp new file mode 100644 index 00000000..d607713b --- /dev/null +++ b/Controllers/LenovoControllers/LenovoUSBController_Gen7_8.cpp @@ -0,0 +1,300 @@ +#include "LenovoUSBController_Gen7_8.h" +#include +#include + +using namespace std; + +LenovoGen7And8USBController::LenovoGen7And8USBController(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 = wstring(tmp); + name = string(w_tmp.begin(), w_tmp.end()); + + hid_get_product_string(dev, tmp, sz); + w_tmp = wstring(tmp); + name.append(" ").append(string(w_tmp.begin(), w_tmp.end())); +} + +LenovoGen7And8USBController::~LenovoGen7And8USBController() +{ + hid_close(dev); +} + +uint16_t LenovoGen7And8USBController::getPid() +{ + return pid; +} + +string LenovoGen7And8USBController::getName() +{ + return name; +} + +string LenovoGen7And8USBController::getLocation() +{ + return location; +} + +void LenovoGen7And8USBController::setLedsByGroup(uint8_t profile_id, vector led_groups) +{ + uint8_t buffer[PACKET_SIZE]; + memset(buffer, 0x00, PACKET_SIZE); + + size_t i = 0; + buffer[i++] = REPORT_ID; + buffer[i++] = SAVE_PROFILE; + buffer[i++] = 0xC0; + buffer[i++] = 0x03; + buffer[i++] = profile_id; + buffer[i++] = 0x01; + buffer[i++] = 0x01; + + for(size_t group = 0; group < led_groups.size() && i < PACKET_SIZE - 21; group++) + { + buffer[i++] = group + 1; //Group index + buffer[i++] = 0x06; + buffer[i++] = 0x01; + buffer[i++] = led_groups[group].mode; + buffer[i++] = 0x02; + buffer[i++] = led_groups[group].speed; + buffer[i++] = 0x03; + buffer[i++] = led_groups[group].spin; + buffer[i++] = 0x04; + buffer[i++] = led_groups[group].direction; + buffer[i++] = 0x05; + buffer[i++] = led_groups[group].color_mode; + buffer[i++] = 0x06; + buffer[i++] = 0x00; + + buffer[i++] = led_groups[group].colors.size(); + for(RGBColor c : led_groups[group].colors) + { + buffer[i++] = RGBGetRValue(c); + buffer[i++] = RGBGetGValue(c); + buffer[i++] = RGBGetBValue(c); + } + + vector leds = led_groups[group].leds; + size_t led_count = min(leds.size(), (PACKET_SIZE - i)/2); + buffer[i++] = led_count; + uint8_t* byte_ptr = reinterpret_cast(leds.data()); + std::copy(byte_ptr, byte_ptr + led_count * sizeof(uint16_t), buffer + i); + i+= led_count * sizeof(uint16_t); + } + + buffer[2] = i; + + sendFeatureReport(buffer, PACKET_SIZE); +} + +void LenovoGen7And8USBController::setLedsDirectOn(uint8_t profile_id) +{ + uint8_t buffer[PACKET_SIZE]; + memset(buffer, 0x00, PACKET_SIZE); + + size_t i = 0; + buffer[i++] = REPORT_ID; + buffer[i++] = SET_DIRECT_MODE; + buffer[i++] = 0xC0; + buffer[i++] = 0x03; + buffer[i++] = 0x01; + buffer[i++] = profile_id; + + sendFeatureReport(buffer, PACKET_SIZE); +} + +void LenovoGen7And8USBController::setLedsDirectOff(uint8_t profile_id) +{ + uint8_t buffer[PACKET_SIZE]; + memset(buffer, 0x00, PACKET_SIZE); + + size_t i = 0; + buffer[i++] = REPORT_ID; + buffer[i++] = SET_DIRECT_MODE; + buffer[i++] = 0xC0; + buffer[i++] = 0x03; + buffer[i++] = 0x02; + buffer[i++] = profile_id; + + sendFeatureReport(buffer, PACKET_SIZE); +} + +void LenovoGen7And8USBController::setLedsDirect(std::vector &leds, std::vector &colors) +{ + uint8_t buffer[PACKET_SIZE]; + memset(buffer, 0x00, PACKET_SIZE); + + size_t i = 0; + buffer[i++] = REPORT_ID; + buffer[i++] = DIRECT_MODE; + buffer[i++] = 0xC0; + buffer[i++] = 0x03; + + for(size_t index = 0; index < leds.size() && i < PACKET_SIZE; index++) + { + buffer[i++] = leds[index].value & 0xFF; + buffer[i++] = leds[index].value >> 8 & 0xFF; + buffer[i++] = RGBGetRValue(colors[index]); + buffer[i++] = RGBGetGValue(colors[index]); + buffer[i++] = RGBGetBValue(colors[index]); + } + + sendFeatureReport(buffer, PACKET_SIZE); +} + +void LenovoGen7And8USBController::setLedsAllOff(uint8_t profile_id) +{ + uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SAVE_PROFILE, 0xC0, 0x03, profile_id, 0x01, 0x01}; + + sendFeatureReport(buffer, PACKET_SIZE); +} + +uint8_t LenovoGen7And8USBController::getCurrentProfileId() +{ + uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_ACTIVE_PROFILE, 0xC0, 0x03}; + + vector response = getFeatureReport(buffer, PACKET_SIZE); + + return response.size()>4?response[4]:0x01; +} + +uint8_t LenovoGen7And8USBController::getCurrentBrightness() +{ + uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_BRIGHTNESS, 0xC0, 0x03}; + + vector response = getFeatureReport(buffer, PACKET_SIZE); + + return response.size()>4?response[4]:0x00; +} + + +void LenovoGen7And8USBController::setBrightness(uint8_t brightness) +{ + uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SET_BRIGHTNESS, 0xC0, 0x03, brightness}; + + sendFeatureReport(buffer, PACKET_SIZE); +} + +void LenovoGen7And8USBController::switchProfileTo(uint8_t profile_id) +{ + uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SWITCH_PROFILE, 0xC0, 0x03, profile_id}; + + sendFeatureReport(buffer, PACKET_SIZE); +} + +std::vector LenovoGen7And8USBController::getProfileSettings(uint8_t profile_id) +{ + uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_PROFILE, 0xC0, 0x03, profile_id}; + + vector response = getFeatureReport(buffer, PACKET_SIZE); + + vector groups; + + size_t i = 7; + while(i < response.size() && response[i] != 0x00){ + i++; + + led_group group; + + /*-----------------*\ + |read group settings| + \*-----------------*/ + + size_t cnt = response[i++]; + for(size_t j = 0; j < cnt && i < response.size(); j++, i+=2) + { + switch(response[i]) + { + case 0x01: + group.mode = response[i+1]; + break; + case 0x02: + group.speed = response[i+1]; + break; + case 0x03: + group.spin = response[i+1]; + break; + case 0x04: + group.direction = response[i+1]; + break; + case 0x05: + group.color_mode = response[i+1]; + break; + case 0x06: + //group.mode = response[i+1]; + break; + } + } + + /*-----------------*\ + |read group colors | + \*-----------------*/ + + cnt = response[i++]; + for(size_t j = 0; j < cnt && i < response.size(); j++, i+=3) + { + group.colors.push_back(ToRGBColor(response[i],response[i+1],response[i+2])); + } + + /*-----------------*\ + |read group LEDs | + \*-----------------*/ + + cnt = response[i++]; + for(size_t j = 0; j < cnt && i < response.size(); j++, i+=2) + { + group.leds.push_back(response[i] | response[i+1] << 8); + } + + groups.push_back(group); + } + + return groups; + +} + +void LenovoGen7And8USBController::sendFeatureReport(uint8_t packet[], size_t packet_size) +{ + hid_send_feature_report(dev, packet, packet_size); + LOG_TRACE("[Lenovo Gen 7 Controller] Buffer: %s", ConvertBytesToHex(packet, packet_size).c_str()); +} + +std::vector LenovoGen7And8USBController::getFeatureReport(uint8_t packet[], size_t packet_size) +{ + sendFeatureReport(packet, packet_size); + + uint8_t read_buffer[PACKET_SIZE] = {REPORT_ID}; + int num_bytes = 0; + num_bytes = hid_get_feature_report(dev, read_buffer, sizeof(read_buffer)); + + vector response = {}; + if(num_bytes > 0) + { + response.insert(response.begin(), read_buffer, read_buffer + num_bytes); + } + + LOG_TRACE("[Lenovo Gen 7 Controller] Read Buffer: %s", ConvertBytesToHex(response).c_str()); + return response; +} + +std::string LenovoGen7And8USBController::ConvertBytesToHex(uint8_t packet[], size_t packet_size) +{ + return ConvertBytesToHex(std::vector(packet, packet + packet_size)); +} + +std::string LenovoGen7And8USBController::ConvertBytesToHex(const std::vector &input) +{ + std::ostringstream temp_stream; + for(const uint8_t &oneInputByte : input) + { + temp_stream << (temp_stream.tellp()==0 ? "" : " ") << std::setw(2) << std::setfill('0') << std::hex << (int)oneInputByte; + } + return temp_stream.str(); +} diff --git a/Controllers/LenovoControllers/LenovoUSBController_Gen7_8.h b/Controllers/LenovoControllers/LenovoUSBController_Gen7_8.h new file mode 100644 index 00000000..20fe115d --- /dev/null +++ b/Controllers/LenovoControllers/LenovoUSBController_Gen7_8.h @@ -0,0 +1,97 @@ +/*-------------------------------------------------------------------*\ +| LenovoGen7And8USBController.h | +| | +| Driver for Lenovo Legion 7 Gen 7 | +| | +| Peter Vazny 15 Nov 2022 | +| | +\*-------------------------------------------------------------------*/ + +#include "RGBController.h" +#include "LogManager.h" + +#include +#include +#include +#include +#include + +#ifndef HID_MAX_STR +#define HID_MAX_STR 255 +#endif + +#ifndef LENOVOGEN7AND8USBCONTROLLER_H +#define LENOVOGEN7AND8USBCONTROLLER_H + +#define PACKET_SIZE 960 +#define REPORT_ID 0x07 +#define DIRECT_MODE 0xA1 +#define SWITCH_PROFILE 0xC8 +#define GET_ACTIVE_PROFILE 0xCA +#define SAVE_PROFILE 0xCB +#define GET_PROFILE 0xCC +#define GET_BRIGHTNESS 0xCD +#define SET_BRIGHTNESS 0xCE +#define SET_DIRECT_MODE 0xD0 +#define GET_DIRECT_MODE_PROFILE 0xD1 + +struct led_group +{ + uint8_t mode; + uint8_t speed; + uint8_t spin; + uint8_t direction; + uint8_t color_mode; + std::vector colors; + std::vector leds; +}; + +class LenovoGen7And8USBController +{ + + public: + /*--------------*\ + |ctor(s) and dtor| + \*--------------*/ + LenovoGen7And8USBController(hid_device* dev_handle, const char* path, uint16_t in_pid); + LenovoGen7And8USBController(); + ~LenovoGen7And8USBController(); + + /*--------------*\ + |device functions| + \*--------------*/ + void setLedsByGroup(uint8_t profile_id, std::vector led_groups); + void setLedsDirect(std::vector &leds, std::vector &colors); + void setLedsAllOff(uint8_t profile_id); + void setLedsDirectOn(uint8_t profile_id); + void setLedsDirectOff(uint8_t profile_id); + uint16_t getPid(); + std::string getName(); + std::string getLocation(); + uint8_t getCurrentProfileId(); + uint8_t getCurrentBrightness(); + void setBrightness(uint8_t brightness); + uint8_t getKeyboardId(); + void switchProfileTo(uint8_t profile_id); + std::vector getProfileSettings(uint8_t profile_id); + + + private: + /*--------------*\ + |data members | + \*--------------*/ + std::string name; + hid_device *dev; + std::string location; + uint16_t pid; + + /*--------------*\ + |device functions| + \*--------------*/ + void sendFeatureReport(uint8_t packet[], size_t packet_size); + std::vector getFeatureReport(uint8_t packet[], size_t packet_size); + std::string ConvertBytesToHex(uint8_t packet[], size_t packet_size); + std::string ConvertBytesToHex(const std::vector &input); +}; + +#endif // LENOVOGEN7AND8USBCONTROLLER_H diff --git a/Controllers/LenovoControllers/LenovoUSBDetect.cpp b/Controllers/LenovoControllers/LenovoUSBDetect.cpp index 93a57908..a21fa790 100644 --- a/Controllers/LenovoControllers/LenovoUSBDetect.cpp +++ b/Controllers/LenovoControllers/LenovoUSBDetect.cpp @@ -10,11 +10,11 @@ #include "Detector.h" #include "LogManager.h" #include "RGBController.h" -#include "LenovoGen7USBController.h" +#include "LenovoGen7And8USBController.h" #include "LenovoUSBController.h" #include "LenovoDevices.h" #include "RGBController_LenovoUSB.h" -#include "RGBController_Lenovo_Gen7USB.h" +#include "LenovoRGBController_Gen7_8.h" #include /*-----------------------------------------------------*\ @@ -45,23 +45,24 @@ void DetectLenovoLegionUSBControllers(hid_device_info* info, const std::string& } } -void DetectLenovoLegionUSBControllersGen7(hid_device_info* info, const std::string& name) +void DetectLenovoLegionUSBControllersGen7And8(hid_device_info* info, const std::string& name) { hid_device* dev = hid_open_path(info->path); if(dev) { - LenovoGen7USBController* controller = new LenovoGen7USBController(dev, info->path, info->product_id); - RGBController_Lenovo_Gen7USB* rgb_controller = new RGBController_Lenovo_Gen7USB(controller); - rgb_controller->name = name; + LenovoGen7And8USBController* controller = new LenovoGen7And8USBController(dev, info->path, info->product_id); + LenovoRGBController_Gen7_8* rgb_controller = new LenovoRGBController_Gen7_8(controller); + rgb_controller->name = name; ResourceManager::get()->RegisterRGBController(rgb_controller); } } -REGISTER_HID_DETECTOR_PU("Lenovo Legion Y740", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y740, LENOVO_PAGE, LENOVO_USAGE); -REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 gen 5", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y750, LENOVO_PAGE, LENOVO_USAGE); -REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S gen 5", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y750S, LENOVO_PAGE, LENOVO_USAGE); -REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y760, LENOVO_PAGE, LENOVO_USAGE); -REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y760S, LENOVO_PAGE, LENOVO_USAGE); -REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 gen 7", DetectLenovoLegionUSBControllersGen7, ITE_VID, LEGION_7GEN7, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion Y740", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y740, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 5", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y750, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 5", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y750S, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y760, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y760S, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 7", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN7, LENOVO_PAGE, LENOVO_USAGE); +REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 8", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN8, LENOVO_PAGE, LENOVO_USAGE); diff --git a/Controllers/LenovoControllers/RGBController_LenovoUSB.cpp b/Controllers/LenovoControllers/RGBController_LenovoUSB.cpp index 070c68ad..666197a5 100644 --- a/Controllers/LenovoControllers/RGBController_LenovoUSB.cpp +++ b/Controllers/LenovoControllers/RGBController_LenovoUSB.cpp @@ -289,10 +289,14 @@ void RGBController_LenovoUSB::SetupZones() lenovo_zones.push_back(lenovo_legion_Y760_neon); break; case LEGION_7GEN7: - lenovo_zones.push_back(lenovo_legion_7gen7_kbd_ansi); + lenovo_zones.push_back(legion7_gen7and8_kbd_ansi); lenovo_zones.push_back(lenovo_legion_7gen7_logo); lenovo_zones.push_back(lenovo_legion_7gen7_vents); - lenovo_zones.push_back(lenovo_legion_7gen7_neon); + lenovo_zones.push_back(legion7_gen7and8_neon); + break; + case LEGION_7GEN8: + lenovo_zones.push_back(legion7_gen7and8_kbd_ansi); + lenovo_zones.push_back(legion7_gen7and8_neon); break; }