--- /dev/null
+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);
+ }
+ }
+}