diff --git a/Controllers/LianLiController/LianLiControllerDetect.cpp b/Controllers/LianLiController/LianLiControllerDetect.cpp index db10faa4..f4c97c33 100644 --- a/Controllers/LianLiController/LianLiControllerDetect.cpp +++ b/Controllers/LianLiController/LianLiControllerDetect.cpp @@ -32,6 +32,8 @@ #include "RGBController_LianLiUniHub_AL10.h" #include "LianLiUniHubSLV2Controller.h" #include "RGBController_LianLiUniHubSLV2.h" +#include "LianLiUniHubSLInfinityController.h" +#include "RGBController_LianLiUniHubSLInfinity.h" /*-----------------------------------------------------*\ | ENE USB vendor ID | @@ -48,6 +50,7 @@ \*-----------------------------------------------------*/ #define UNI_HUB_PID 0x7750 #define UNI_HUB_AL_PID 0xA101 +#define UNI_HUB_SLINF_PID 0xA102 #define UNI_HUB_SLV2_PID 0xA103 #define UNI_HUB_SLV2_V05_PID 0xA105 @@ -191,6 +194,19 @@ void DetectLianLiUniHubSLV2(hid_device_info* info, const std::string& name) } } /* DetectLianLiUniHubSLV2() */ +void DetectLianLiUniHubSLInfinity(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + LianLiUniHubSLInfinityController* controller = new LianLiUniHubSLInfinityController(dev, info->path, name); + + RGBController_LianLiUniHubSLInfinity* rgb_controller = new RGBController_LianLiUniHubSLInfinity(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} /* DetectLianLiUniHubSLInfinity() */ + void DetectStrimerControllers(hid_device_info* info, const std::string& name) { hid_device* dev = hid_open_path(info->path); @@ -209,6 +225,7 @@ REGISTER_DETECTOR("Lian Li Uni Hub", DetectLianLiUniHub); REGISTER_HID_DETECTOR_IPU("Lian Li Uni Hub - AL", DetectLianLiUniHubAL, ENE_USB_VID, UNI_HUB_AL_PID, 0x01, 0xFF72, 0xA1); REGISTER_HID_DETECTOR_IPU("Lian Li Uni Hub - SL V2", DetectLianLiUniHubSLV2, ENE_USB_VID, UNI_HUB_SLV2_PID, 0x01, 0xFF72, 0xA1); REGISTER_HID_DETECTOR_IPU("Lian Li Uni Hub - SL V2 v0.5", DetectLianLiUniHubSLV2, ENE_USB_VID, UNI_HUB_SLV2_V05_PID, 0x01, 0xFF72, 0xA1); +REGISTER_HID_DETECTOR_IPU("Lian Li Uni Hub - SL Infinity", DetectLianLiUniHubSLInfinity, ENE_USB_VID, UNI_HUB_SLINF_PID, 0x01, 0xFF72, 0xA1); /*---------------------------------------------------------------------------------------------------------*\ | Entries for dynamic UDEV rules | | | diff --git a/Controllers/LianLiController/LianLiUniHubSLInfinityController.cpp b/Controllers/LianLiController/LianLiUniHubSLInfinityController.cpp new file mode 100644 index 00000000..2f0c3892 --- /dev/null +++ b/Controllers/LianLiController/LianLiUniHubSLInfinityController.cpp @@ -0,0 +1,322 @@ +/*-----------------------------------------*\ +| LianLiUniHubSLInfinityController.cpp | +| | +| Driver for Lian Li Uni Hub SL INF USB | +| lighting controller | +| | +| Simon McKenna 2023-20-21 | +| Will Kennedy 01/17/2023 | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#include "LianLiUniHubSLInfinityController.h" + +#include + +using namespace std::chrono_literals; + +LianLiUniHubSLInfinityController::LianLiUniHubSLInfinityController(hid_device* dev_handle, const char* path, std::string dev_name) +{ + dev = dev_handle; + location = path; + name = dev_name; +} + +LianLiUniHubSLInfinityController::~LianLiUniHubSLInfinityController() +{ + hid_close(dev); +} + +std::string LianLiUniHubSLInfinityController::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string LianLiUniHubSLInfinityController::GetFirmwareVersionString() +{ + wchar_t product_string[40]; + int ret = hid_get_product_string(dev, product_string, 40); + + if (ret != 0) + { + return (""); + } + + std::wstring return_wstring = product_string; + std::string return_string(return_wstring.begin(),return_wstring.end()); + + return(return_string.substr(return_string.find_last_of("-")+1,4).c_str()); +} + +std::string LianLiUniHubSLInfinityController::GetName() +{ + return(name); +} + +std::string LianLiUniHubSLInfinityController::GetSerialString() +{ + wchar_t serial_string[20]; + int ret = hid_get_serial_number_string(dev, serial_string, 20); + + if (ret != 0) + { + return (""); + } + + std::wstring return_wstring = serial_string; + std::string return_string(return_wstring.begin(), return_wstring.end()); + + return(return_string); + +} + +float infinityBrightnessLimit(RGBColor color) +{ + /*---------------------------------------------------------*\ + | Limiter to protect LEDs | + \*---------------------------------------------------------*/ + if(UNIHUB_SLINF_LED_LIMITER && (RGBGetRValue(color) + RGBGetBValue(color) + RGBGetGValue(color) > 460)) + { + return 460.f / (RGBGetRValue(color) + RGBGetBValue(color) + RGBGetGValue(color)); + } + return 1; +} + +void LianLiUniHubSLInfinityController::SetChannelLEDs(unsigned char channel, RGBColor * colors, unsigned int num_colors, float brightness) +{ + unsigned char led_data[16 * 6 * 3]; + int fan_idx = 0; + int mod_led_idx; + int cur_led_idx; + + if(num_colors == 0) + { + return; // Do nothing, channel isn't in use + } + + for(unsigned int led_idx = 0; led_idx < num_colors; led_idx++) + { + mod_led_idx = (led_idx % 16); + + if((mod_led_idx == 0) && (led_idx != 0)) + { + fan_idx++; + } + + float brightness_scale = brightness * infinityBrightnessLimit(colors[led_idx]); + + //Determine current position of led_data array from colors array + cur_led_idx = ((mod_led_idx + (fan_idx * 16)) * 3); + + led_data[cur_led_idx + 0] = RGBGetRValue(colors[led_idx]) * brightness_scale; + led_data[cur_led_idx + 1] = RGBGetBValue(colors[led_idx]) * brightness_scale; + led_data[cur_led_idx + 2] = RGBGetGValue(colors[led_idx]) * brightness_scale; + } + + /*---------------------------------------------------------*\ + | Send fan LED data | + \*---------------------------------------------------------*/ + + SendStartAction + ( + channel, // Current channel + (fan_idx + 1) // Number of fans + ); + + SendColorData + ( + channel, // Channel + (fan_idx + 1)*16, + led_data + ); + + SendCommitAction + ( + channel, // Channel + UNIHUB_SLINF_LED_MODE_STATIC_COLOR, // Effect + UNIHUB_SLINF_LED_SPEED_000, // Speed + UNIHUB_SLINF_LED_DIRECTION_LTR, // Direction + UNIHUB_SLINF_LED_BRIGHTNESS_100 // Brightness + ); + +} + +void LianLiUniHubSLInfinityController::SetChannelMode(unsigned char channel, const mode active_mode, unsigned int num_fans) +{ + static unsigned int brightness_code[5] = + { + UNIHUB_SLINF_LED_BRIGHTNESS_000, + UNIHUB_SLINF_LED_BRIGHTNESS_025, + UNIHUB_SLINF_LED_BRIGHTNESS_050, + UNIHUB_SLINF_LED_BRIGHTNESS_075, + UNIHUB_SLINF_LED_BRIGHTNESS_100 + }; + + static unsigned int speed_code[5] = + { + UNIHUB_SLINF_LED_SPEED_000, + UNIHUB_SLINF_LED_SPEED_025, + UNIHUB_SLINF_LED_SPEED_050, + UNIHUB_SLINF_LED_SPEED_075, + UNIHUB_SLINF_LED_SPEED_100 + }; + + unsigned char fan_led_data[16 * 6 * 3]; + int cur_led_idx; + float brightness; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(fan_led_data, 0x00, sizeof(fan_led_data)); + + std::vector colors = active_mode.colors; + unsigned int num_colors = colors.size(); + + if(!colors.empty()) // Update led_data if there's colors + { + brightness = static_cast(active_mode.brightness)/4; + if (num_colors == 6) + { + for(unsigned int i = 0; i < 6; i++) + { + float brightness_scale = brightness * infinityBrightnessLimit(colors[i]); + for(unsigned int led_idx = 0; led_idx < 16 * 3; led_idx += 3) + { + cur_led_idx = (i * 16 * 3) + led_idx; + fan_led_data[cur_led_idx + 0] = (RGBGetRValue(colors[i]) * brightness_scale); + fan_led_data[cur_led_idx + 1] = (RGBGetBValue(colors[i]) * brightness_scale); + fan_led_data[cur_led_idx + 2] = (RGBGetGValue(colors[i]) * brightness_scale); + } + } + } + else + { + colors.resize(4); + for(unsigned int i = num_colors; i < 4; i++) + { + colors[i] = 0x00; + } + + // needs a 72 length array of 4 colors, even if less are defined + for(unsigned int j = 0; j < 4; j++) + { + float brightness_scale = brightness * infinityBrightnessLimit(colors[j]); + for(unsigned int i = 0; i < 6; i++) + { + cur_led_idx = (i * 12) + (j * 3); + fan_led_data[cur_led_idx + 0] = RGBGetRValue(colors[j]) * brightness_scale; + fan_led_data[cur_led_idx + 1] = RGBGetBValue(colors[j]) * brightness_scale; + fan_led_data[cur_led_idx + 2] = RGBGetGValue(colors[j]) * brightness_scale; + } + } + } + + } + + SendStartAction + ( + channel, // Current channel + (num_fans + 1) // Number of fans + ); + + SendColorData + ( + channel, // Channel + (num_fans + 1)*16, + fan_led_data // Data + ); + + SendCommitAction + ( + channel, // Channel + active_mode.value, // Effect + speed_code[active_mode.speed], // Speed + active_mode.direction, // Direction + brightness_code[active_mode.brightness] // Brightness + ); +} + +void LianLiUniHubSLInfinityController::SendStartAction(unsigned char channel, unsigned int num_fans) +{ + unsigned char usb_buf[65]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Set up message packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = UNIHUB_SLINF_TRANSACTION_ID; + usb_buf[0x01] = 0x10; + usb_buf[0x02] = 0x60; + usb_buf[0x03] = 1 + (channel / 2); // every fan-array uses two channels (one for the spinner and one for the led-band on the side) + usb_buf[0x04] = 0x04; // TODO: number of fans (1-4) on this channel, hardcoding this to 4 for now + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, sizeof(usb_buf)); + std::this_thread::sleep_for(5ms); + +} + +void LianLiUniHubSLInfinityController::SendColorData(unsigned char channel, unsigned int num_leds, unsigned char* led_data) +{ + /*---------------------------------------------------------*\ + | Send LED data | + \*---------------------------------------------------------*/ + + unsigned char usb_buf[353]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Set up message packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = UNIHUB_SLINF_TRANSACTION_ID; + usb_buf[0x01] = 0x30 + channel; // action + channel(30 = channel 1, 31 = channel 2, etc.) + + /*-----------------------------------------------------*\ + | Copy in color data bytes | + \*-----------------------------------------------------*/ + memcpy(&usb_buf[0x02], led_data, num_leds * 3); + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, sizeof(usb_buf)); + std::this_thread::sleep_for(5ms); +} + +void LianLiUniHubSLInfinityController::SendCommitAction(unsigned char channel, unsigned char effect, unsigned char speed, unsigned int direction, unsigned int brightness) +{ + unsigned char usb_buf[65]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Set up message packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = UNIHUB_SLINF_TRANSACTION_ID; + usb_buf[0x01] = 0x10 + channel; // Channel+device (10 = channel 1, 11 = channel 2, etc.) + usb_buf[0x02] = effect; // Effect + usb_buf[0x03] = speed; // Speed, 02=0%, 01=25%, 00=50%, ff=75%, fe=100% + usb_buf[0x04] = direction; // Direction, right=00, left=01 + usb_buf[0x05] = brightness; // Brightness, 0=100%, 1= 75%, 2 = 50%, 3 = 25%, 8 = 0% + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, sizeof(usb_buf)); + std::this_thread::sleep_for(5ms); +} diff --git a/Controllers/LianLiController/LianLiUniHubSLInfinityController.h b/Controllers/LianLiController/LianLiUniHubSLInfinityController.h new file mode 100644 index 00000000..e582d1a9 --- /dev/null +++ b/Controllers/LianLiController/LianLiUniHubSLInfinityController.h @@ -0,0 +1,225 @@ +/*----------------------------------------------*\ +| LianLiHubSLInfinityController.h | +| | +| Definitions and types for Lian Li SL Infinity | +| | +| Simon McKenna 2023-20-21 | +| Will Kennedy 01/17/2023 | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*----------------------------------------------*/ + +#include "RGBController.h" + +#include +#include + +#pragma once + +/*----------------------------------------------------------------------------*\ +| Global definitions. | +\*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*\ +| Definitions related to zone Sizes | +\*----------------------------------------------------------------------------*/ + + +enum +{ + UNIHUB_SLINF_CHANNEL_COUNT = 0x08, /* Channel count */ + UNIHUB_SLINF_CHAN_LED_COUNT = 0x10 * 6, /* Max-LED per channel count - 96 */ +}; + +/*----------------------------------------------------------------------------*\ +| Definitions related to LED configuration. | +\*----------------------------------------------------------------------------*/ + +// Used for sync'd mode between Fan and Edge + +enum +{ + UNIHUB_SLINF_LED_MODE_STATIC_COLOR = 0x01, // full data array + UNIHUB_SLINF_LED_MODE_BREATHING = 0x02, // full data array + UNIHUB_SLINF_LED_MODE_RAINBOW_MORPH = 0x04, // no array + UNIHUB_SLINF_LED_MODE_RAINBOW = 0x05, // no array + UNIHUB_SLINF_LED_MODE_STAGGERED = 0x18, // size 2 + UNIHUB_SLINF_LED_MODE_TIDE = 0x1A, // size 2 + UNIHUB_SLINF_LED_MODE_RUNWAY = 0x1C, // size 2 + UNIHUB_SLINF_LED_MODE_MIXING = 0x1E, // size 2 + UNIHUB_SLINF_LED_MODE_STACK = 0x20, // size 1 + UNIHUB_SLINF_LED_MODE_STACK_MULTI_COLOR = 0x21, // no array + UNIHUB_SLINF_LED_MODE_NEON = 0x22, // no array + UNIHUB_SLINF_LED_MODE_COLOR_CYCLE = 0x23, // size 3 + UNIHUB_SLINF_LED_MODE_METEOR = 0x24, // size 2 + UNIHUB_SLINF_LED_MODE_VOICE = 0x26, // no array + UNIHUB_SLINF_LED_MODE_GROOVE = 0x27, // size 2 + UNIHUB_SLINF_LED_MODE_RENDER = 0x28, // size 4 + UNIHUB_SLINF_LED_MODE_TUNNEL = 0x29, // size 4 + // merged modes + UNIHUB_SLINF_LED_MODE_METEOR_MERGED = 0x2A, + UNIHUB_SLINF_LED_MODE_RUNWAY_MERGED = 0x2B, + UNIHUB_SLINF_LED_MODE_TIDE_MERGED = 0x2C, + UNIHUB_SLINF_LED_MODE_MIXING_MERGED = 0x2D, + UNIHUB_SLINF_LED_MODE_STACK_MULTI_COLOR_MERGED = 0x2E +}; + +enum +{ + UNIHUB_SLINF_LED_SPEED_000 = 0x02, /* Very slow speed */ + UNIHUB_SLINF_LED_SPEED_025 = 0x01, /* Rather slow speed */ + UNIHUB_SLINF_LED_SPEED_050 = 0x00, /* Medium speed */ + UNIHUB_SLINF_LED_SPEED_075 = 0xFF, /* Rather fast speed */ + UNIHUB_SLINF_LED_SPEED_100 = 0xFE, /* Very fast speed */ +}; + +enum +{ + UNIHUB_SLINF_LED_DIRECTION_LTR = 0x00, /* Left-to-Right direction */ + UNIHUB_SLINF_LED_DIRECTION_RTL = 0x01, /* Right-to-Left direction */ +}; + +enum +{ + UNIHUB_SLINF_LED_BRIGHTNESS_000 = 0x08, /* Very dark (off) */ + UNIHUB_SLINF_LED_BRIGHTNESS_025 = 0x03, /* Rather dark */ + UNIHUB_SLINF_LED_BRIGHTNESS_050 = 0x02, /* Medium bright */ + UNIHUB_SLINF_LED_BRIGHTNESS_075 = 0x01, /* Rather bright */ + UNIHUB_SLINF_LED_BRIGHTNESS_100 = 0x00, /* Very bright */ +}; + +enum +{ + UNIHUB_SLINF_LED_LIMITER = 0x01 /* Limit the color white to 999999 as per manufacturer limits */ +}; + + +/*----------------------------------------------------------------------------*\ +| Definitions related to packet configuration. | +\*----------------------------------------------------------------------------*/ + +enum +{ + UNIHUB_SLINF_TRANSACTION_ID = 0xE0, /* Command value to start all packets */ +}; + +/*----------------------------------------------------------------------------*\ +| Uni Hub SL Infinity controller. | +\*----------------------------------------------------------------------------*/ + +class LianLiUniHubSLInfinityController +{ + + +public: + LianLiUniHubSLInfinityController(hid_device* dev_handle, const char* path, std::string dev_name); + ~LianLiUniHubSLInfinityController(); + + std::string GetDeviceLocation(); + std::string GetFirmwareVersionString(); + std::string GetName(); + std::string GetSerialString(); + + void SetChannelMode + ( + unsigned char channel, + const mode active_mode, + unsigned int num_fans + ); + + void SetChannelLEDs + ( + unsigned char channel, + RGBColor * colors, + unsigned int num_colors, + float brightness + ); + + void SendStartAction + ( + unsigned char channel, + unsigned int num_fans + ); + + void SendColorData + ( + unsigned char channel, // Zone index + unsigned int num_leds, + unsigned char* led_data // Color data payload + ); + + void SendCommitAction + ( + unsigned char channel, // Zone index + unsigned char effect, + unsigned char speed, + unsigned int direction, + unsigned int brightness + ); + +private: + /* The Uni Hub requires colors in RBG order */ + struct Color + { + uint8_t r; + uint8_t b; + uint8_t g; + }; + + /* The values correspond to the definitions above */ + struct Channel + { + uint8_t index; + + uint8_t anyFanCountOffset; + uint8_t anyFanCount; + + uint16_t ledActionAddress; + uint16_t ledCommitAddress; + uint16_t ledModeAddress; + uint16_t ledSpeedAddress; + uint16_t ledDirectionAddress; + uint16_t ledBrightnessAddress; + + Color colors[UNIHUB_SLINF_CHAN_LED_COUNT]; + + uint8_t ledMode; + uint8_t ledSpeed; + uint8_t ledDirection; + uint8_t ledBrightness; + + uint16_t fanHubActionAddress; + uint16_t fanHubCommitAddress; + + uint16_t fanPwmActionAddress; + uint16_t fanPwmCommitAddress; + uint16_t fanRpmActionAddress; + + uint16_t fanSpeed; + }; + +private: + hid_device* dev; + unsigned short dev_pid; + + /*---------------------------------------------------------*\ + | Device-specific protocol settings | + \*---------------------------------------------------------*/ + unsigned char dev_transaction_id; + unsigned char dev_led_id; + + /*---------------------------------------------------------*\ + | Device information strings | + \*---------------------------------------------------------*/ + std::string firmware_version; + std::string location; + std::string name; + device_type type; + + /*---------------------------------------------------------*\ + | HID report index for request and response | + \*---------------------------------------------------------*/ + unsigned char report_index; + unsigned char response_index; + +}; diff --git a/Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.cpp b/Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.cpp new file mode 100644 index 00000000..e423baf0 --- /dev/null +++ b/Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.cpp @@ -0,0 +1,453 @@ +/*-----------------------------------------*\ +| RGBController_LianLiUniHubSLInfinity.cpp | +| | +| Generic RGB Interface for Lian Li Uni | +| Hub SLINF USB controller driver | +| | +| Simon McKenna 2023-20-21 | +| Will Kennedy 01/17/2023 | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#include "RGBController_LianLiUniHubSLInfinity.h" + +#include + +/**------------------------------------------------------------------*\ + @name Lian Li Uni Hub SL Infinity + @type USB + @save :x: + @direct :rotating_light: + @effects :white_check_mark: + @detectors DetectLianLiUniHubSLInfinity + @comment +\*-------------------------------------------------------------------*/ + +RGBController_LianLiUniHubSLInfinity::RGBController_LianLiUniHubSLInfinity(LianLiUniHubSLInfinityController* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetName(); + vendor = "Lian Li"; + type = DEVICE_TYPE_COOLER; + description = "Lian Li Uni Hub - SL Infinity"; + version = controller->GetFirmwareVersionString(); + location = controller->GetDeviceLocation(); + serial = controller->GetSerialString(); + + initializedMode = false; + + mode Custom; + Custom.name = "Custom"; + Custom.value = UNIHUB_SLINF_LED_MODE_STATIC_COLOR; + Custom.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_PER_LED_COLOR; + Custom.brightness_min = 0; + Custom.brightness_max = 50; + Custom.brightness = 37; + Custom.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Custom); + + mode StaticColor; + StaticColor.name = "Static"; + StaticColor.value = UNIHUB_SLINF_LED_MODE_STATIC_COLOR; + StaticColor.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS; + StaticColor.brightness_min = 0; + StaticColor.brightness_max = 4; + StaticColor.colors_min = 0; + StaticColor.colors_max = 6; + StaticColor.brightness = 4; + StaticColor.color_mode = MODE_COLORS_MODE_SPECIFIC; + StaticColor.colors.resize(6); + modes.push_back(StaticColor); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = UNIHUB_SLINF_LED_MODE_BREATHING; + Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Breathing.speed_min = 0; + Breathing.speed_max = 4; + Breathing.brightness_min = 0; + Breathing.brightness_max = 4; + Breathing.colors_min = 0; + Breathing.colors_max = 6; + Breathing.speed = 2; + Breathing.brightness = 4; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.colors.resize(6); + modes.push_back(Breathing); + + mode RainbowMorph; + RainbowMorph.name = "Spectrum Cycle"; + RainbowMorph.value = UNIHUB_SLINF_LED_MODE_RAINBOW_MORPH; + RainbowMorph.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS; + RainbowMorph.speed_min = 0; + RainbowMorph.speed_max = 4; + RainbowMorph.brightness_min = 0; + RainbowMorph.brightness_max = 4; + RainbowMorph.speed = 2; + RainbowMorph.brightness = 4; + RainbowMorph.color_mode = MODE_COLORS_NONE; + modes.push_back(RainbowMorph); + + mode RainbowWave; + RainbowWave.name = "Rainbow Wave"; + RainbowWave.value = UNIHUB_SLINF_LED_MODE_RAINBOW; + RainbowWave.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_DIRECTION_LR; + RainbowWave.speed_min = 0; + RainbowWave.speed_max = 4; + RainbowWave.brightness_min = 0; + RainbowWave.brightness_max = 4; + RainbowWave.speed = 2; + RainbowWave.brightness = 4; + RainbowWave.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + RainbowWave.color_mode = MODE_COLORS_NONE; + modes.push_back(RainbowWave); + + mode Staggered; + Staggered.name = "Staggered"; + Staggered.value = UNIHUB_SLINF_LED_MODE_STAGGERED; + Staggered.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Staggered.speed_min = 0; + Staggered.speed_max = 4; + Staggered.brightness_min = 0; + Staggered.brightness_max = 4; + Staggered.colors_min = 0; + Staggered.colors_max = 2; + Staggered.speed = 2; + Staggered.brightness = 4; + Staggered.color_mode = MODE_COLORS_MODE_SPECIFIC; + Staggered.colors.resize(2); + modes.push_back(Staggered); + + mode Tide; // TODO: Has merge + Tide.name = "Tide"; + Tide.value = UNIHUB_SLINF_LED_MODE_TIDE; + Tide.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Tide.speed_min = 0; + Tide.speed_max = 4; + Tide.brightness_min = 0; + Tide.brightness_max = 4; + Tide.colors_min = 0; + Tide.colors_max = 2; + Tide.speed = 2; + Tide.brightness = 4; + Tide.color_mode = MODE_COLORS_MODE_SPECIFIC; + Tide.colors.resize(2); + modes.push_back(Tide); + + mode Runway; //TODO: Has merge + Runway.name = "Runway"; + Runway.value = UNIHUB_SLINF_LED_MODE_RUNWAY; + Runway.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Runway.speed_min = 0; + Runway.speed_max = 4; + Runway.brightness_min = 0; + Runway.brightness_max = 4; + Runway.colors_min = 0; + Runway.colors_max = 2; + Runway.speed = 2; + Runway.brightness = 4; + Runway.color_mode = MODE_COLORS_MODE_SPECIFIC; + Runway.colors.resize(2); + modes.push_back(Runway); + + mode Mixing; //TODO: Has merge + Mixing.name = "Mixing"; + Mixing.value = UNIHUB_SLINF_LED_MODE_MIXING; + Mixing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Mixing.speed_min = 0; + Mixing.speed_max = 4; + Mixing.brightness_min = 0; + Mixing.brightness_max = 4; + Mixing.colors_min = 0; + Mixing.colors_max = 2; + Mixing.speed = 2; + Mixing.brightness = 4; + Mixing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Mixing.colors.resize(2); + modes.push_back(Mixing); + + mode Stack; + Stack.name = "Stack"; + Stack.value = UNIHUB_SLINF_LED_MODE_STACK; + Stack.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Stack.speed_min = 0; + Stack.speed_max = 4; + Stack.brightness_min = 0; + Stack.brightness_max = 4; + Stack.colors_min = 0; + Stack.colors_max = 1; + Stack.speed = 2; + Stack.brightness = 4; + Stack.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + Stack.color_mode = MODE_COLORS_MODE_SPECIFIC; + Stack.colors.resize(1); + modes.push_back(Stack); + + mode StackMultiColor; //TODO: Has merge + Stack.name = "Stack Multi Color"; + Stack.value = UNIHUB_SLINF_LED_MODE_STACK_MULTI_COLOR; + Stack.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_DIRECTION_LR; + Stack.speed_min = 0; + Stack.speed_max = 4; + Stack.brightness_min = 0; + Stack.brightness_max = 4; + Stack.speed = 2; + Stack.brightness = 4; + Stack.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + Stack.color_mode = MODE_COLORS_NONE; + modes.push_back(Stack); + + mode Neon; + Neon.name = "Neon"; + Neon.value = UNIHUB_SLINF_LED_MODE_NEON; + Neon.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS; + Neon.speed_min = 0; + Neon.speed_max = 4; + Neon.brightness_min = 0; + Neon.brightness_max = 4; + Neon.speed = 2; + Neon.brightness = 4; + Neon.color_mode = MODE_COLORS_NONE; + modes.push_back(Neon); + + mode ColorCycle; + ColorCycle.name = "ColorCycle"; + ColorCycle.value = UNIHUB_SLINF_LED_MODE_COLOR_CYCLE; + ColorCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + ColorCycle.speed_min = 0; + ColorCycle.speed_max = 4; + ColorCycle.brightness_min = 0; + ColorCycle.brightness_max = 4; + ColorCycle.colors_min = 0; + ColorCycle.colors_max = 3; + ColorCycle.speed = 2; + ColorCycle.brightness = 4; + ColorCycle.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + ColorCycle.color_mode = MODE_COLORS_MODE_SPECIFIC; + ColorCycle.colors.resize(3); + modes.push_back(ColorCycle); + + mode Meteor; //TODO: Has merge + Meteor.name = "Meteor"; + Meteor.value = UNIHUB_SLINF_LED_MODE_METEOR; + Meteor.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Meteor.speed_min = 0; + Meteor.speed_max = 4; + Meteor.brightness_min = 0; + Meteor.brightness_max = 4; + Meteor.colors_min = 0; + Meteor.colors_max = 2; + Meteor.speed = 2; + Meteor.brightness = 4; + Meteor.color_mode = MODE_COLORS_MODE_SPECIFIC; + Meteor.colors.resize(2); + modes.push_back(Meteor); + + mode Voice; + Voice.name = "Voice"; + Voice.value = UNIHUB_SLINF_LED_MODE_VOICE; + Voice.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS; + Voice.speed_min = 0; + Voice.speed_max = 4; + Voice.brightness_min = 0; + Voice.brightness_max = 4; + Voice.speed = 2; + Voice.brightness = 4; + modes.push_back(Voice); + + mode Groove; + Groove.name = "Groove"; + Groove.value = UNIHUB_SLINF_LED_MODE_GROOVE; + Groove.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Groove.speed_min = 0; + Groove.speed_max = 4; + Groove.brightness_min = 0; + Groove.brightness_max = 4; + Groove.colors_min = 0; + Groove.colors_max = 1; + Groove.speed = 2; + Groove.brightness = 4; + Groove.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + Groove.color_mode = MODE_COLORS_MODE_SPECIFIC; + Groove.colors.resize(1); + modes.push_back(Groove); + + mode Render; + Render.name = "Render"; + Render.value = UNIHUB_SLINF_LED_MODE_RENDER; + Render.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Render.speed_min = 0; + Render.speed_max = 4; + Render.brightness_min = 0; + Render.brightness_max = 4; + Render.colors_min = 0; + Render.colors_max = 4; + Render.speed = 2; + Render.brightness = 4; + Render.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + Render.color_mode = MODE_COLORS_MODE_SPECIFIC; + Render.colors.resize(4); + modes.push_back(Render); + + mode Tunnel; + Tunnel.name = "Tunnel"; + Tunnel.value = UNIHUB_SLINF_LED_MODE_TUNNEL; + Tunnel.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Tunnel.speed_min = 0; + Tunnel.speed_max = 4; + Tunnel.brightness_min = 0; + Tunnel.brightness_max = 4; + Tunnel.colors_min = 0; + Tunnel.colors_max = 4; + Tunnel.speed = 2; + Tunnel.brightness = 4; + Tunnel.direction = UNIHUB_SLINF_LED_DIRECTION_LTR; + Tunnel.color_mode = MODE_COLORS_MODE_SPECIFIC; + Tunnel.colors.resize(4); + modes.push_back(Tunnel); + + RGBController_LianLiUniHubSLInfinity::SetupZones(); +} + +RGBController_LianLiUniHubSLInfinity::~RGBController_LianLiUniHubSLInfinity() +{ + delete controller; +} + +void RGBController_LianLiUniHubSLInfinity::SetupZones() +{ + /*-------------------------------------------------*\ + | Only set LED count on the first run | + \*-------------------------------------------------*/ + bool first_run = false; + + if(zones.size() == 0) + { + first_run = true; + zones.resize(UNIHUB_SLINF_CHANNEL_COUNT); + } + + /*-------------------------------------------------*\ + | Clear any existing color/LED configuration | + \*-------------------------------------------------*/ + leds.clear(); + colors.clear(); + + /*-------------------------------------------------*\ + | Set zones and leds | + \*-------------------------------------------------*/ + for(unsigned int channel_idx = 0; channel_idx < zones.size(); channel_idx++) + { + zones[channel_idx].name = "Channel "; + zones[channel_idx].name.append(std::to_string(channel_idx + 1)); + + zones[channel_idx].type = ZONE_TYPE_LINEAR; + zones[channel_idx].leds_min = 0; + zones[channel_idx].leds_max = UNIHUB_SLINF_CHAN_LED_COUNT; + + if(first_run) + { + zones[channel_idx].leds_count = zones[channel_idx].leds_min; + } + + for(unsigned int led_ch_idx = 0; led_ch_idx < zones[channel_idx].leds_count; led_ch_idx++) + { + led new_led; + new_led.name = zones[channel_idx].name; + new_led.name.append(", LED "); + new_led.name.append(std::to_string(led_ch_idx + 1)); + new_led.value = channel_idx; + + leds.push_back(new_led); + } + + } + + SetupColors(); +} + +void RGBController_LianLiUniHubSLInfinity::ResizeZone(int zone, int new_size) +{ + if((size_t) zone >= zones.size()) + { + return; + } + + if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max)) + { + zones[zone].leds_count = new_size; + + SetupZones(); + } +} + +void RGBController_LianLiUniHubSLInfinity::DeviceUpdateLEDs() +{ + + if(!initializedMode) + { + DeviceUpdateMode(); + } + + float brightness_scale = static_cast(modes[active_mode].brightness)/modes[active_mode].brightness_max; + + for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + controller->SetChannelLEDs(zone_idx, zones[zone_idx].colors, zones[zone_idx].leds_count, brightness_scale); + } +} + +void RGBController_LianLiUniHubSLInfinity::UpdateZoneLEDs(int zone) +{ + if(!initializedMode) + { + DeviceUpdateMode(); + } + + float brightness_scale = static_cast(modes[active_mode].brightness)/modes[active_mode].brightness_max; + + controller->SetChannelLEDs(zone, zones[zone].colors, zones[zone].leds_count, brightness_scale); +} + +void RGBController_LianLiUniHubSLInfinity::UpdateSingleLED(int /* led */) +{ + DeviceUpdateMode(); + +} + +void RGBController_LianLiUniHubSLInfinity::DeviceUpdateMode() +{ + if(!active_mode) + { + return; // Do nothing, custom mode should go through DeviceUpdateLEDs() to avoid flooding controller + } + + initializedMode = true; + + int fan_idx = 0; + + for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + if(zones[zone_idx].leds_count == 0) + { + return; // Do nothing, channel isn't in use + } + fan_idx = ((zones[zone_idx].leds_count / 16) - 1); // Indexes start at 0 + + controller->SetChannelMode(zone_idx, + modes[active_mode], + fan_idx); + + } +} + +void RGBController_LianLiUniHubSLInfinity::SetCustomMode() +{ + /*-------------------------------------------------*\ + | Set mode to Static Color | + \*-------------------------------------------------*/ + active_mode = 0; +} + diff --git a/Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.h b/Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.h new file mode 100644 index 00000000..a222b951 --- /dev/null +++ b/Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.h @@ -0,0 +1,42 @@ +/*-----------------------------------------*\ +| RGBController_LianLiUniHubSLInfinity.h | +| | +| Generic RGB Interface for Lian Li Uni | +| Hub SL Infinity USB controller driver | +| | +| Simon McKenna 2023-20-21 | +| Will Kennedy 01/17/2023 | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#pragma once + +#include +#include + +#include "LianLiUniHubSLInfinityController.h" +#include "RGBController.h" + +class RGBController_LianLiUniHubSLInfinity : public RGBController +{ +public: + RGBController_LianLiUniHubSLInfinity(LianLiUniHubSLInfinityController* controller_ptr); + ~RGBController_LianLiUniHubSLInfinity(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + + void SetCustomMode(); + +private: + LianLiUniHubSLInfinityController* controller; + bool initializedMode; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index f41aa9a2..fa9053ec 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -600,6 +600,8 @@ HEADERS += Controllers/LianLiController/LianLiUniHubALController.h \ Controllers/LianLiController/RGBController_LianLiUniHubAL.h \ Controllers/LianLiController/RGBController_LianLiUniHub_AL10.h \ + Controllers/LianLiController/LianLiUniHubSLInfinityController.h \ + Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.h \ Controllers/LianLiController/LianLiUniHubSLV2Controller.h \ Controllers/LianLiController/RGBController_LianLiUniHubSLV2.h \ Controllers/LogitechController/LogitechProtocolCommon.h \ @@ -1285,6 +1287,8 @@ SOURCES += Controllers/LianLiController/StrimerLConnectController.cpp \ Controllers/LianLiController/LianLiUniHubALController.cpp \ Controllers/LianLiController/RGBController_LianLiUniHubAL.cpp \ + Controllers/LianLiController/LianLiUniHubSLInfinityController.cpp \ + Controllers/LianLiController/RGBController_LianLiUniHubSLInfinity.cpp \ Controllers/LianLiController/LianLiUniHubSLV2Controller.cpp \ Controllers/LianLiController/RGBController_LianLiUniHubSLV2.cpp \ Controllers/LogitechController/LogitechControllerDetect.cpp \