diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 331a6b79..304e2912 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -110,7 +110,7 @@ before_script: script: - dpkg-architecture -l - dpkg-buildpackage --target-arch i386 -us -B - - rm -v ../openrgb-dbgsym*.deb + - rm -v ../openrgb-dbgsym*.*deb - mv -v ../openrgb*.deb ./ artifacts: @@ -118,7 +118,7 @@ before_script: paths: - openrgb*.deb exclude: - - openrgb-dbgsym*.deb + - openrgb-dbgsym*.*deb expire_in: 30 days rules: @@ -138,7 +138,7 @@ before_script: script: - dpkg-architecture -l - dpkg-buildpackage -us -B - - rm -v ../openrgb-dbgsym*.deb + - rm -v ../openrgb-dbgsym*.*deb - mv -v ../openrgb*.deb ./ artifacts: @@ -146,7 +146,7 @@ before_script: paths: - openrgb*.deb exclude: - - openrgb-dbgsym*.deb + - openrgb-dbgsym*.*deb expire_in: 30 days rules: @@ -166,7 +166,7 @@ before_script: script: - dpkg-architecture -l - dpkg-buildpackage --target-arch i386 -us -B - - rm -v ../openrgb-dbgsym*.deb + - rm -v ../openrgb-dbgsym*.*deb - mv -v ../openrgb*.deb ./ artifacts: @@ -174,7 +174,7 @@ before_script: paths: - openrgb*.deb exclude: - - openrgb-dbgsym*.deb + - openrgb-dbgsym*.*deb expire_in: 30 days rules: @@ -194,7 +194,7 @@ before_script: script: - dpkg-architecture -l - dpkg-buildpackage -us -B - - rm -v ../openrgb-dbgsym*.deb + - rm -v ../openrgb-dbgsym*.*deb - mv -v ../openrgb*.deb ./ artifacts: @@ -202,7 +202,7 @@ before_script: paths: - openrgb*.deb exclude: - - openrgb-dbgsym*.deb + - openrgb-dbgsym*.*deb expire_in: 30 days rules: diff --git a/Controllers/LianLiController/LianLiControllerDetect.cpp b/Controllers/LianLiController/LianLiControllerDetect.cpp index 35633211..a83267e3 100644 --- a/Controllers/LianLiController/LianLiControllerDetect.cpp +++ b/Controllers/LianLiController/LianLiControllerDetect.cpp @@ -7,10 +7,9 @@ | Luca Lovisa 2/20/2021 | \*-----------------------------------------*/ -/*-----------------------------------------------------*\ -| OpenRGB includes | -\*-----------------------------------------------------*/ -#include +#include +#include + #include "Detector.h" #include "ResourceManager.h" @@ -25,6 +24,12 @@ \*-----------------------------------------------------*/ #include "RGBController_LianLiUniHub.h" #include "RGBController_StrimerLConnect.h" +#include "LianLiUniHubController.h" +#include "RGBController_LianLiUniHub.h" +#include "LianLiUniHubALController.h" +#include "RGBController_LianLiUniHubAL.h" +#include "LianLiUniHub_AL10Controller.h" +#include "RGBController_LianLiUniHub_AL10.h" /*-----------------------------------------------------*\ | ENE USB vendor ID | @@ -40,6 +45,7 @@ | Fan controller product IDs | \*-----------------------------------------------------*/ #define UNI_HUB_PID 0x7750 +#define UNI_HUB_AL_PID 0XA101 /*----------------------------------------------------------------------------*\ | The Uni Hub is controlled by sending control transfers to various wIndex | @@ -73,7 +79,7 @@ void DetectLianLiUniHub(std::vector&) libusb_device_descriptor descriptor; ret = libusb_get_device_descriptor(device, &descriptor); - if (ret < 0) + if(ret < 0) { continue; } @@ -93,6 +99,81 @@ void DetectLianLiUniHub(std::vector&) } } +void DetectLianLiUniHub_AL10(std::vector&) +{ + libusb_device** devices = nullptr; + + int ret; + + ret = libusb_init(NULL); + if(ret < 0) + { + return; + } + + ret = libusb_get_device_list(NULL, &devices); + if(ret < 0) + { + return; + } + + int deviceCount = ret; + + for(int i = 0; i < deviceCount; i++) + { + libusb_device* device = devices[i]; + libusb_device_descriptor descriptor; + ret = libusb_get_device_descriptor(device, &descriptor); + + if(ret < 0) + { + continue; + } + + if( descriptor.idVendor == ENE_USB_VID + && descriptor.idProduct == UNI_HUB_AL_PID) + { + LianLiUniHub_AL10Controller* controller = new LianLiUniHub_AL10Controller(device, &descriptor); + RGBController_LianLiUniHub_AL10* rgb_controller = new RGBController_LianLiUniHub_AL10(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + } + + if(devices != nullptr) + { + libusb_free_device_list(devices, 1); + } +} /* DetectLianLiUniHub_AL10() */ + +void DetectLianLiUniHubAL(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + LianLiUniHubALController* controller = new LianLiUniHubALController(dev, info->path, info->product_id, name); + + std::string firmwareVersion = controller->GetFirmwareVersionString(); + + if(firmwareVersion == "v1.7") + { + RGBController_LianLiUniHubAL* rgb_controller = new RGBController_LianLiUniHubAL(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + else if(firmwareVersion == "v1.0") + { + delete controller; + REGISTER_DETECTOR("Lian Li Uni Hub - AL", DetectLianLiUniHub_AL10); + } + else + { + delete controller; + return; + } + + } +} /* DetectLianLiUniHubAL() */ + void DetectStrimerControllers(hid_device_info* info, const std::string& name) { hid_device* dev = hid_open_path(info->path); @@ -108,6 +189,7 @@ void DetectStrimerControllers(hid_device_info* info, const std::string& name) } 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); /*---------------------------------------------------------------------------------------------------------*\ | Entries for dynamic UDEV rules | | | diff --git a/Controllers/LianLiController/LianLiUniHubALController.cpp b/Controllers/LianLiController/LianLiUniHubALController.cpp new file mode 100644 index 00000000..fa246872 --- /dev/null +++ b/Controllers/LianLiController/LianLiUniHubALController.cpp @@ -0,0 +1,402 @@ +/*-----------------------------------------*\ +| LianLiUniHubALController.cpp | +| | +| Driver for Lian Li Uni Hub AL USB | +| lighting controller | +| | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#include "LianLiUniHubALController.h" + +#include + +using namespace std::chrono_literals; + +LianLiUniHubALController::LianLiUniHubALController(hid_device* dev_handle, const char* path, unsigned short pid, std::string dev_name) +{ + dev = dev_handle; + dev_pid = pid; + location = path; + name = dev_name; +} + +LianLiUniHubALController::~LianLiUniHubALController() +{ + hid_close(dev); +} + +std::string LianLiUniHubALController::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string LianLiUniHubALController::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 LianLiUniHubALController::GetName() +{ + return(name); +} + +std::string LianLiUniHubALController::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); + +} + +void LianLiUniHubALController::SetChannelLEDs(unsigned char channel, RGBColor * colors, unsigned int num_colors, float brightness) +{ + unsigned char fan_led_data[96]; + unsigned char edge_led_data[144]; + 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 % 20); + + if((mod_led_idx == 0) && (led_idx != 0)) + { + fan_idx++; + } + + /*---------------------------------------------------------*\ + | Limiter to protect LEDs | + \*---------------------------------------------------------*/ + if(UNIHUB_AL_LED_LIMITER && RGBGetRValue(colors[led_idx]) > 153 && (RGBGetRValue(colors[led_idx]) == RGBGetBValue(colors[led_idx])) && (RGBGetRValue(colors[led_idx]) == RGBGetGValue(colors[led_idx])) ) + { + colors[led_idx] = ToRGBColor(153,153,153); + } + + if(mod_led_idx < 8) // Fan LEDs, 8 LEDs per fan + { + //Determine current position of led_data array from colors array + cur_led_idx = ((mod_led_idx + (fan_idx * 8)) * 3); + + fan_led_data[cur_led_idx + 0] = RGBGetRValue(colors[led_idx]) * brightness; + fan_led_data[cur_led_idx + 1] = RGBGetBValue(colors[led_idx]) * brightness; + fan_led_data[cur_led_idx + 2] = RGBGetGValue(colors[led_idx]) * brightness; + } + else // Edge LEDs, 12 LEDs per fan + { + //Determine current position of led_data array from colors array + cur_led_idx = (((mod_led_idx - 8) + (fan_idx * 12)) * 3); + + edge_led_data[cur_led_idx + 0] = RGBGetRValue(colors[led_idx]) * brightness; + edge_led_data[cur_led_idx + 1] = RGBGetBValue(colors[led_idx]) * brightness; + edge_led_data[cur_led_idx + 2] = RGBGetGValue(colors[led_idx]) * brightness; + } + } + + /*---------------------------------------------------------*\ + | Send fan LED data | + \*---------------------------------------------------------*/ + + SendStartAction + ( + channel, // Current channel + (fan_idx + 1) // Number of fans + ); + + SendColorData + ( + channel, // Channel + 0, // 0 = Fan, 1 = Edge + (fan_idx + 1)*8, + fan_led_data + ); + + SendCommitAction + ( + channel, // Channel + 0, // 0 = Fan, 1 = Edge + UNIHUB_AL_LED_MODE_STATIC_COLOR, // Effect + UNIHUB_AL_LED_SPEED_000, // Speed + UNIHUB_AL_LED_DIRECTION_LTR, // Direction + UNIHUB_AL_LED_BRIGHTNESS_100 // Brightness + ); + + /*---------------------------------------------------------*\ + | Send edge LED data | + \*---------------------------------------------------------*/ + SendStartAction + ( + channel, // Current channel + (fan_idx + 1) // Number of fans + ); + + SendColorData + ( + channel, // Channel + 1, // 0 = Fan, 1 = Edge + (fan_idx + 1)*12, + edge_led_data + ); + + SendCommitAction + ( + channel, // Channel + 1, // 0 = Fan, 1 = Edge + UNIHUB_AL_LED_MODE_STATIC_COLOR, // Effect + UNIHUB_AL_LED_SPEED_000, // Speed + UNIHUB_AL_LED_DIRECTION_LTR, // Direction + UNIHUB_AL_LED_BRIGHTNESS_100 // Brightness + ); + +} + +void LianLiUniHubALController::SetChannelMode(unsigned char channel, unsigned int mode_value, std::vector colors, unsigned int num_colors, unsigned int num_fans, bool upd_both_fan_edge, unsigned int brightness, unsigned int speed, unsigned int direction) +{ + static unsigned int brightness_code[5] = + { + UNIHUB_AL_LED_BRIGHTNESS_000, + UNIHUB_AL_LED_BRIGHTNESS_025, + UNIHUB_AL_LED_BRIGHTNESS_050, + UNIHUB_AL_LED_BRIGHTNESS_075, + UNIHUB_AL_LED_BRIGHTNESS_100 + }; + + static unsigned int speed_code[5] = + { + UNIHUB_AL_LED_SPEED_000, + UNIHUB_AL_LED_SPEED_025, + UNIHUB_AL_LED_SPEED_050, + UNIHUB_AL_LED_SPEED_075, + UNIHUB_AL_LED_SPEED_100 + }; + + unsigned char fan_led_data[96]; + unsigned char edge_led_data[144]; + int cur_led_idx; + float brightness_scale; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(fan_led_data, 0x00, sizeof(fan_led_data)); + memset(edge_led_data, 0x00, sizeof(edge_led_data)); + + if(num_colors) // Update led_data if there's colors + { + switch(mode_value) + { + case UNIHUB_AL_LED_MODE_STATIC_COLOR: // Static mode requires a full data array + case UNIHUB_AL_LED_MODE_BREATHING: + brightness_scale = static_cast(brightness)/4; + for(unsigned int i = 0; i < 4; i++) + { + /*---------------------------------------------------------*\ + | Limiter to protect LEDs | + \*---------------------------------------------------------*/ + if(UNIHUB_AL_LED_LIMITER && RGBGetRValue(colors[i]) > 153 && (RGBGetRValue(colors[i]) == RGBGetBValue(colors[i])) && (RGBGetRValue(colors[i]) == RGBGetGValue(colors[i])) ) + { + colors[i] = ToRGBColor(153,153,153); + } + + for(unsigned int led_idx = 0; led_idx < 22; led_idx += 3) + { + cur_led_idx = (i * 8 * 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); + } + + for(unsigned int led_idx = 0; led_idx < 34; led_idx += 3) + { + cur_led_idx = (i * 12 * 3) + led_idx; + edge_led_data[cur_led_idx + 0] = (RGBGetRValue(colors[i]) * brightness_scale); + edge_led_data[cur_led_idx + 1] = (RGBGetBValue(colors[i]) * brightness_scale); + edge_led_data[cur_led_idx + 2] = (RGBGetGValue(colors[i]) * brightness_scale); + } + } + break; + + default: + colors.resize(4); + for(unsigned int i = num_colors; i < 4; i++) + { + colors[i] = 0x00; + } + + // needs a 48 length array of 4 colors, even if less are defined + for(unsigned int i = 0; i < 4; i++) + { + for(unsigned int j = 0; j < 4; j++) + { + cur_led_idx = (i * 12) + (j * 3); + fan_led_data[cur_led_idx + 0] = RGBGetRValue(colors[j]); + fan_led_data[cur_led_idx + 1] = RGBGetBValue(colors[j]); + fan_led_data[cur_led_idx + 2] = RGBGetGValue(colors[j]); + } + } + break; + } + + } + + SendStartAction + ( + channel, // Current channel + (num_fans + 1) // Number of fans + ); + + SendColorData + ( + channel, // Channel + 0, // 0 = Fan, 1 = Edge + (num_fans + 1)*8, + fan_led_data // Data + ); + + SendCommitAction + ( + channel, // Channel + 0, // 0 = Fan, 1 = Edge + mode_value, // Effect + speed_code[speed], // Speed + direction, // Direction + brightness_code[brightness] // Brightness + ); + + if(upd_both_fan_edge) + { + SendStartAction + ( + channel, // Current channel + (num_fans + 1) // Number of fans + ); + + SendColorData + ( + channel, // Channel + 1, // 0 = Fan, 1 = Edge + (num_fans + 1)*12, + edge_led_data + ); + + SendCommitAction + ( + channel, // Channel + 1, // 0 = Fan, 1 = Edge + mode_value, // Effect + speed_code[speed], // Speed + direction, // Direction + brightness_code[brightness] // Brightness + ); + } +} + +void LianLiUniHubALController::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_AL_TRANSACTION_ID; + usb_buf[0x01] = 0x10; + usb_buf[0x02] = 0x40; + usb_buf[0x03] = channel + 1; + usb_buf[0x04] = num_fans; + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, 65); + std::this_thread::sleep_for(5ms); + +} + +void LianLiUniHubALController::SendColorData(unsigned char channel, unsigned int fan_or_edge, unsigned int num_leds, unsigned char* led_data) +{ + /*---------------------------------------------------------*\ + | Send edge LED data | + \*---------------------------------------------------------*/ + + unsigned char usb_buf[146]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Set up message packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = UNIHUB_AL_TRANSACTION_ID; + usb_buf[0x01] = 0x30 + fan_or_edge + (channel * 2); // Channel+device (30 = channel 1 edge, 31 = channel 1 edge, 32 = channel 2 fan, 33 = channel 2 edge, etc.) + + /*-----------------------------------------------------*\ + | Copy in color data bytes | + \*-----------------------------------------------------*/ + memcpy(&usb_buf[0x02], led_data, num_leds * 3); + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, 146); + std::this_thread::sleep_for(5ms); +} + +void LianLiUniHubALController::SendCommitAction(unsigned char channel, unsigned int fan_or_edge, 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_AL_TRANSACTION_ID; + usb_buf[0x01] = 0x10 + fan_or_edge + (channel*2); // Channel+device (10 = channel 1 fan, 11 = channel 1 edge, 12 = channel 2 fan, 13 = chanell 2 edge, 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, 65); + std::this_thread::sleep_for(5ms); +} diff --git a/Controllers/LianLiController/LianLiUniHubALController.h b/Controllers/LianLiController/LianLiUniHubALController.h new file mode 100644 index 00000000..87be3291 --- /dev/null +++ b/Controllers/LianLiController/LianLiUniHubALController.h @@ -0,0 +1,229 @@ +/*-----------------------------------------*\ +| LianLiHubALController.h | +| | +| Definitions and types for Lian Li AL120 | +| | +| 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_AL_CHANNEL_COUNT = 0x04, /* Channel count */ + UNIHUB_AL_CHAN_FANLED_COUNT = 0x20, /* Max-LED per channel count - 32 */ + UNIHUB_AL_CHAN_EDGELED_COUNT = 0x30, /* Max-LED per channel count - 48 */ + UNIHUB_AL_CHAN_LED_COUNT = 0x50, /* Max-LED per channel count - 80 */ +}; + +/*----------------------------------------------------------------------------*\ +| Definitions related to LED configuration. | +\*----------------------------------------------------------------------------*/ + +// Used for sync'd mode between Fan and Edge + +enum +{ + UNIHUB_AL_LED_MODE_RAINBOW = 0x28, /* Rainbow mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_RAINBOW_MORPH = 0x35, /* Rainbow Morph mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_STATIC_COLOR = 0x01, /* Static Color mode */ + UNIHUB_AL_LED_MODE_BREATHING = 0x02, /* Breathing mode */ + UNIHUB_AL_LED_MODE_TAICHI = 0x2C, /* Neon mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_COLOR_CYCLE = 0x2B, /* Color Cycle mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_RUNWAY = 0x1A, /* Runway mode */ + UNIHUB_AL_LED_MODE_METEOR = 0x19, /* Meteor mode */ + UNIHUB_AL_LED_MODE_WARNING = 0x2D, /* Warning mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_VOICE = 0x2E, /* Voice mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_SPINNING_TEACUP = 0x38, /* Spinning Teacup mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_TORNADO = 0x36, /* Tornado mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_MIXING = 0x2F, /* Mixing mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_STACK = 0x30, /* Stack mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_STAGGGERED = 0x37, /* Stagggered mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_TIDE = 0x31, /* Tide mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_SCAN = 0x32, /* Scan mode - Calls Fan only */ + UNIHUB_AL_LED_MODE_CONTEST = 0x33, /* Contest mode - Calls Fan only */ + +}; + +enum +{ + UNIHUB_AL_LED_SPEED_000 = 0x02, /* Very slow speed */ + UNIHUB_AL_LED_SPEED_025 = 0x01, /* Rather slow speed */ + UNIHUB_AL_LED_SPEED_050 = 0x00, /* Medium speed */ + UNIHUB_AL_LED_SPEED_075 = 0xFF, /* Rather fast speed */ + UNIHUB_AL_LED_SPEED_100 = 0xFE, /* Very fast speed */ +}; + +enum +{ + UNIHUB_AL_LED_DIRECTION_LTR = 0x00, /* Left-to-Right direction */ + UNIHUB_AL_LED_DIRECTION_RTL = 0x01, /* Right-to-Left direction */ +}; + +enum +{ + UNIHUB_AL_LED_BRIGHTNESS_000 = 0x08, /* Very dark (off) */ + UNIHUB_AL_LED_BRIGHTNESS_025 = 0x03, /* Rather dark */ + UNIHUB_AL_LED_BRIGHTNESS_050 = 0x02, /* Medium bright */ + UNIHUB_AL_LED_BRIGHTNESS_075 = 0x01, /* Rather bright */ + UNIHUB_AL_LED_BRIGHTNESS_100 = 0x00, /* Very bright */ +}; + +enum +{ + UNIHUB_AL_LED_LIMITER = 0x01 /* Limit the color white to 999999 as per manufacturer limits */ +}; + + +/*----------------------------------------------------------------------------*\ +| Definitions related to packet configuration. | +\*----------------------------------------------------------------------------*/ + +enum +{ + UNIHUB_AL_TRANSACTION_ID = 0xE0, /* Command value to start all packets */ +}; + +/*----------------------------------------------------------------------------*\ +| Uni Hub AL controller. | +\*----------------------------------------------------------------------------*/ + +class LianLiUniHubALController +{ + + +public: + LianLiUniHubALController(hid_device* dev_handle, const char* path, unsigned short pid, std::string dev_name); + ~LianLiUniHubALController(); + + std::string GetDeviceLocation(); + std::string GetFirmwareVersionString(); + std::string GetName(); + std::string GetSerialString(); + + void SetChannelMode + ( + unsigned char channel, + unsigned int mode_value, + std::vector colors, // Not a pointer because the copy gets resized + unsigned int num_colors, + unsigned int num_fans, + bool upd_both_fan_edge, + unsigned int brightness, + unsigned int speed, + unsigned int direction + ); + + 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 fan_or_edge, // 1 (Fan) or 0 (Edge) modifer to channel + unsigned int num_leds, + unsigned char* led_data // Color data payload + ); + + void SendCommitAction + ( + unsigned char channel, // Zone index + unsigned int fan_or_edge, // 1 (Fan) or 0 (Edge) modifer to channel + 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_AL_CHAN_FANLED_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/LianLiUniHub_AL10Controller.cpp b/Controllers/LianLiController/LianLiUniHub_AL10Controller.cpp new file mode 100644 index 00000000..ccbbb1ae --- /dev/null +++ b/Controllers/LianLiController/LianLiUniHub_AL10Controller.cpp @@ -0,0 +1,788 @@ +/*-----------------------------------------*\ +| LianLiUniHub_AL10Controller.cpp | +| | +| Driver for Lian Li Uni Hub USB | +| lighting controller | +| | +| Oliver P 05/05/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#include "LianLiUniHub_AL10Controller.h" + +#include + +using namespace std::chrono_literals; + +/*----------------------------------------------------------------------------*\ +| The Uni Hub is controlled by sending control transfers to various wIndex | +| addresses, allthough it announces some kind of hid interface. Hence it | +| requires libusb as hidapi provides no wIndex customization. | +\*----------------------------------------------------------------------------*/ + +LianLiUniHub_AL10Controller::LianLiUniHub_AL10Controller + ( + libusb_device* device, + libusb_device_descriptor* descriptor + ) +{ + int ret; + + /*--------------------------------------------------------------------*\ + | Open the libusb device. | + \*--------------------------------------------------------------------*/ + ret = libusb_open(device, &handle); + + if(ret < 0) + { + return; + } + + /*--------------------------------------------------------------------*\ + | Fill in the location string from USB port numbers. | + \*--------------------------------------------------------------------*/ + uint8_t ports[7]; + + ret = libusb_get_port_numbers(device, ports, sizeof(ports)); + + if(ret > 0) + { + location = "USB: "; + + for (int i = 0; i < ret; i ++) + { + location += std::to_string(ports[i]); + location.push_back(':'); + } + + location.pop_back(); + } + + /*--------------------------------------------------------------------*\ + | Fill in the serial string from the string descriptor | + \*--------------------------------------------------------------------*/ + char serialStr[64]; + + ret = libusb_get_string_descriptor_ascii(handle, descriptor->iSerialNumber, reinterpret_cast(serialStr), sizeof(serialStr)); + + if(ret > 0) + { + serial = std::string(serialStr, ret); + } + + /*--------------------------------------------------------------------*\ + | Fill in the version string by reading version from device. | + \*--------------------------------------------------------------------*/ + version = ReadVersion(); + + /*--------------------------------------------------------------------*\ + | Create channels with their static configuration and "sane" defaults. | + \*--------------------------------------------------------------------*/ + Channel channel1; + channel1.index = 0; + channel1.anyFanCountOffset = UNIHUB_AL10_ANY_C1_FAN_COUNT_OFFSET; + channel1.anyFanCount = UNIHUB_AL10_ANY_FAN_COUNT_001; + channel1.ledActionAddress = UNIHUB_AL10_LED_C1_ACTION_ADDRESS; + channel1.ledCommitAddress = UNIHUB_AL10_LED_C1_COMMIT_ADDRESS; + channel1.ledModeAddress = UNIHUB_AL10_LED_C1_MODE_ADDRESS; + channel1.ledSpeedAddress = UNIHUB_AL10_LED_C1_SPEED_ADDRESS; + channel1.ledDirectionAddress = UNIHUB_AL10_LED_C1_DIRECTION_ADDRESS; + channel1.ledBrightnessAddress = UNIHUB_AL10_LED_C1_BRIGHTNESS_ADDRESS; + channel1.ledMode = UNIHUB_AL10_LED_MODE_RAINBOW; + channel1.ledSpeed = UNIHUB_AL10_LED_SPEED_100; + channel1.ledDirection = UNIHUB_AL10_LED_DIRECTION_LTR; + channel1.ledBrightness = UNIHUB_AL10_LED_BRIGHTNESS_100; + channel1.fanHubActionAddress = UNIHUB_AL10_FAN_C1_HUB_ACTION_ADDRESS; + channel1.fanHubCommitAddress = UNIHUB_AL10_FAN_C1_HUB_COMMIT_ADDRESS; + channel1.fanPwmActionAddress = UNIHUB_AL10_FAN_C1_PWM_ACTION_ADDRESS; + channel1.fanPwmCommitAddress = UNIHUB_AL10_FAN_C1_PWM_COMMIT_ADDRESS; + channel1.fanRpmActionAddress = UNIHUB_AL10_FAN_C1_RPM_ACTION_ADDRESS; + channel1.fanSpeed = UNIHUB_AL10_FAN_SPEED_QUIET; + channels[0] = channel1; + + Channel channel2; + channel2.index = 1; + channel2.anyFanCountOffset = UNIHUB_AL10_ANY_C2_FAN_COUNT_OFFSET; + channel2.anyFanCount = UNIHUB_AL10_ANY_FAN_COUNT_001; + channel2.ledActionAddress = UNIHUB_AL10_LED_C2_ACTION_ADDRESS; + channel2.ledCommitAddress = UNIHUB_AL10_LED_C2_COMMIT_ADDRESS; + channel2.ledModeAddress = UNIHUB_AL10_LED_C2_MODE_ADDRESS; + channel2.ledSpeedAddress = UNIHUB_AL10_LED_C2_SPEED_ADDRESS; + channel2.ledDirectionAddress = UNIHUB_AL10_LED_C2_DIRECTION_ADDRESS; + channel2.ledBrightnessAddress = UNIHUB_AL10_LED_C2_BRIGHTNESS_ADDRESS; + channel2.ledMode = UNIHUB_AL10_LED_MODE_RAINBOW; + channel2.ledSpeed = UNIHUB_AL10_LED_SPEED_100; + channel2.ledDirection = UNIHUB_AL10_LED_DIRECTION_LTR; + channel2.ledBrightness = UNIHUB_AL10_LED_BRIGHTNESS_100; + channel2.fanHubActionAddress = UNIHUB_AL10_FAN_C2_HUB_ACTION_ADDRESS; + channel2.fanHubCommitAddress = UNIHUB_AL10_FAN_C2_HUB_COMMIT_ADDRESS; + channel2.fanPwmActionAddress = UNIHUB_AL10_FAN_C2_PWM_ACTION_ADDRESS; + channel2.fanPwmCommitAddress = UNIHUB_AL10_FAN_C2_PWM_COMMIT_ADDRESS; + channel2.fanRpmActionAddress = UNIHUB_AL10_FAN_C2_RPM_ACTION_ADDRESS; + channel2.fanSpeed = UNIHUB_AL10_FAN_SPEED_QUIET; + channels[1] = channel2; + + Channel channel3; + channel3.index = 2; + channel3.anyFanCountOffset = UNIHUB_AL10_ANY_C3_FAN_COUNT_OFFSET; + channel3.anyFanCount = UNIHUB_AL10_ANY_FAN_COUNT_001; + channel3.ledActionAddress = UNIHUB_AL10_LED_C3_ACTION_ADDRESS; + channel3.ledCommitAddress = UNIHUB_AL10_LED_C3_COMMIT_ADDRESS; + channel3.ledModeAddress = UNIHUB_AL10_LED_C3_MODE_ADDRESS; + channel3.ledSpeedAddress = UNIHUB_AL10_LED_C3_SPEED_ADDRESS; + channel3.ledDirectionAddress = UNIHUB_AL10_LED_C3_DIRECTION_ADDRESS; + channel3.ledBrightnessAddress = UNIHUB_AL10_LED_C3_BRIGHTNESS_ADDRESS; + channel3.ledMode = UNIHUB_AL10_LED_MODE_RAINBOW; + channel3.ledSpeed = UNIHUB_AL10_LED_SPEED_100; + channel3.ledDirection = UNIHUB_AL10_LED_DIRECTION_LTR; + channel3.ledBrightness = UNIHUB_AL10_LED_BRIGHTNESS_100; + channel3.fanHubActionAddress = UNIHUB_AL10_FAN_C3_HUB_ACTION_ADDRESS; + channel3.fanHubCommitAddress = UNIHUB_AL10_FAN_C3_HUB_COMMIT_ADDRESS; + channel3.fanPwmActionAddress = UNIHUB_AL10_FAN_C3_PWM_ACTION_ADDRESS; + channel3.fanPwmCommitAddress = UNIHUB_AL10_FAN_C3_PWM_COMMIT_ADDRESS; + channel3.fanRpmActionAddress = UNIHUB_AL10_FAN_C3_RPM_ACTION_ADDRESS; + channel3.fanSpeed = UNIHUB_AL10_FAN_SPEED_QUIET; + channels[2] = channel3; + + Channel channel4; + channel4.index = 3; + channel4.anyFanCountOffset = UNIHUB_AL10_ANY_C4_FAN_COUNT_OFFSET; + channel4.anyFanCount = UNIHUB_AL10_ANY_FAN_COUNT_001; + channel4.ledActionAddress = UNIHUB_AL10_LED_C4_ACTION_ADDRESS; + channel4.ledCommitAddress = UNIHUB_AL10_LED_C4_COMMIT_ADDRESS; + channel4.ledModeAddress = UNIHUB_AL10_LED_C4_MODE_ADDRESS; + channel4.ledSpeedAddress = UNIHUB_AL10_LED_C4_SPEED_ADDRESS; + channel4.ledDirectionAddress = UNIHUB_AL10_LED_C4_DIRECTION_ADDRESS; + channel4.ledBrightnessAddress = UNIHUB_AL10_LED_C4_BRIGHTNESS_ADDRESS; + channel4.ledMode = UNIHUB_AL10_LED_MODE_RAINBOW; + channel4.ledSpeed = UNIHUB_AL10_LED_SPEED_100; + channel4.ledDirection = UNIHUB_AL10_LED_DIRECTION_LTR; + channel4.ledBrightness = UNIHUB_AL10_LED_BRIGHTNESS_100; + channel4.fanHubActionAddress = UNIHUB_AL10_FAN_C4_HUB_ACTION_ADDRESS; + channel4.fanHubCommitAddress = UNIHUB_AL10_FAN_C4_HUB_COMMIT_ADDRESS; + channel4.fanPwmActionAddress = UNIHUB_AL10_FAN_C4_PWM_ACTION_ADDRESS; + channel4.fanPwmCommitAddress = UNIHUB_AL10_FAN_C4_PWM_COMMIT_ADDRESS; + channel4.fanRpmActionAddress = UNIHUB_AL10_FAN_C4_RPM_ACTION_ADDRESS; + channel4.fanSpeed = UNIHUB_AL10_FAN_SPEED_QUIET; + channels[3] = channel4; +} + +LianLiUniHub_AL10Controller::~LianLiUniHub_AL10Controller() +{ + CloseLibusb(); +} + +std::string LianLiUniHub_AL10Controller::GetVersion() +{ + return version; +} + +std::string LianLiUniHub_AL10Controller::GetLocation() +{ + return location; +} + +std::string LianLiUniHub_AL10Controller::GetSerial() +{ + return serial; +} + +void LianLiUniHub_AL10Controller::SetAnyFanCount(size_t channel, uint8_t count) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + channels[channel].anyFanCount = count; +} + +void LianLiUniHub_AL10Controller::SetLedColors(size_t channel, RGBColor* colors, size_t count) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + /*-------------------------------------*\ + | Check for invalid count | + \*-------------------------------------*/ + if(count > UNIHUB_AL10_CHANLED_COUNT) + { + count = UNIHUB_AL10_CHANLED_COUNT; + } + + /*-------------------------------------*\ + | Check for mode colors | + \*-------------------------------------*/ + size_t i = 0; + switch(channels[channel].ledMode) + { + case UNIHUB_AL10_LED_MODE_RAINBOW: + channels[channel].colors[0].r = 0xFC; + channels[channel].colors[0].b = 0xFC; + channels[channel].colors[0].g = 0xFC; + i = 1; + break; + case UNIHUB_AL10_LED_MODE_BREATHING: + for(unsigned int color_idx = 0; color_idx < count; color_idx++) + { + for(unsigned int led_idx = 0; led_idx < 20; led_idx++) + { + channels[channel].colors[led_idx + (color_idx * 20)].r = RGBGetRValue(colors[color_idx]); + channels[channel].colors[led_idx + (color_idx * 20)].b = RGBGetBValue(colors[color_idx]); + channels[channel].colors[led_idx + (color_idx * 20)].g = RGBGetGValue(colors[color_idx]); + i++; + } + } + break; + case UNIHUB_AL10_LED_MODE_SCAN: + for(; i < 20; i++) + { + channels[channel].colors[i].r = 0x00; + channels[channel].colors[i].b = 0x00; + channels[channel].colors[i].g = 0x00; + } + + channels[channel].colors[0x00].r = RGBGetRValue(colors[0]); + channels[channel].colors[0x00].b = RGBGetBValue(colors[0]); + channels[channel].colors[0x00].g = RGBGetGValue(colors[0]); + + channels[channel].colors[0x08].r = RGBGetRValue(colors[1]); + channels[channel].colors[0x08].b = RGBGetBValue(colors[1]); + channels[channel].colors[0x08].g = RGBGetGValue(colors[1]); + + break; + default: + for(; i < count; i++) + { + channels[channel].colors[i].r = (RGBGetRValue(colors[i])); + channels[channel].colors[i].b = (RGBGetBValue(colors[i])); + channels[channel].colors[i].g = (RGBGetGValue(colors[i])); + + // Limiter to protect LEDs + if(UNIHUB_AL10_LED_LIMITER && (channels[channel].colors[i].r > 153) && (channels[channel].colors[i].r == channels[channel].colors[i].b) && (channels[channel].colors[i].r == channels[channel].colors[i].g)) + { + channels[channel].colors[i].r = 153; + channels[channel].colors[i].b = 153; + channels[channel].colors[i].g = 153; + } + } + } + /* Set all remaining leds to black */ + for(; i < UNIHUB_AL10_CHANLED_COUNT; i++) + { + channels[channel].colors[i].r = 0x00; + channels[channel].colors[i].b = 0x00; + channels[channel].colors[i].g = 0x00; + } + + + +} + +void LianLiUniHub_AL10Controller::SetLedMode(size_t channel, uint8_t mode) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + channels[channel].ledMode = mode; +} + +void LianLiUniHub_AL10Controller::SetLedSpeed(size_t channel, uint8_t speed) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + channels[channel].ledSpeed = speed; +} + +void LianLiUniHub_AL10Controller::SetLedDirection(size_t channel, uint8_t direction) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + channels[channel].ledDirection = direction; +} + +void LianLiUniHub_AL10Controller::SetLedBrightness(size_t channel, uint8_t brightness) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + channels[channel].ledBrightness = brightness; +} + +uint16_t LianLiUniHub_AL10Controller::GetFanSpeed(size_t channel) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return 0; + } + + return channels[channel].fanSpeed; +} + +void LianLiUniHub_AL10Controller::SetFanSpeed(size_t channel, uint16_t speed) +{ + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel >= UNIHUB_AL10_CHANNEL_COUNT) + { + return; + } + + channels[channel].fanSpeed = speed; +} + +void LianLiUniHub_AL10Controller::EnableRgbhMode() +{ + rgbhModeEnabled = true; +} + +void LianLiUniHub_AL10Controller::DisableRgbhMode() +{ + rgbhModeEnabled = false; +} + +void LianLiUniHub_AL10Controller::EnableSyncMode() +{ + syncModeEnabled = true; +} + +void LianLiUniHub_AL10Controller::DisableSyncMode() +{ + syncModeEnabled = false; +} + +/*----------------------------------------------------------------------------*\ +| The Uni Hub is a PWM and LED controller designed specifically for the Lian | +| Li Uni Fans. It can control them by itself using the built-in effect engine | +| can also be connected to the mainboard via 4-pin PWM and 3-pin RGB cables | +| and forward these signals. The protocol implementation below was build as | +| close a possible to the Lian Li L-Connect software. | +| | +| The commands to control the fan speeds and to switch between controller and | +| mainboard control is already included, but currently deactivated as OpenRGB | +| had no fan control module or controller specific configuration at the time | +| of writing. | +\*----------------------------------------------------------------------------*/ +void LianLiUniHub_AL10Controller::Synchronize() +{ + /*---------------------------------------------------------------------*\ + | Configure common settings. | + \*---------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------*\ + | Still unsure about this. Probably some sort of configuration | + | initialization | + \*---------------------------------------------------------------------*/ + uint8_t config_initialization[16]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(config_initialization, 0x00, sizeof(config_initialization)); + + config_initialization[0x0F] = 0x43; // Control data + config_initialization[0x0F] = 0x01; // Ending data + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS, config_initialization, sizeof(config_initialization)); + + for(const Channel& channel : channels) + { + /*-------------------------------------*\ + | The Uni Hub doesn't know zero fans | + \*-------------------------------------*/ + uint8_t anyFanCount = channel.anyFanCount; + + if(anyFanCount == UNIHUB_AL10_ANY_FAN_COUNT_000) + { + anyFanCount = UNIHUB_AL10_ANY_FAN_COUNT_001; + } + + /*-------------------------------------*\ + | Configure the physical fan count | + \*-------------------------------------*/ + uint8_t config_fan_count[16]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(config_fan_count, 0x00, sizeof(config_fan_count)); + + config_fan_count[0x01] = 0x40; // Control data + config_fan_count[0x02] = channel.index + 1; // Channel + config_fan_count[0x03] = anyFanCount + 1; // Number of fans + config_fan_count[0x0F] = 0x01; // Ending data + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS, config_fan_count, sizeof(config_fan_count)); + //SendCommit(UNIHUB_AL10_COMMIT_ADDRESS); + } + + /*--------------------------------------------------------------------*\ + | Configure channels for sync effects | + \*--------------------------------------------------------------------*/ + + /* + if(syncModeEnabled) + { + uint8_t config_sync[6]; + uint8_t config_sync_index = 0; + + config_sync[config_sync_index++] = 0x33; + + for(const Channel& channel : channels) + { + if(channel.anyFanCount != UNIHUB_AL10_ANY_FAN_COUNT_000) + { + config_sync[config_sync_index++] = channel.index; + } + } + + config_sync[config_sync_index++] = 0x08; + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS, config_sync, config_sync_index); + SendCommit(UNIHUB_AL10_COMMIT_ADDRESS); + } + + */ + + /*--------------------------------------------------------------------*\ + | Configure led settings. | + \*--------------------------------------------------------------------*/ + for(const Channel& channel : channels) + { + if(channel.anyFanCount != UNIHUB_AL10_ANY_FAN_COUNT_000) + { + for(unsigned int fan_idx = 0; fan_idx <= UNIHUB_AL10_ANY_FAN_COUNT_004; fan_idx++) + { + /*-----------------------------*\ + | Configure fan colors | + \*-----------------------------*/ + uint8_t fan_config_colors[24]; + memcpy(fan_config_colors, channel.colors + (fan_idx * 20), sizeof(fan_config_colors)); + + SendConfig(channel.ledActionAddress + (60 * fan_idx), fan_config_colors, sizeof(fan_config_colors)); + } + + /*-----------------------------*\ + | Configure led mode | + \*-----------------------------*/ + uint8_t led_config[16]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(led_config, 0x00, sizeof(led_config)); + + led_config[0x01] = channel.ledMode; // Effect + led_config[0x02] = channel.ledSpeed; // Speed + led_config[0x03] = channel.ledDirection; // Direction + led_config[0x09] = channel.ledBrightness; // Brightness? + led_config[0x0F] = 0x01; // Ending data + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS + (channel.index * 32 ), led_config, sizeof(led_config)); + + for(unsigned int fan_idx = 0; fan_idx <= UNIHUB_AL10_ANY_FAN_COUNT_004; fan_idx++) + { + /*-----------------------------*\ + | Configure rim colors | + \*-----------------------------*/ + uint8_t rim_config_colors[36]; + memcpy(rim_config_colors, channel.colors + (fan_idx * 20) + 8, sizeof(rim_config_colors)); + + SendConfig(channel.ledActionAddress + 24 + (60 * fan_idx), rim_config_colors, sizeof(rim_config_colors)); + } + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS + 16 + (channel.index * 32 ), led_config, sizeof(led_config)); + } + /*-----------------------------------------------------------------*\ + | The Uni Hub doesn't know zero fans so we set them to black | + \*-----------------------------------------------------------------*/ + else + { + for(unsigned int fan_idx = 0; fan_idx <= UNIHUB_AL10_ANY_FAN_COUNT_004; fan_idx++) + { + /*-----------------------------*\ + | Configure fan colors | + \*-----------------------------*/ + uint8_t fan_config_colors[24]; + memset(fan_config_colors, 0x00, sizeof(fan_config_colors)); + + SendConfig(channel.ledActionAddress + (60 * fan_idx), fan_config_colors, sizeof(fan_config_colors)); + } + + /*-----------------------------*\ + | Configure led mode | + \*-----------------------------*/ + uint8_t led_config[16]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(led_config, 0x00, sizeof(led_config)); + + led_config[0x01] = UNIHUB_AL10_LED_MODE_STATIC_COLOR; // Effect + led_config[0x02] = channel.ledSpeed; // Speed? + led_config[0x03] = channel.ledDirection; // direction + led_config[0x0F] = 0x01; // Ending data + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS + (channel.index * 32 ), led_config, sizeof(led_config)); + + for(unsigned int fan_idx = 0; fan_idx <= UNIHUB_AL10_ANY_FAN_COUNT_004; fan_idx++) + { + /*-----------------------------*\ + | Configure rim colors | + \*-----------------------------*/ + uint8_t rim_config_colors[36]; + memset(rim_config_colors, 0x00, sizeof(rim_config_colors)); + + SendConfig(channel.ledActionAddress + 24 + (60 * fan_idx), rim_config_colors, sizeof(rim_config_colors)); + } + + SendConfig(UNIHUB_AL10_ACTION_ADDRESS + 16 + (channel.index * 32 ), led_config, sizeof(led_config)); + } + } + + /*--------------------------------------------------------------------*\ + | Configure fan settings. Comment out until enabling fan control | + \*--------------------------------------------------------------------*/ +// uint8_t control = 0; + +// /*-------------------------------------*\ +// | Configure fan settings | +// \*-------------------------------------*/ +// for(const Channel& channel : channels) +// { +// if(channel.fanSpeed == UNIHUB_AL10_FAN_SPEED_PWM) +// { +// /*-----------------------------*\ +// | Configure the fan to pwm | +// | control | +// \*-----------------------------*/ +// uint8_t config_pwm[1] = { 0x00 }; + +// control |= (0x01 << channel.index); + +// SendConfig(channel.fanPwmActionAddress, config_pwm, sizeof(config_pwm)); +// SendCommit(channel.fanPwmCommitAddress); +// } +// else +// { +// /*-----------------------------*\ +// | Configure the fan to hub | +// | control and set speed | +// \*-----------------------------*/ +// uint8_t config_hub[2] = { (uint8_t)(channel.fanSpeed >> 0x08), (uint8_t)(channel.fanSpeed & 0xFF) }; + +// SendConfig(channel.fanHubActionAddress, config_hub, sizeof(config_hub)); +// SendCommit(channel.fanHubCommitAddress); +// } +// } + +// /*-------------------------------------*\ +// | Configure fan control modes | +// \*-------------------------------------*/ +// uint8_t config_fan_mode[2] = { 0x31, (uint8_t)(0xF0 | control) }; + +// SendConfig(UNIHUB_AL10_ACTION_ADDRESS, config_fan_mode, sizeof(config_fan_mode)); +// SendCommit(UNIHUB_AL10_COMMIT_ADDRESS); + + /*--------------------------------------------------------------------*\ + | Configure led settings. | + \*--------------------------------------------------------------------*/ +// if(rgbhModeEnabled) +// { + /*-------------------------------------*\ + | Configure the leds to hdr control. | + \*-------------------------------------*/ +// uint8_t config_hdr[2] = { 0x30, 0x01 }; + +// SendConfig(UNIHUB_AL10_ACTION_ADDRESS, config_hdr, sizeof(config_hdr)); +// SendCommit(UNIHUB_AL10_COMMIT_ADDRESS); +// } +// else +// { + /*-------------------------------------*\ + | Configure the leds to hub control | + \*-------------------------------------*/ +// uint8_t config_hub[2] = { 0x30, 0x00 }; + +// SendConfig(UNIHUB_AL10_ACTION_ADDRESS, config_hub, sizeof(config_hub)); +// SendCommit(UNIHUB_AL10_COMMIT_ADDRESS); +// } +} + +uint16_t LianLiUniHub_AL10Controller::ReadFanSpeed(size_t channel) +{ + /*-------------------------------------*\ + | Check for invalid handle | + \*-------------------------------------*/ + if(handle == nullptr) + { + return(0); + } + + /*-------------------------------------*\ + | Check for invalid channel | + \*-------------------------------------*/ + if(channel > UNIHUB_AL10_CHANNEL_COUNT) + { + return(0); + } + + uint8_t buffer[2]; + uint8_t length = sizeof(buffer); + + uint16_t wIndex = channels[channel].fanRpmActionAddress; + + /*-------------------------------------*\ + | Send packet | + \*-------------------------------------*/ + size_t ret = libusb_control_transfer(handle, /* dev_handle */ + 0xC0, /* bmRequestType */ + 0x81, /* bRequest */ + 0x00, /* wValue */ + wIndex, /* wIndex */ + buffer, /* data */ + length, /* wLength */ + 1000); /* timeout */ + + /*-------------------------------------*\ + | Check for communication error | + \*-------------------------------------*/ + if(ret != length) + { + return(0); + } + + return(*(uint16_t*)buffer); +} + +void LianLiUniHub_AL10Controller::CloseLibusb() +{ + if (handle != nullptr) + { + libusb_close(handle); + handle = nullptr; + } +} + +std::string LianLiUniHub_AL10Controller::ReadVersion() +{ + /*-------------------------------------*\ + | Check for invalid handle | + \*-------------------------------------*/ + if(handle == nullptr) + { + return(""); + } + + uint8_t buffer[5]; + uint8_t length = sizeof(buffer); + + /*-------------------------------------*\ + | Send packet | + \*-------------------------------------*/ + size_t ret = libusb_control_transfer(handle, /* dev_handle */ + 0xC0, /* bmRequestType */ + 0x81, /* bRequest */ + 0x00, /* wValue */ + 0xB500, /* wIndex */ + buffer, /* data */ + length, /* wLength */ + 1000); /* timeout */ + + /*-------------------------------------*\ + | Check for communication error | + \*-------------------------------------*/ + if(ret != length) + { + return(""); + } + + /*-------------------------------------*\ + | Format version string | + \*-------------------------------------*/ + char version[14]; + int vlength = std::snprintf(version, sizeof(version), "%x.%x.%x.%x.%x", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); + + return(std::string(version, vlength)); +} + +void LianLiUniHub_AL10Controller::SendConfig(uint16_t wIndex, uint8_t *config, size_t length) +{ + /*-------------------------------------*\ + | Check for invalid handle | + \*-------------------------------------*/ + if(handle == nullptr) + { + return; + } + + /*-------------------------------------*\ + | Send packet | + \*-------------------------------------*/ + size_t ret = libusb_control_transfer(handle, /* dev_handle */ + 0x40, /* bmRequestType */ + 0x80, /* bRequest */ + 0x00, /* wValue */ + wIndex, /* wIndex */ + config, /* data */ + length, /* wLength */ + 1000); /* timeout */ + std::this_thread::sleep_for(5ms); + /*-------------------------------------*\ + | Check for communication error | + \*-------------------------------------*/ + if(ret != length) + { + return; + } +} + +void LianLiUniHub_AL10Controller::SendCommit(uint16_t wIndex) +{ + /*-------------------------------------*\ + | Set up config packet | + \*-------------------------------------*/ + uint8_t config[1] = { 0x01 }; + + /*-------------------------------------*\ + | Send packet | + \*-------------------------------------*/ + SendConfig(wIndex, config, sizeof(config)); + + std::this_thread::sleep_for(5ms); +} diff --git a/Controllers/LianLiController/LianLiUniHub_AL10Controller.h b/Controllers/LianLiController/LianLiUniHub_AL10Controller.h new file mode 100644 index 00000000..0be07f2a --- /dev/null +++ b/Controllers/LianLiController/LianLiUniHub_AL10Controller.h @@ -0,0 +1,273 @@ +/*-----------------------------------------*\ +| LianLiUniHub_AL10Controller.h | +| | +| Definitions and types for Lian Li Uni | +| Hub USB RGB lighting controller | +| | +| Oliver P 05/05/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#pragma once + +#include +#include +#include + +#include "RGBController.h" + +#include + +/*----------------------------------------------------------------------------*\ +| Global definitions. | +\*----------------------------------------------------------------------------*/ + +enum +{ + UNIHUB_AL10_CHANNEL_COUNT = 0x04, /* Channel count */ + UNIHUB_AL10_CHANLED_COUNT = 0x50, /* Max-LED per channel count */ +}; + +enum +{ + UNIHUB_AL10_ACTION_ADDRESS = 0xE020, /* Global action address */ + UNIHUB_AL10_COMMIT_ADDRESS = 0xE02F, /* Global commit address */ +}; + +enum +{ + UNIHUB_AL10_ANY_C1_FAN_COUNT_OFFSET = 0x00, /* Channel 1 fan count offset */ + UNIHUB_AL10_ANY_C2_FAN_COUNT_OFFSET = 0x14, /* Channel 2 fan count offset */ + UNIHUB_AL10_ANY_C3_FAN_COUNT_OFFSET = 0x28, /* Channel 3 fan count offset */ + UNIHUB_AL10_ANY_C4_FAN_COUNT_OFFSET = 0x3C, /* Channel 4 fan count offset */ +}; + +enum +{ + UNIHUB_AL10_ANY_FAN_COUNT_000 = 0xFF, /* Fan count for 0 fans (dummy value) */ + UNIHUB_AL10_ANY_FAN_COUNT_001 = 0x00, /* Fan count for 1 fan */ + UNIHUB_AL10_ANY_FAN_COUNT_002 = 0x01, /* Fan count for 2 fans */ + UNIHUB_AL10_ANY_FAN_COUNT_003 = 0x02, /* Fan count for 3 fans */ + UNIHUB_AL10_ANY_FAN_COUNT_004 = 0x03, /* Fan count for 4 fans */ +}; + +enum +{ + UNIHUB_AL10_LED_LIMITER = 1, /* Limit the color white to 999999 as per manufacturer limits in v1.7 */ +}; + +/*----------------------------------------------------------------------------*\ +| Definitions related to led configuration. | +\*----------------------------------------------------------------------------*/ + +enum +{ + UNIHUB_AL10_LED_C1_ACTION_ADDRESS = 0xE500, /* Channel 1 led action address */ + UNIHUB_AL10_LED_C1_COMMIT_ADDRESS = 0xE02F, /* Channel 1 led commit address */ + UNIHUB_AL10_LED_C1_MODE_ADDRESS = 0xE021, /* Channel 1 led mode address */ + UNIHUB_AL10_LED_C1_SPEED_ADDRESS = 0xE022, /* Channel 1 led speed address */ + UNIHUB_AL10_LED_C1_DIRECTION_ADDRESS = 0xE023, /* Channel 1 led direction address */ + UNIHUB_AL10_LED_C1_BRIGHTNESS_ADDRESS = 0xE029, /* Channel 1 led brightness address */ + + UNIHUB_AL10_LED_C2_ACTION_ADDRESS = 0xE5F0, /* Channel 2 led action address */ + UNIHUB_AL10_LED_C2_COMMIT_ADDRESS = 0xE03F, /* Channel 2 led commit address */ + UNIHUB_AL10_LED_C2_MODE_ADDRESS = 0xE031, /* Channel 2 led mode address */ + UNIHUB_AL10_LED_C2_SPEED_ADDRESS = 0xE032, /* Channel 2 led speed address */ + UNIHUB_AL10_LED_C2_DIRECTION_ADDRESS = 0xE033, /* Channel 2 led direction address */ + UNIHUB_AL10_LED_C2_BRIGHTNESS_ADDRESS = 0xE039, /* Channel 2 led brightness address */ + + UNIHUB_AL10_LED_C3_ACTION_ADDRESS = 0xE6E0, /* Channel 3 led action address */ + UNIHUB_AL10_LED_C3_COMMIT_ADDRESS = 0xE04F, /* Channel 3 led commit address */ + UNIHUB_AL10_LED_C3_MODE_ADDRESS = 0xE041, /* Channel 3 led mode address */ + UNIHUB_AL10_LED_C3_SPEED_ADDRESS = 0xE042, /* Channel 3 led speed address */ + UNIHUB_AL10_LED_C3_DIRECTION_ADDRESS = 0xE043, /* Channel 3 led direction address */ + UNIHUB_AL10_LED_C3_BRIGHTNESS_ADDRESS = 0xE049, /* Channel 3 led brightness address */ + + UNIHUB_AL10_LED_C4_ACTION_ADDRESS = 0xE7D0, /* Channel 4 led action address */ + UNIHUB_AL10_LED_C4_COMMIT_ADDRESS = 0xE05F, /* Channel 4 led commit address */ + UNIHUB_AL10_LED_C4_MODE_ADDRESS = 0xE051, /* Channel 4 led mode address */ + UNIHUB_AL10_LED_C4_SPEED_ADDRESS = 0xE052, /* Channel 4 led speed address */ + UNIHUB_AL10_LED_C4_DIRECTION_ADDRESS = 0xE053, /* Channel 4 led direction address */ + UNIHUB_AL10_LED_C4_BRIGHTNESS_ADDRESS = 0xE059, /* Channel 4 led brightness address */ +}; + +enum +{ + UNIHUB_AL10_LED_MODE_RAINBOW = 0x05, /* Rainbow mode */ + UNIHUB_AL10_LED_MODE_RAINBOW_MORPH = 0xFF, /* Runway mode - Needs updated code */ + UNIHUB_AL10_LED_MODE_STATIC_COLOR = 0x01, /* Static Color mode */ + UNIHUB_AL10_LED_MODE_BREATHING = 0x02, /* Breathing mode */ + UNIHUB_AL10_LED_MODE_TAICHI = 0x2C, /* Neon mode */ + UNIHUB_AL10_LED_MODE_COLOR_CYCLE = 0x2B, /* Color Cycle mode */ + UNIHUB_AL10_LED_MODE_RUNWAY = 0xFF, /* Runway mode - Needs updated code */ + UNIHUB_AL10_LED_MODE_METEOR = 0xFF, /* Meteor mode - Needs updated code */ + UNIHUB_AL10_LED_MODE_WARNING = 0x2D, /* Warning mode */ + UNIHUB_AL10_LED_MODE_VOICE = 0x22, /* Voice mode */ + UNIHUB_AL10_LED_MODE_SPINNING_TEACUP = 0x36, /* Spinning Teacup mode */ + UNIHUB_AL10_LED_MODE_TORNADO = 0x34, /* Tornado mode */ + UNIHUB_AL10_LED_MODE_MIXING = 0x23, /* Mixing mode */ + UNIHUB_AL10_LED_MODE_STACK = 0xFF, /* Stack mode - Needs updated code */ + UNIHUB_AL10_LED_MODE_STAGGGERED = 0x35, /* Stagggered mode */ + UNIHUB_AL10_LED_MODE_TIDE = 0x25, /* Tide mode */ + UNIHUB_AL10_LED_MODE_SCAN = 0x26, /* Scan mode */ + UNIHUB_AL10_LED_MODE_CONTEST = 0x33, /* Contest mode */ +}; + +enum +{ + UNIHUB_AL10_LED_SPEED_000 = 0x02, /* Very slow speed */ + UNIHUB_AL10_LED_SPEED_025 = 0x01, /* Rather slow speed */ + UNIHUB_AL10_LED_SPEED_050 = 0x00, /* Medium speed */ + UNIHUB_AL10_LED_SPEED_075 = 0xFF, /* Rather fast speed */ + UNIHUB_AL10_LED_SPEED_100 = 0xFE, /* Very fast speed */ +}; + +enum +{ + UNIHUB_AL10_LED_DIRECTION_LTR = 0x00, /* Left-to-Right direction */ + UNIHUB_AL10_LED_DIRECTION_RTL = 0x01, /* Right-to-Left direction */ +}; + +enum +{ + UNIHUB_AL10_LED_BRIGHTNESS_000 = 0x08, /* Very dark (off) */ + UNIHUB_AL10_LED_BRIGHTNESS_025 = 0x03, /* Rather dark */ + UNIHUB_AL10_LED_BRIGHTNESS_050 = 0x02, /* Medium bright */ + UNIHUB_AL10_LED_BRIGHTNESS_075 = 0x01, /* Rather bright */ + UNIHUB_AL10_LED_BRIGHTNESS_100 = 0x00, /* Very bright */ +}; + +/*----------------------------------------------------------------------------*\ +| Definitions related to fan configuration. | +\*----------------------------------------------------------------------------*/ + +enum +{ + UNIHUB_AL10_FAN_C1_HUB_ACTION_ADDRESS = 0xE8A0, /* Channel 1 fan action address for hub control */ + UNIHUB_AL10_FAN_C1_HUB_COMMIT_ADDRESS = 0xE890, /* Channel 1 fan commit address for hub control */ + UNIHUB_AL10_FAN_C1_PWM_ACTION_ADDRESS = 0xE890, /* Channel 1 fan action address for pwm control */ + UNIHUB_AL10_FAN_C1_PWM_COMMIT_ADDRESS = 0xE818, /* Channel 1 fan commit address for pwm control */ + UNIHUB_AL10_FAN_C1_RPM_ACTION_ADDRESS = 0xE800, /* Channel 1 fan pwm read address */ + + UNIHUB_AL10_FAN_C2_HUB_ACTION_ADDRESS = 0xE8A2, /* Channel 2 fan action address for hub control */ + UNIHUB_AL10_FAN_C2_HUB_COMMIT_ADDRESS = 0xE891, /* Channel 2 fan commit address for hub control */ + UNIHUB_AL10_FAN_C2_PWM_ACTION_ADDRESS = 0xE891, /* Channel 2 fan action address for pwm control */ + UNIHUB_AL10_FAN_C2_PWM_COMMIT_ADDRESS = 0xE81A, /* Channel 2 fan commit address for pwm control */ + UNIHUB_AL10_FAN_C2_RPM_ACTION_ADDRESS = 0xE802, /* Channel 1 fan pwm read address */ + + UNIHUB_AL10_FAN_C3_HUB_ACTION_ADDRESS = 0xE8A4, /* Channel 3 fan action address for hub control */ + UNIHUB_AL10_FAN_C3_HUB_COMMIT_ADDRESS = 0xE892, /* Channel 3 fan commit address for hub control */ + UNIHUB_AL10_FAN_C3_PWM_ACTION_ADDRESS = 0xE892, /* Channel 3 fan action address for pwm control */ + UNIHUB_AL10_FAN_C3_PWM_COMMIT_ADDRESS = 0xE81C, /* Channel 3 fan commit address for pwm control */ + UNIHUB_AL10_FAN_C3_RPM_ACTION_ADDRESS = 0xE804, /* Channel 1 fan pwm read address */ + + UNIHUB_AL10_FAN_C4_HUB_ACTION_ADDRESS = 0xE8A6, /* Channel 4 fan action address for hub control */ + UNIHUB_AL10_FAN_C4_HUB_COMMIT_ADDRESS = 0xE893, /* Channel 4 fan commit address for hub control */ + UNIHUB_AL10_FAN_C4_PWM_ACTION_ADDRESS = 0xE893, /* Channel 4 fan action address for pwm control */ + UNIHUB_AL10_FAN_C4_PWM_COMMIT_ADDRESS = 0xE81E, /* Channel 4 fan commit address for pwm control */ + UNIHUB_AL10_FAN_C4_RPM_ACTION_ADDRESS = 0xE806, /* Channel 1 fan pwm read address */ +}; + +enum +{ + UNIHUB_AL10_FAN_SPEED_QUIET = 0x2003, /* Rather slow */ + UNIHUB_AL10_FAN_SPEED_HIGH_SPEED = 0x2206, /* Rather fast */ + UNIHUB_AL10_FAN_SPEED_FULL_SPEED = 0x6C07, /* BRRRRRRRRRR */ + UNIHUB_AL10_FAN_SPEED_PWM = 0xFFFF, /* PWM Control */ +}; + +/*----------------------------------------------------------------------------*\ +| Uni Hub controller. | +\*----------------------------------------------------------------------------*/ + +class LianLiUniHub_AL10Controller +{ +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_AL10_CHANLED_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; + }; + +public: + LianLiUniHub_AL10Controller + ( + libusb_device* device, + libusb_device_descriptor* descriptor + ); + ~LianLiUniHub_AL10Controller(); + + std::string GetVersion(); + std::string GetLocation(); + std::string GetSerial(); + + void SetAnyFanCount(size_t channel, uint8_t count); + void SetLedColors(size_t channel, RGBColor* colors, size_t count); + void SetLedMode(size_t channel, uint8_t mode); + void SetLedSpeed(size_t channel, uint8_t speed); + void SetLedDirection(size_t channel, uint8_t direction); + void SetLedBrightness(size_t channel, uint8_t brightness); + uint16_t GetFanSpeed(size_t channel); + void SetFanSpeed(size_t channel, uint16_t speed); + void EnableRgbhMode(); + void DisableRgbhMode(); + void EnableSyncMode(); + void DisableSyncMode(); + uint16_t ReadFanSpeed(size_t channel); + + /*-----------------------------------------------------*\ + | Synchronize the current configuration to the Uni Hub. | + \*-----------------------------------------------------*/ + void Synchronize(); + +private: + libusb_device_handle* handle = nullptr; + + std::string version; + std::string location; + std::string serial; + + bool rgbhModeEnabled = false; + bool syncModeEnabled = false; + + Channel channels[UNIHUB_AL10_CHANNEL_COUNT]; + + void CloseLibusb(); + std::string ReadVersion(); + void SendConfig(uint16_t wIndex, uint8_t *config, size_t length); + void SendCommit(uint16_t wIndex); +}; diff --git a/Controllers/LianLiController/RGBController_LianLiUniHubAL.cpp b/Controllers/LianLiController/RGBController_LianLiUniHubAL.cpp new file mode 100644 index 00000000..d7aada1a --- /dev/null +++ b/Controllers/LianLiController/RGBController_LianLiUniHubAL.cpp @@ -0,0 +1,533 @@ +/*-----------------------------------------*\ +| RGBController_LianLiUniHubAL.cpp | +| | +| Generic RGB Interface for Lian Li Uni | +| Hub AL USB controller driver | +| | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#include "RGBController_LianLiUniHubAL.h" + +#include + +//0xFFFFFFFF indicates an unused entry in matrix +#define NA 0xFFFFFFFF + +static unsigned int matrix_map[8][35] = + { { NA, NA, 10, NA, NA, 11, NA, NA, NA, NA, NA, 30, NA, NA, 31, NA, NA, NA, NA, NA, 50, NA, NA, 51, NA, NA, NA, NA, NA, 70, NA, NA, 71, NA, NA}, + { NA, 9, NA, NA, NA, NA, 12, NA, NA, NA, 29, NA, NA, NA, NA, 32, NA, NA, NA, 49, NA, NA, NA, NA, 52, NA, NA, NA, 69, NA, NA, NA, NA, 72, NA}, + { 8, NA, NA, 1, 2, NA, NA, 13, NA, 28, NA, NA, 21, 22, NA, NA, 33, NA, 48, NA, NA, 41, 42, NA, NA, 53, NA, 68, NA, NA, 61, 62, NA, NA, 73}, + { NA, NA, 0, NA, NA, 3, NA, NA, NA, NA, NA, 20, NA, NA, 23, NA, NA, NA, NA, NA, 40, NA, NA, 43, NA, NA, NA, NA, NA, 60, NA, NA, 63, NA, NA}, + { NA, NA, 7, NA, NA, 4, NA, NA, NA, NA, NA, 27, NA, NA, 24, NA, NA, NA, NA, NA, 47, NA, NA, 44, NA, NA, NA, NA, NA, 67, NA, NA, 64, NA, NA}, + { 19, NA, NA, 6, 5, NA, NA, 14, NA, 39, NA, NA, 26, 25, NA, NA, 34, NA, 59, NA, NA, 46, 45, NA, NA, 54, NA, 79, NA, NA, 66, 65, NA, NA, 74}, + { NA, 18, NA, NA, NA, NA, 15, NA, NA, NA, 38, NA, NA, NA, NA, 35, NA, NA, NA, 58, NA, NA, NA, NA, 55, NA, NA, NA, 78, NA, NA, NA, NA, 75, NA}, + { NA, NA, 17, NA, NA, 16, NA, NA, NA, NA, NA, 37, NA, NA, 36, NA, NA, NA, NA, NA, 57, NA, NA, 56, NA, NA, NA, NA, NA, 77, NA, NA, 76, NA, NA} + }; + +/**------------------------------------------------------------------*\ + @name Lian Li Uni Hub AL + @type USB + @save :x: + @direct :warning: + @effects :white_check_mark: + @detectors DetectLianLiUniHubAL + @comment +\*-------------------------------------------------------------------*/ + +RGBController_LianLiUniHubAL::RGBController_LianLiUniHubAL(LianLiUniHubALController* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetName(); + vendor = "Lian Li"; + type = DEVICE_TYPE_COOLER; + description = "Lian Li Uni Hub - AL"; + version = controller->GetFirmwareVersionString(); + location = controller->GetDeviceLocation(); + serial = controller->GetSerialString(); + + + initializedMode = false; + + mode Custom; + Custom.name = "Custom"; + Custom.value = UNIHUB_AL_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 RainbowWave; + RainbowWave.name = "Rainbow Wave"; + RainbowWave.value = UNIHUB_AL_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 = 3; + RainbowWave.brightness = 3; + RainbowWave.direction = UNIHUB_AL_LED_DIRECTION_LTR; + RainbowWave.color_mode = MODE_COLORS_NONE; + modes.push_back(RainbowWave); + + mode RainbowMorph; + RainbowMorph.name = "Rainbow Morph"; + RainbowMorph.value = UNIHUB_AL_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 = 3; + RainbowMorph.brightness = 3; + RainbowMorph.color_mode = MODE_COLORS_NONE; + modes.push_back(RainbowMorph); + + mode StaticColor; + StaticColor.name = "Static Color"; + StaticColor.value = UNIHUB_AL_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 = 4; + StaticColor.brightness = 3; + StaticColor.color_mode = MODE_COLORS_MODE_SPECIFIC; + StaticColor.colors.resize(4); + modes.push_back(StaticColor); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = UNIHUB_AL_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 = 4; + Breathing.speed = 3; + Breathing.brightness = 3; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.colors.resize(4); + modes.push_back(Breathing); + + mode Taichi; + Taichi.name = "Taichi"; + Taichi.value = UNIHUB_AL_LED_MODE_TAICHI; + Taichi.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Taichi.speed_min = 0; + Taichi.speed_max = 4; + Taichi.brightness_min = 0; + Taichi.brightness_max = 4; + Taichi.colors_min = 0; + Taichi.colors_max = 2; + Taichi.speed = 3; + Taichi.brightness = 3; + Taichi.direction = UNIHUB_AL_LED_DIRECTION_LTR; + Taichi.color_mode = MODE_COLORS_MODE_SPECIFIC; + Taichi.colors.resize(2); + modes.push_back(Taichi); + + mode ColorCycle; + ColorCycle.name = "ColorCycle"; + ColorCycle.value = UNIHUB_AL_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 = 4; + ColorCycle.speed = 3; + ColorCycle.brightness = 3; + ColorCycle.direction = UNIHUB_AL_LED_DIRECTION_LTR; + ColorCycle.color_mode = MODE_COLORS_MODE_SPECIFIC; + ColorCycle.colors.resize(4); + modes.push_back(ColorCycle); + + mode Runway; + Runway.name = "Runway"; + Runway.value = UNIHUB_AL_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 = 3; + Runway.brightness = 3; + Runway.color_mode = MODE_COLORS_MODE_SPECIFIC; + Runway.colors.resize(2); + modes.push_back(Runway); + + mode Meteor; + Meteor.name = "Meteor"; + Meteor.value = UNIHUB_AL_LED_MODE_METEOR; + Meteor.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Meteor.speed_min = 0; + Meteor.speed_max = 4; + Meteor.brightness_min = 0; + Meteor.brightness_max = 4; + Meteor.colors_min = 0; + Meteor.colors_max = 4; + Meteor.speed = 3; + Meteor.brightness = 3; + Meteor.direction = UNIHUB_AL_LED_DIRECTION_LTR; + Meteor.color_mode = MODE_COLORS_MODE_SPECIFIC; + Meteor.colors.resize(4); + modes.push_back(Meteor); + + mode Warning; + Warning.name = "Warning"; + Warning.value = UNIHUB_AL_LED_MODE_WARNING; + Warning.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Warning.speed_min = 0; + Warning.speed_max = 4; + Warning.brightness_min = 0; + Warning.brightness_max = 4; + Warning.colors_min = 0; + Warning.colors_max = 4; + Warning.speed = 3; + Warning.brightness = 3; + Warning.color_mode = MODE_COLORS_MODE_SPECIFIC; + Warning.colors.resize(4); + modes.push_back(Warning); + + mode Voice; + Voice.name = "Voice"; + Voice.value = UNIHUB_AL_LED_MODE_VOICE; + Voice.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Voice.speed_min = 0; + Voice.speed_max = 4; + Voice.brightness_min = 0; + Voice.brightness_max = 4; + Voice.colors_min = 0; + Voice.colors_max = 4; + Voice.speed = 3; + Voice.brightness = 3; + Voice.direction = UNIHUB_AL_LED_DIRECTION_LTR; + Voice.color_mode = MODE_COLORS_MODE_SPECIFIC; + Voice.colors.resize(4); + modes.push_back(Voice); + + mode SpinningTeacup; + SpinningTeacup.name = "SpinningTeacup"; + SpinningTeacup.value = UNIHUB_AL_LED_MODE_SPINNING_TEACUP; + SpinningTeacup.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + SpinningTeacup.speed_min = 0; + SpinningTeacup.speed_max = 4; + SpinningTeacup.brightness_min = 0; + SpinningTeacup.brightness_max = 4; + SpinningTeacup.colors_min = 0; + SpinningTeacup.colors_max = 4; + SpinningTeacup.speed = 3; + SpinningTeacup.brightness = 3; + SpinningTeacup.direction = UNIHUB_AL_LED_DIRECTION_LTR; + SpinningTeacup.color_mode = MODE_COLORS_MODE_SPECIFIC; + SpinningTeacup.colors.resize(4); + modes.push_back(SpinningTeacup); + + mode Tornado; + Tornado.name = "Tornado"; + Tornado.value = UNIHUB_AL_LED_MODE_TORNADO; + Tornado.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Tornado.speed_min = 0; + Tornado.speed_max = 4; + Tornado.brightness_min = 0; + Tornado.brightness_max = 4; + Tornado.colors_min = 0; + Tornado.colors_max = 4; + Tornado.speed = 3; + Tornado.brightness = 3; + Tornado.direction = UNIHUB_AL_LED_DIRECTION_LTR; + Tornado.color_mode = MODE_COLORS_MODE_SPECIFIC; + Tornado.colors.resize(4); + modes.push_back(Tornado); + + mode Mixing; + Mixing.name = "Mixing"; + Mixing.value = UNIHUB_AL_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 = 3; + Mixing.brightness = 3; + Mixing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Mixing.colors.resize(2); + modes.push_back(Mixing); + + mode Stack; + Stack.name = "Stack"; + Stack.value = UNIHUB_AL_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 = 2; + Stack.speed = 3; + Stack.brightness = 3; + Stack.direction = UNIHUB_AL_LED_DIRECTION_LTR; + Stack.color_mode = MODE_COLORS_MODE_SPECIFIC; + Stack.colors.resize(2); + modes.push_back(Stack); + + mode Staggered; + Staggered.name = "Staggered"; + Staggered.value = UNIHUB_AL_LED_MODE_STAGGGERED; + 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 = 4; + Staggered.speed = 3; + Staggered.brightness = 3; + Staggered.color_mode = MODE_COLORS_MODE_SPECIFIC; + Staggered.colors.resize(4); + modes.push_back(Staggered); + + mode Tide; + Tide.name = "Tide"; + Tide.value = UNIHUB_AL_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 = 4; + Tide.speed = 3; + Tide.brightness = 3; + Tide.color_mode = MODE_COLORS_MODE_SPECIFIC; + Tide.colors.resize(4); + modes.push_back(Tide); + + mode Scan; + Scan.name = "Scan"; + Scan.value = UNIHUB_AL_LED_MODE_SCAN; + Scan.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Scan.speed_min = 0; + Scan.speed_max = 4; + Scan.brightness_min = 0; + Scan.brightness_max = 4; + Scan.colors_min = 0; + Scan.colors_max = 2; + Scan.speed = 3; + Scan.brightness = 3; + Scan.color_mode = MODE_COLORS_MODE_SPECIFIC; + Scan.colors.resize(2); + modes.push_back(Scan); + + mode Contest; + Contest.name = "Contest"; + Contest.value = UNIHUB_AL_LED_MODE_CONTEST; + Contest.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Contest.speed_min = 0; + Contest.speed_max = 4; + Contest.brightness_min = 0; + Contest.brightness_max = 4; + Contest.colors_min = 0; + Contest.colors_max = 2; + Contest.speed = 3; + Contest.brightness = 3; + Contest.direction = UNIHUB_AL_LED_DIRECTION_LTR; + Contest.color_mode = MODE_COLORS_MODE_SPECIFIC; + Contest.colors.resize(3); + modes.push_back(Contest); + + RGBController_LianLiUniHubAL::SetupZones(); +} + +RGBController_LianLiUniHubAL::~RGBController_LianLiUniHubAL() +{ + /*---------------------------------------------------------*\ + | Delete the matrix map | + \*---------------------------------------------------------*/ + for(unsigned int zone_index = 0; zone_index < zones.size(); zone_index++) + { + if(zones[zone_index].matrix_map != NULL) + { + delete zones[zone_index].matrix_map; + } + } + + delete controller; +} + +void RGBController_LianLiUniHubAL::SetupZones() +{ + /*-------------------------------------------------*\ + | Only set LED count on the first run | + \*-------------------------------------------------*/ + bool first_run = false; + + if(zones.size() == 0) + { + first_run = true; + zones.resize(UNIHUB_AL_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)); + + // Note: Matrix types won't get loaded from the sizes.ors as the default zone type in this RGBController is ZONE_TYPE_LINEAR + // This will require augmentation on the ProfileManager.cpp to be able to override zone types but this is probably not wanted in general + if (zones[channel_idx].leds_count == 60 || zones[channel_idx].leds_count == 40 || zones[channel_idx].leds_count == 20 || zones[channel_idx].leds_count == 80) // Assume they're AL120 Fans + { + zones[channel_idx].type = ZONE_TYPE_MATRIX; + zones[channel_idx].leds_min = 0; + zones[channel_idx].leds_max = UNIHUB_AL_CHAN_LED_COUNT; + zones[channel_idx].matrix_map = new matrix_map_type; + zones[channel_idx].matrix_map->height = 8; + zones[channel_idx].matrix_map->width = 35; + zones[channel_idx].matrix_map->map = (unsigned int *)&matrix_map; + } + else // Treat as regular LED strip + { + zones[channel_idx].type = ZONE_TYPE_LINEAR; + zones[channel_idx].leds_min = 0; + zones[channel_idx].leds_max = UNIHUB_AL_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_LianLiUniHubAL::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_LianLiUniHubAL::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_LianLiUniHubAL::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_LianLiUniHubAL::UpdateSingleLED(int /* led */) +{ + DeviceUpdateMode(); + +} + +void RGBController_LianLiUniHubAL::DeviceUpdateMode() +{ + if(!active_mode) + { + return; // Do nothing, custom mode should go through DeviceUpdateLEDs() to avoid flooding controller + } + + initializedMode = true; + + int fan_idx = 0; + bool upd_both_fan_edge = false; + + /*-----------------------------------------------------*\ + | Check modes that requires updating both arrays | + \*-----------------------------------------------------*/ + + switch(modes[active_mode].value) + { + case UNIHUB_AL_LED_MODE_STATIC_COLOR: + case UNIHUB_AL_LED_MODE_BREATHING: + case UNIHUB_AL_LED_MODE_RUNWAY: + case UNIHUB_AL_LED_MODE_METEOR: + upd_both_fan_edge = true; + break; + } + + 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 / 20) - 1); // Indexes start at 0 + + controller->SetChannelMode(zone_idx, modes[active_mode].value,modes[active_mode].colors, modes[active_mode].colors.size(), (fan_idx >= 0 ? fan_idx : 0), upd_both_fan_edge, modes[active_mode].brightness, modes[active_mode].speed, modes[active_mode].direction); + + } +} + +void RGBController_LianLiUniHubAL::SetCustomMode() +{ + /*-------------------------------------------------*\ + | Set mode to Static Color | + \*-------------------------------------------------*/ + active_mode = 0; +} + diff --git a/Controllers/LianLiController/RGBController_LianLiUniHubAL.h b/Controllers/LianLiController/RGBController_LianLiUniHubAL.h new file mode 100644 index 00000000..4520e4a4 --- /dev/null +++ b/Controllers/LianLiController/RGBController_LianLiUniHubAL.h @@ -0,0 +1,40 @@ +/*-----------------------------------------*\ +| RGBController_LianLiUniHubAL.h | +| | +| Generic RGB Interface for Lian Li Uni | +| Hub AL USB controller driver | +| | +| Oliver P 04/26/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#pragma once + +#include +#include + +#include "LianLiUniHubALController.h" +#include "RGBController.h" + +class RGBController_LianLiUniHubAL : public RGBController +{ +public: + RGBController_LianLiUniHubAL(LianLiUniHubALController* controller_ptr); + ~RGBController_LianLiUniHubAL(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + + void SetCustomMode(); + +private: + LianLiUniHubALController* controller; + bool initializedMode; +}; diff --git a/Controllers/LianLiController/RGBController_LianLiUniHub_AL10.cpp b/Controllers/LianLiController/RGBController_LianLiUniHub_AL10.cpp new file mode 100644 index 00000000..da2f4697 --- /dev/null +++ b/Controllers/LianLiController/RGBController_LianLiUniHub_AL10.cpp @@ -0,0 +1,668 @@ +/*-----------------------------------------*\ +| RGBController_LianLiUniHub_AL10.cpp | +| | +| Generic RGB Interface for Lian Li Uni | +| Hub USB controller driver | +| | +| Oliver P 05/05/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#include "RGBController_LianLiUniHub_AL10.h" + +#include + +/**------------------------------------------------------------------*\ + @name Lian Li Uni Hub + @type USB + @save :x: + @direct :warning: + @effects :white_check_mark: + @detectors DetectLianLiUniHub + @comment +\*-------------------------------------------------------------------*/ + +RGBController_LianLiUniHub_AL10::RGBController_LianLiUniHub_AL10(LianLiUniHub_AL10Controller* controller_ptr) +{ + controller = controller_ptr; + + name = "Lian Li Uni Hub - AL"; + vendor = "Lian Li"; + version = controller->GetVersion(); + type = DEVICE_TYPE_COOLER; + description = "Lian Li Uni Hub - AL v1.0"; + location = controller->GetLocation(); + serial = controller->GetSerial(); + + initializedMode = false; + + mode Custom; + Custom.name = "Custom"; + Custom.value = UNIHUB_AL10_LED_MODE_STATIC_COLOR; + Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Custom.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Custom); + + mode RainbowWave; + RainbowWave.name = "Rainbow Wave"; + RainbowWave.value = UNIHUB_AL10_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 = 3; + RainbowWave.brightness = 3; + RainbowWave.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + RainbowWave.color_mode = MODE_COLORS_NONE; + //RainbowWave.colors[0] = ToRGBColor(253,253,253); + modes.push_back(RainbowWave); + + /* Needs updated code + mode RainbowMorph; + RainbowMorph.name = "Rainbow Morph"; + RainbowMorph.value = UNIHUB_AL10_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 = 3; + RainbowMorph.brightness = 3; + RainbowMorph.color_mode = MODE_COLORS_NONE; + modes.push_back(RainbowMorph); + */ + + mode StaticColor; + StaticColor.name = "Static Color"; + StaticColor.value = UNIHUB_AL10_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 = 4; + StaticColor.brightness = 3; + StaticColor.color_mode = MODE_COLORS_MODE_SPECIFIC; + StaticColor.colors.resize(4); + modes.push_back(StaticColor); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = UNIHUB_AL10_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 = 4; + Breathing.speed = 3; + Breathing.brightness = 3; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.colors.resize(4); + modes.push_back(Breathing); + + mode Taichi; + Taichi.name = "Taichi"; + Taichi.value = UNIHUB_AL10_LED_MODE_TAICHI; + Taichi.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Taichi.speed_min = 0; + Taichi.speed_max = 4; + Taichi.brightness_min = 0; + Taichi.brightness_max = 4; + Taichi.colors_min = 0; + Taichi.colors_max = 2; + Taichi.speed = 3; + Taichi.brightness = 3; + Taichi.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + Taichi.color_mode = MODE_COLORS_MODE_SPECIFIC; + Taichi.colors.resize(2); + modes.push_back(Taichi); + + mode ColorCycle; + ColorCycle.name = "ColorCycle"; + ColorCycle.value = UNIHUB_AL10_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 = 4; + ColorCycle.speed = 3; + ColorCycle.brightness = 3; + ColorCycle.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + ColorCycle.color_mode = MODE_COLORS_MODE_SPECIFIC; + ColorCycle.colors.resize(4); + modes.push_back(ColorCycle); + + /* Needs updated code + mode Runway; + Runway.name = "Runway"; + Runway.value = UNIHUB_AL10_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 = 3; + Runway.brightness = 3; + Runway.color_mode = MODE_COLORS_MODE_SPECIFIC; + Runway.colors.resize(2); + modes.push_back(Runway); + */ + + /* Needs updated code + mode Meteor; + Meteor.name = "Meteor"; + Meteor.value = UNIHUB_AL10_LED_MODE_METEOR; + Meteor.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Meteor.speed_min = 0; + Meteor.speed_max = 4; + Meteor.brightness_min = 0; + Meteor.brightness_max = 4; + Meteor.colors_min = 0; + Meteor.colors_max = 4; + Meteor.speed = 3; + Meteor.brightness = 3; + Meteor.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + Meteor.color_mode = MODE_COLORS_MODE_SPECIFIC; + Meteor.colors.resize(4); + modes.push_back(Meteor); + */ + + mode Warning; + Warning.name = "Warning"; + Warning.value = UNIHUB_AL10_LED_MODE_WARNING; + Warning.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Warning.speed_min = 0; + Warning.speed_max = 4; + Warning.brightness_min = 0; + Warning.brightness_max = 4; + Warning.colors_min = 0; + Warning.colors_max = 4; + Warning.speed = 3; + Warning.brightness = 3; + Warning.color_mode = MODE_COLORS_MODE_SPECIFIC; + Warning.colors.resize(4); + modes.push_back(Warning); + + mode Voice; + Voice.name = "Voice"; + Voice.value = UNIHUB_AL10_LED_MODE_VOICE; + Voice.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Voice.speed_min = 0; + Voice.speed_max = 4; + Voice.brightness_min = 0; + Voice.brightness_max = 4; + Voice.colors_min = 0; + Voice.colors_max = 4; + Voice.speed = 3; + Voice.brightness = 3; + Voice.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + Voice.color_mode = MODE_COLORS_MODE_SPECIFIC; + Voice.colors.resize(4); + modes.push_back(Voice); + + mode SpinningTeacup; + SpinningTeacup.name = "SpinningTeacup"; + SpinningTeacup.value = UNIHUB_AL10_LED_MODE_SPINNING_TEACUP; + SpinningTeacup.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + SpinningTeacup.speed_min = 0; + SpinningTeacup.speed_max = 4; + SpinningTeacup.brightness_min = 0; + SpinningTeacup.brightness_max = 4; + SpinningTeacup.colors_min = 0; + SpinningTeacup.colors_max = 4; + SpinningTeacup.speed = 3; + SpinningTeacup.brightness = 3; + SpinningTeacup.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + SpinningTeacup.color_mode = MODE_COLORS_MODE_SPECIFIC; + SpinningTeacup.colors.resize(4); + modes.push_back(SpinningTeacup); + + mode Tornado; + Tornado.name = "Tornado"; + Tornado.value = UNIHUB_AL10_LED_MODE_TORNADO; + Tornado.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Tornado.speed_min = 0; + Tornado.speed_max = 4; + Tornado.brightness_min = 0; + Tornado.brightness_max = 4; + Tornado.colors_min = 0; + Tornado.colors_max = 4; + Tornado.speed = 3; + Tornado.brightness = 3; + Tornado.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + Tornado.color_mode = MODE_COLORS_MODE_SPECIFIC; + Tornado.colors.resize(4); + modes.push_back(Tornado); + + mode Mixing; + Mixing.name = "Mixing"; + Mixing.value = UNIHUB_AL10_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 = 3; + Mixing.brightness = 3; + Mixing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Mixing.colors.resize(2); + modes.push_back(Mixing); + + /* Needs updated code + mode Stack; + Stack.name = "Stack"; + Stack.value = UNIHUB_AL10_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 = 2; + Stack.speed = 3; + Stack.brightness = 3; + Stack.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + Stack.color_mode = MODE_COLORS_MODE_SPECIFIC; + Stack.colors.resize(2); + modes.push_back(Stack); + */ + + mode Staggered; + Staggered.name = "Staggered"; + Staggered.value = UNIHUB_AL10_LED_MODE_STAGGGERED; + 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 = 4; + Staggered.speed = 3; + Staggered.brightness = 3; + Staggered.color_mode = MODE_COLORS_MODE_SPECIFIC; + Staggered.colors.resize(4); + modes.push_back(Staggered); + + mode Tide; + Tide.name = "Tide"; + Tide.value = UNIHUB_AL10_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 = 4; + Tide.speed = 3; + Tide.brightness = 3; + Tide.color_mode = MODE_COLORS_MODE_SPECIFIC; + Tide.colors.resize(4); + modes.push_back(Tide); + + mode Scan; + Scan.name = "Scan"; + Scan.value = UNIHUB_AL10_LED_MODE_SCAN; + Scan.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Scan.speed_min = 0; + Scan.speed_max = 4; + Scan.brightness_min = 0; + Scan.brightness_max = 4; + Scan.colors_min = 0; + Scan.colors_max = 2; + Scan.speed = 3; + Scan.brightness = 3; + Scan.color_mode = MODE_COLORS_MODE_SPECIFIC; + Scan.colors.resize(2); + modes.push_back(Scan); + + mode Contest; + Contest.name = "Contest"; + Contest.value = UNIHUB_AL10_LED_MODE_CONTEST; + Contest.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR; + Contest.speed_min = 0; + Contest.speed_max = 4; + Contest.brightness_min = 0; + Contest.brightness_max = 4; + Contest.colors_min = 0; + Contest.colors_max = 2; + Contest.speed = 3; + Contest.brightness = 3; + Contest.direction = UNIHUB_AL10_LED_DIRECTION_LTR; + Contest.color_mode = MODE_COLORS_MODE_SPECIFIC; + Contest.colors.resize(3); + modes.push_back(Contest); + + /* Motherboard header mode? Not implemented yet + mode Rgbh = makeModeAL(); + Rgbh.name = "RGB Header"; + Rgbh.value = UNIHUB_AL10_LED_MODE_STATIC_COLOR | 0x0200; + Rgbh.flags = 0; + Rgbh.color_mode = MODE_COLORS_NONE; + modes.push_back(Rgbh); + */ + + RGBController_LianLiUniHub_AL10::SetupZones(); +} + +void RGBController_LianLiUniHub_AL10::SetupZones() +{ + /*-------------------------------------------------*\ + | Only set LED count on the first run | + \*-------------------------------------------------*/ + bool first_run = false; + + if(zones.size() == 0) + { + first_run = true; + } + + /*-------------------------------------------------*\ + | Clear any existing color/LED configuration | + \*-------------------------------------------------*/ + leds.clear(); + colors.clear(); + zones.resize(UNIHUB_AL10_CHANNEL_COUNT); + + /*-------------------------------------------------*\ + | Set zones and leds | + \*-------------------------------------------------*/ + int addressableCounter = 1; + 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(addressableCounter)); + + addressableCounter++; + + zones[channel_idx].type = ZONE_TYPE_LINEAR; + + zones[channel_idx].leds_min = 0; + zones[channel_idx].leds_max = UNIHUB_AL10_CHANLED_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); + } + + zones[channel_idx].matrix_map = NULL; + } + + SetupColors(); +} + +void RGBController_LianLiUniHub_AL10::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_LianLiUniHub_AL10::DeviceUpdateLEDs() +{ + if(!initializedMode) + { + DeviceUpdateMode(); + } + for(size_t channel = 0; channel < zones.size(); channel++) + { + uint8_t fanCount = convertLedCountToFanCount(zones[channel].leds_count); + controller->SetAnyFanCount(channel, convertAnyFanCount(fanCount)); + controller->SetLedColors(channel, zones[channel].colors, zones[channel].leds_count); + } + + controller->Synchronize(); +} + +void RGBController_LianLiUniHub_AL10::UpdateZoneLEDs(int zone) +{ + if(!initializedMode) + { + DeviceUpdateMode(); + } + unsigned int channel = zone; + + uint8_t fanCount = convertLedCountToFanCount(zones[channel].leds_count); + controller->SetAnyFanCount(channel, convertAnyFanCount(fanCount)); + controller->SetLedColors(channel, zones[channel].colors, zones[channel].leds_count); + + controller->Synchronize(); +} + +void RGBController_LianLiUniHub_AL10::UpdateSingleLED(int led) +{ + if(!initializedMode) + { + DeviceUpdateMode(); + } + unsigned int channel = leds[led].value; + + uint8_t fanCount = convertLedCountToFanCount(zones[channel].leds_count); + controller->SetAnyFanCount(channel, convertAnyFanCount(fanCount)); + controller->SetLedColors(channel, zones[channel].colors, zones[channel].leds_count); + + controller->Synchronize(); +} + +void RGBController_LianLiUniHub_AL10::DeviceUpdateMode() +{ + initializedMode = true; + + for (size_t channel = 0; channel < zones.size(); channel++) + { + uint8_t fanCount = convertLedCountToFanCount(zones[channel].leds_count); + controller->SetAnyFanCount(channel, convertAnyFanCount(fanCount)); + + switch (modes[active_mode].color_mode) + { + case MODE_COLORS_PER_LED: + controller->SetLedColors(channel, zones[channel].colors, zones[channel].leds_count); + break; + + case MODE_COLORS_MODE_SPECIFIC: + controller->SetLedColors(channel, modes[active_mode].colors.data(), modes[active_mode].colors.size()); + break; + + default: + controller->SetLedColors(channel, nullptr, 0); + break; + } + + controller->SetLedMode(channel, modes[active_mode].value); + + if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED) + { + controller->SetLedSpeed(channel, convertLedSpeed(modes[active_mode].speed)); + } + else + { + controller->SetLedSpeed(channel, UNIHUB_AL10_LED_SPEED_075); + } + + if(modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) + { + controller->SetLedDirection(channel, convertLedDirection(modes[active_mode].direction)); + } + else + { + controller->SetLedDirection(channel, UNIHUB_AL10_LED_DIRECTION_LTR); + } + + if(modes[active_mode].flags & MODE_FLAG_HAS_BRIGHTNESS) + { + controller->SetLedBrightness(channel, convertLedBrightness(modes[active_mode].brightness)); + } + else + { + controller->SetLedBrightness(channel, UNIHUB_AL10_LED_BRIGHTNESS_100); + } + } + + if(modes[active_mode].value & 0x0200) + { + controller->EnableRgbhMode(); + controller->DisableSyncMode(); + } + else if (modes[active_mode].value & 0x0100) + { + controller->DisableRgbhMode(); + controller->EnableSyncMode(); + } + else + { + controller->DisableRgbhMode(); + controller->DisableSyncMode(); + } + + controller->Synchronize(); +} + +void RGBController_LianLiUniHub_AL10::SetCustomMode() +{ + /*-------------------------------------------------*\ + | Set mode to Static Color | + \*-------------------------------------------------*/ + active_mode = 0; +} + +uint8_t RGBController_LianLiUniHub_AL10::convertAnyFanCount(uint8_t count) +{ + switch (count) + { + case 0: + return UNIHUB_AL10_ANY_FAN_COUNT_000; + + case 1: + return UNIHUB_AL10_ANY_FAN_COUNT_001; + + case 2: + return UNIHUB_AL10_ANY_FAN_COUNT_002; + + case 3: + return UNIHUB_AL10_ANY_FAN_COUNT_003; + + case 4: + return UNIHUB_AL10_ANY_FAN_COUNT_004; + + default: + return UNIHUB_AL10_ANY_FAN_COUNT_001; + } +} + +uint8_t RGBController_LianLiUniHub_AL10::convertLedSpeed(uint8_t speed) +{ + switch (speed) + { + case 0: + return UNIHUB_AL10_LED_SPEED_000; + + case 1: + return UNIHUB_AL10_LED_SPEED_025; + + case 2: + return UNIHUB_AL10_LED_SPEED_050; + + case 3: + return UNIHUB_AL10_LED_SPEED_075; + + case 4: + return UNIHUB_AL10_LED_SPEED_100; + + default: + return UNIHUB_AL10_LED_SPEED_050; + } +} + +uint8_t RGBController_LianLiUniHub_AL10::convertLedDirection(uint8_t direction) +{ + switch (direction) + { + case 0: + return UNIHUB_AL10_LED_DIRECTION_LTR; + + case 1: + return UNIHUB_AL10_LED_DIRECTION_RTL; + + default: + return UNIHUB_AL10_LED_DIRECTION_LTR; + } +} + +uint8_t RGBController_LianLiUniHub_AL10::convertLedBrightness(uint8_t brightness) +{ + switch (brightness) + { + case 0: + return UNIHUB_AL10_LED_BRIGHTNESS_000; + + case 1: + return UNIHUB_AL10_LED_BRIGHTNESS_025; + + case 2: + return UNIHUB_AL10_LED_BRIGHTNESS_050; + + case 3: + return UNIHUB_AL10_LED_BRIGHTNESS_075; + + case 4: + return UNIHUB_AL10_LED_BRIGHTNESS_100; + + default: + return UNIHUB_AL10_LED_BRIGHTNESS_100; + } +} +uint8_t RGBController_LianLiUniHub_AL10::convertLedCountToFanCount(uint8_t count) +{ + /*-------------------------------------------------*\ + | Converts <20 to 0, 20-39 to 1, 40-59 to 2, 60=79 | + | to 3 and 80+ to 4 | + \*-------------------------------------------------*/ + // Sets lower and upper limits + if (count == 0x00) + { + return 0x00; + } + if (count >= 0x50) + { + count = 0x50; + } + + /*---------------------------------------------------------*\ + | Returns regular count if it's not in multiples of 20s | + | (AL120 has 20 LEDs per fan, LED strip scenario) | + \*---------------------------------------------------------*/ + if (count % 20) + { + return(count); + } + else + { + return(count / 20); + } +} diff --git a/Controllers/LianLiController/RGBController_LianLiUniHub_AL10.h b/Controllers/LianLiController/RGBController_LianLiUniHub_AL10.h new file mode 100644 index 00000000..beea7cc6 --- /dev/null +++ b/Controllers/LianLiController/RGBController_LianLiUniHub_AL10.h @@ -0,0 +1,47 @@ +/*-----------------------------------------*\ +| RGBController_LianLiUniHub_AL10.h | +| | +| Generic RGB Interface for Lian Li Uni | +| Hub USB controller driver | +| | +| Oliver P 05/05/2022 | +| Credit to Luca Lovisa for original work. | +\*-----------------------------------------*/ + +#pragma once + +#include +#include + +#include "LianLiUniHub_AL10Controller.h" +#include "RGBController.h" + +class RGBController_LianLiUniHub_AL10 : public RGBController +{ +public: + RGBController_LianLiUniHub_AL10(LianLiUniHub_AL10Controller* controller_ptr); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + + void SetCustomMode(); + +private: + uint8_t convertAnyFanCount(uint8_t count); + uint8_t convertLedSpeed(uint8_t speed); + uint8_t convertLedDirection(uint8_t direction); + uint8_t convertLedBrightness(uint8_t brightness); + + uint8_t convertLedCountToFanCount(uint8_t count); + +private: + LianLiUniHub_AL10Controller* controller; + bool initializedMode; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index 28120ff4..284e647b 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -176,6 +176,8 @@ contains(QMAKE_PLATFORM, freebsd) { HEADERS += \ Colors.h \ + Controllers/LianLiController/LianLiUniHub_AL10Controller.h \ + Controllers/LianLiController/RGBController_LianLiUniHub_AL10.h \ dependencies/ColorWheel/ColorWheel.h \ dependencies/Swatches/swatches.h \ dependencies/json/json.hpp \ @@ -450,6 +452,8 @@ HEADERS += Controllers/LianLiController/RGBController_LianLiUniHub.h \ Controllers/LianLiController/RGBController_StrimerLConnect.h \ Controllers/LianLiController/StrimerLConnectController.h \ + Controllers/LianLiController/LianLiUniHubALController.h \ + Controllers/LianLiController/RGBController_LianLiUniHubAL.h \ Controllers/LogitechController/LogitechProtocolCommon.h \ Controllers/LogitechController/LogitechG203LController.h \ Controllers/LogitechController/LogitechG213Controller.h \ @@ -629,6 +633,8 @@ contains(QMAKE_PLATFORM, freebsd) { } SOURCES += \ + Controllers/LianLiController/LianLiUniHub_AL10Controller.cpp \ + Controllers/LianLiController/RGBController_LianLiUniHub_AL10.cpp \ dependencies/Swatches/swatches.cpp \ dependencies/dmiinfo.cpp \ dependencies/ColorWheel/ColorWheel.cpp \ @@ -991,6 +997,8 @@ SOURCES += Controllers/LianLiController/RGBController_LianLiUniHub.cpp \ Controllers/LianLiController/RGBController_StrimerLConnect.cpp \ Controllers/LianLiController/StrimerLConnectController.cpp \ + Controllers/LianLiController/LianLiUniHubALController.cpp \ + Controllers/LianLiController/RGBController_LianLiUniHubAL.cpp \ Controllers/LogitechController/LogitechControllerDetect.cpp \ Controllers/LogitechController/LogitechProtocolCommon.cpp \ Controllers/LogitechController/LogitechG203LController.cpp \