From f23ee416738146f3f9b005ac759b9dd68574ddfa Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 28 Apr 2024 23:04:06 +0200 Subject: [PATCH] Add support for Lian Li SL Infinity fan controller --- Cargo.toml | 4 +- src/lian_li_sl_infinity.rs | 87 ++++++++++++++++++++++++++++++++++++++ src/machine.rs | 7 ++- src/main.rs | 1 + src/tests.rs | 18 ++++++-- 5 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 src/lian_li_sl_infinity.rs diff --git a/Cargo.toml b/Cargo.toml index 8ef1511..a69afbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ flexi_logger = "0.28" log-panics = { version = "2", features = ["with-backtrace"] } log = "0.4" -windows-service = "0.6" +windows-service = "0.7" # HIDAPI is a library which allows an application to interface with # USB and Bluetooth HID-Class devices. @@ -38,7 +38,7 @@ crc = "3.0" # netcorehost = "0.15" [dependencies.windows] -version = "0.54" +version = "0.56" features = [ "Win32_Foundation", "Win32_Security", diff --git a/src/lian_li_sl_infinity.rs b/src/lian_li_sl_infinity.rs new file mode 100644 index 0000000..d16a4a3 --- /dev/null +++ b/src/lian_li_sl_infinity.rs @@ -0,0 +1,87 @@ +use crate::rgb::RGB; + +const LIANLI_VID: u16 = 0x0CF2; +const LIANLI_UNI_HUB_SLINF_PID: u16 = 0xA102; + +const UNIHUB_SLINF_LED_MODE_STATIC_COLOR: u8 = 0x01; +const UNIHUB_SLINF_LED_SPEED_000: u8 = 0x02; +const UNIHUB_SLINF_LED_DIRECTION_LTR: u8 = 0x00; +const UNIHUB_SLINF_LED_BRIGHTNESS_100: u8 = 0x00; + +const UNIHUB_SLINF_TRANSACTION_ID: u8 = 0xE0; + +const BUFFER_SIZE: usize = 353; + +const NB_LEDS_PER_FAN: u8 = 8; +const NB_LEDS_PER_SIDE: u8 = 12; + +// Specific hardcoded values (should be given in the constructor). +const CHANNEL_COUNT: u8 = 4; // 2 Channel per line of fans: one for fan itself and one for sides. +const NB_FAN_PER_CHANNEL: u8 = 2; // 2 fans per channel. + +pub struct Device { + device: hidapi::HidDevice, +} + +impl Device { + pub fn new(api: &hidapi::HidApi) -> Self { + let device = Device { + device: api.open(LIANLI_VID, LIANLI_UNI_HUB_SLINF_PID).unwrap(), + }; + + device + } + + fn send_start_action(&self, channel_id: u8) { + let mut buffer = [0u8; 5]; + buffer[0x00] = UNIHUB_SLINF_TRANSACTION_ID; + buffer[0x01] = 0x10; + buffer[0x02] = 0x60; + buffer[0x03] = 1 + channel_id / 2; + buffer[0x04] = NB_FAN_PER_CHANNEL; + + let n_write = self.device.write(&buffer).unwrap(); + assert_eq!(n_write, BUFFER_SIZE); + } + + fn send_commit_data(&self, channel_id: u8) { + let mut buffer = [0u8; 6]; + buffer[0x00] = UNIHUB_SLINF_TRANSACTION_ID; + buffer[0x01] = 0x10 + channel_id; + buffer[0x02] = UNIHUB_SLINF_LED_MODE_STATIC_COLOR; + buffer[0x03] = UNIHUB_SLINF_LED_SPEED_000; + buffer[0x04] = UNIHUB_SLINF_LED_DIRECTION_LTR; + buffer[0x05] = UNIHUB_SLINF_LED_BRIGHTNESS_100; + + let n_write = self.device.write(&buffer).unwrap(); + assert_eq!(n_write, BUFFER_SIZE); + } + + pub fn set_color(&self, color: &RGB) { + for channel_id in 0..CHANNEL_COUNT { + self.send_start_action(channel_id); + + let mut buffer = [0u8; BUFFER_SIZE]; + buffer[0x00] = UNIHUB_SLINF_TRANSACTION_ID; + buffer[0x01] = 0x30 + channel_id; + + let nb_leds = if channel_id % 2 == 0 { + NB_LEDS_PER_FAN * NB_FAN_PER_CHANNEL + } else { + NB_LEDS_PER_SIDE * NB_FAN_PER_CHANNEL + }; + + for i in 0..(26 as usize) { + let pos = i * 3 + 2; + buffer[pos] = color.red; + buffer[pos + 1] = color.blue; + buffer[pos + 2] = color.green; + } + + let n_write = self.device.write(&buffer).unwrap(); + assert_eq!(n_write, buffer.len()); + + self.send_commit_data(channel_id); + } + } +} diff --git a/src/machine.rs b/src/machine.rs index ac60e72..1012c00 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,7 +3,7 @@ use nvapi::sys::i2c; use crate::{ /*a770,*/ asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature, - intel_arc, rgb, + intel_arc, lian_li_sl_infinity, rgb, }; const RGB_FUSION2_GPU_REG_COLOR: u8 = 0x40; @@ -75,6 +75,7 @@ impl Machine for MachineJiji { pub struct MachineLyssMetal { crosshair_device: asus_aura_usb::Device, corsair_lignting_pro: corsair_lighting_pro::Device, + lian_li_sl_infinity: lian_li_sl_infinity::Device, gpus: Vec, } @@ -97,6 +98,7 @@ impl MachineLyssMetal { blue: 40, }, ), + lian_li_sl_infinity: lian_li_sl_infinity::Device::new(&api), gpus: nvapi::PhysicalGpu::enumerate()?, }; @@ -159,8 +161,9 @@ impl MachineLyssMetal { impl Machine for MachineLyssMetal { fn set_color(&mut self, color: &rgb::RGB) { - self.crosshair_device.set_color(&color); + self.crosshair_device.set_color(&color).unwrap(); self.corsair_lignting_pro.set_color(&color); + self.lian_li_sl_infinity.set_color(&color); // self.set_color_3080ti(&color); // TODO. } diff --git a/src/main.rs b/src/main.rs index fdbb104..014c61d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ mod intel_arc { mod a770; mod asus_aura_usb; mod corsair_lighting_pro; +mod lian_li_sl_infinity; mod machine; mod main_loop; mod winring0; diff --git a/src/tests.rs b/src/tests.rs index f01f77a..b49081e 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use wmi::{COMLibrary, Variant, WMIConnection}; use crate::{ - a770, asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature, machine, - rgb::RGB, winring0, wrapper_winring0, + a770, asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature, + lian_li_sl_infinity, machine, rgb::RGB, winring0, wrapper_winring0, }; pub fn tests() { @@ -14,6 +14,7 @@ pub fn tests() { // test_asus_aura_usb(asus_aura_usb::Motherboard::Asus650e); // test_corsair_lighting_pro(); + test_lianli_sl_infinity(); // list_usb_devices(); // test_roccat(); // test_wmi(); @@ -22,7 +23,7 @@ pub fn tests() { // test_3080ti(); // test_read_temperature_cpu(); // test_read_temperature_a770(); - test_read_temperature_3080(); + // test_read_temperature_3080(); winring0::deinit(); @@ -136,6 +137,17 @@ fn test_corsair_lighting_pro() { } } +fn test_lianli_sl_infinity() { + let api = hidapi::HidApi::new().unwrap(); + let device = lian_li_sl_infinity::Device::new(&api); + + device.set_color(&RGB { + red: 0, + green: 0, + blue: 255, + }); +} + fn test_corsair() { let corsair_controllers = [ corsair_vengeance::Controller::new(0x19), -- 2.45.2