Split machine module in sub modules. Add gigabyte_rgb_fusion module
authorGreg Burri <greg.burri@gmail.com>
Mon, 17 Feb 2025 16:56:09 +0000 (17:56 +0100)
committerGreg Burri <greg.burri@gmail.com>
Mon, 17 Feb 2025 16:56:09 +0000 (17:56 +0100)
13 files changed:
Cargo.toml
src/gigabyte_rgb_fusion_usb.rs [new file with mode: 0644]
src/lian_li_sl_infinity.rs
src/machine.rs [deleted file]
src/machine/jiji.rs [new file with mode: 0644]
src/machine/lyss_metal.rs [new file with mode: 0644]
src/machine/lyss_metal2.rs [new file with mode: 0644]
src/machine/mod.rs [new file with mode: 0644]
src/main.rs
src/main_loop.rs
src/piix4_i2c.rs
src/settings.rs
src/tests.rs

index 82d89af..ce95993 100644 (file)
@@ -10,11 +10,12 @@ edition = "2021"
 
 [dependencies]
 serde = { version = "1.0", features = ["derive"] }
-ron = "0.8"                                        # Rust object notation, to load configuration files.
+# Rust object notation, to load configuration files.
+ron = "0.8"
 
 num = "0.4"
 
-dirs = "5.0"
+dirs = "6.0"
 anyhow = "1.0"
 
 flexi_logger = "0.29"
@@ -31,14 +32,14 @@ hidapi = "2.6"
 nvapi = "0.1"
 
 libc = "0.2"
-wmi = "0.13"
+wmi = "0.15"
 crc = "3.2"
 
 # libloading = "0.8"
 # netcorehost = "0.15"
 
 [dependencies.windows]
-version = "0.58"
+version = "0.59"
 features = [
     "Win32_Foundation",
     "Win32_Security",
@@ -54,7 +55,7 @@ features = [
 ]
 
 [build-dependencies]
-bindgen = "0.70"
+bindgen = "0.71"
 
 [profile.release]
 # strip = "debuginfo"
diff --git a/src/gigabyte_rgb_fusion_usb.rs b/src/gigabyte_rgb_fusion_usb.rs
new file mode 100644 (file)
index 0000000..c9667be
--- /dev/null
@@ -0,0 +1,206 @@
+use std::{str, time::Duration};
+
+use crate::rgb::RGB;
+
+const VID: u16 = 0x048D; // Vendor ID: Gigabyte.
+const PID: u16 = 0x5711; // Product ID.
+
+/*
+HidDeviceInfo { vendor_id: 1165, product_id: 22289 }
+name: GIGABYTE Device
+interface number: 1
+page: 65417
+usage: 204
+*/
+
+pub struct Device {
+    device: hidapi::HidDevice,
+}
+
+impl Device {
+    pub fn new(api: &hidapi::HidApi) -> anyhow::Result<Self> {
+        let d = api
+            .device_list()
+            .find(|d| d.vendor_id() == VID && d.product_id() == PID && d.usage() == 204)
+            .unwrap()
+            .open_device(api)
+            .unwrap();
+
+        let device = Device { device: d };
+
+        // Initialization?
+        let mut buffer = [0u8; 64];
+        buffer[0] = 0xCC;
+        buffer[1] = 0x60;
+        device.device.send_feature_report(&buffer)?;
+
+        Ok(device)
+    }
+
+    pub fn test_raw_data(&self) -> anyhow::Result<()> {
+        loop {
+            self.send_str(
+                "
+// cc20010000000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+cc22040000000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc23080000000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc24100000000000 000000015a006127 b70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc25200000000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc26400000000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc27800000000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc91000200000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc92000400000000 000000015a00b727 610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc34110100000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+cc580000392761b7 2761b72761b72761 b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b70000
+// cc583900392761b7 2761b72761b72761 b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b70000
+// cc587200392761b7 2761b72761b72761 b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b70000
+// cc58ab00092761b7 2761b72761b70000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+// Arctic freezer 3
+cc620000392761b7 2761b72761b72761 b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b70000
+cc623900392761b7 2761b72761b72761 b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b70000
+// cc627200392761b7 2761b72761b72761 b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b72761b70000
+// cc62ab00092761b7 2761b72761b70000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")?;
+            std::thread::sleep(Duration::from_secs(1));
+            self.send_str(
+    "
+// cc20010000000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+cc22040000000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc23080000000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc24100000000000 000000015a0035ab 430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc25200000000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc26400000000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc27800000000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc91000200000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc92000400000000 000000015a0043ab 350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc28ff0700000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+// cc34110100000000 0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+cc58000039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab45430000
+// cc58390039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab45430000
+// cc58720039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab45430000
+// cc58ab0009ab4543 ab4543ab45430000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+// Arctic freezer 3
+cc62000039 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 ab4543 0000
+cc62390039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab45430000
+// cc62720039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab45430000
+// cc62ab0009ab4543 ab4543ab45430000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+")?;
+            std::thread::sleep(Duration::from_secs(1));
+        }
+    }
+
+    fn line_to_bytes(line: &str) -> Vec<u8> {
+        let line = line.replace(" ", "");
+        let mut buffer = vec![0u8; line.len() / 2];
+        for i in 0..buffer.len() {
+            buffer[i] = u8::from_str_radix(&line[2 * i..2 * i + 2], 16).unwrap();
+        }
+
+        println!("buffer: {:?}", buffer);
+        buffer
+    }
+
+    fn send_str(&self, buffer: &str) -> anyhow::Result<()> {
+        println!("------");
+        for line in buffer.lines() {
+            let line = line.trim();
+            if line.is_empty() || line.starts_with("//") {
+                continue;
+            }
+
+            let buffer = Self::line_to_bytes(line);
+            self.device.send_feature_report(&buffer)?;
+        }
+        Ok(())
+    }
+
+    const NB_LEDS_PER_PACKET: usize = 19;
+
+    fn set_color_device(&self, color: &RGB, device: u8, nb_leds: usize) -> anyhow::Result<()> {
+        let nb_packets = (nb_leds - 1) / Self::NB_LEDS_PER_PACKET + 1;
+        for i in 0..nb_packets {
+            let mut buffer = [0u8; 64];
+            let nb_leds_in_packet = if i == nb_packets - 1 && nb_leds % Self::NB_LEDS_PER_PACKET > 0
+            {
+                nb_leds % Self::NB_LEDS_PER_PACKET
+            } else {
+                Self::NB_LEDS_PER_PACKET
+            };
+
+            buffer[0] = 0xCC;
+            buffer[1] = device;
+            buffer[2] = (i * Self::NB_LEDS_PER_PACKET) as u8 * 3;
+            buffer[4] = nb_leds_in_packet as u8 * 3;
+
+            for j in 0..nb_leds_in_packet {
+                buffer[5 + 3 * j] = color.green;
+                buffer[5 + 3 * j + 1] = color.red;
+                buffer[5 + 3 * j + 2] = color.blue;
+            }
+
+            // println!("BUFFER: {:?}", buffer); // Debug.
+            self.device.send_feature_report(&buffer)?;
+        }
+
+        Ok(())
+    }
+
+    fn set_color_motherboard(&self, color: &RGB) -> anyhow::Result<()> {
+        {
+            let mut buffer = [0u8; 64];
+            buffer[0] = 0xCC;
+            buffer[1] = 0x22;
+            buffer[2] = 0x04;
+
+            buffer[11] = 0x01;
+            buffer[12] = 0x5a;
+
+            buffer[14] = color.blue;
+            buffer[15] = color.green;
+            buffer[16] = color.red;
+
+            self.device.send_feature_report(&buffer)?;
+        }
+        {
+            let mut buffer = [0u8; 64];
+            buffer[0] = 0xCC;
+            buffer[1] = 0x28;
+            buffer[2] = 0xFF;
+            buffer[3] = 0x07;
+
+            self.device.send_feature_report(&buffer)?;
+        }
+
+        Ok(())
+    }
+
+    pub fn set_color(&self, color: &RGB) {
+        // Motherboard & GPU power cables.
+        self.set_color_device(color, 0x58, 19).unwrap();
+
+        // Arctic freezer 3.
+        self.set_color_device(color, 0x62, 38).unwrap();
+
+        self.set_color_motherboard(color).unwrap();
+    }
+}
index d16a4a3..cd3e149 100644 (file)
@@ -25,11 +25,9 @@ pub struct Device {
 
 impl Device {
     pub fn new(api: &hidapi::HidApi) -> Self {
-        let device = Device {
+        Self {
             device: api.open(LIANLI_VID, LIANLI_UNI_HUB_SLINF_PID).unwrap(),
-        };
-
-        device
+        }
     }
 
     fn send_start_action(&self, channel_id: u8) {
diff --git a/src/machine.rs b/src/machine.rs
deleted file mode 100644 (file)
index 1d7bb2e..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-use log::error;
-use nvapi::sys::i2c;
-
-use crate::{
-    /*a770,*/ asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature,
-    intel_arc, lian_li_sl_infinity, rgb,
-};
-
-const RGB_FUSION2_GPU_REG_COLOR: u8 = 0x40;
-const RGB_FUSION2_GPU_REG_MODE: u8 = 0x88;
-
-const GIGABYTE_RTX3080TI_VISION_OC_ADDR: u8 = 0x63;
-
-pub trait Machine {
-    fn set_color(&mut self, color: &rgb::RGB) {
-        self.set_color_1(&color);
-        self.set_color_2(&color);
-    }
-    fn set_color_1(&mut self, color: &rgb::RGB);
-    fn set_color_2(&mut self, color: &rgb::RGB);
-    fn get_gpu_tmp(&self) -> f32;
-    fn get_cpu_tmp(&self) -> f32;
-}
-
-pub struct MachineJiji {
-    ram: Vec<corsair_vengeance::Controller>,
-    b650e_device: asus_aura_usb::Device,
-    // a770: a770::A770,
-    // gpu_devices: intel_arc::Devices,
-    gpus: Vec<nvapi::PhysicalGpu>,
-}
-
-impl MachineJiji {
-    pub fn new() -> anyhow::Result<Self> {
-        let api = hidapi::HidApi::new().unwrap();
-        Ok(MachineJiji {
-            ram: vec![
-                corsair_vengeance::Controller::new(0x19),
-                corsair_vengeance::Controller::new(0x1B),
-            ],
-            b650e_device: asus_aura_usb::Device::new(&api, asus_aura_usb::Motherboard::Asus650e)?,
-            // a770: a770::A770::new()?,
-            // gpu_devices: unsafe { intel_arc::GetDevices() },
-            gpus: nvapi::PhysicalGpu::enumerate()?,
-        })
-    }
-}
-
-impl Machine for MachineJiji {
-    fn set_color_1(&mut self, color: &rgb::RGB) {
-        for controller in &self.ram {
-            controller.set_color(&color);
-        }
-        self.b650e_device.set_color(&color).unwrap();
-    }
-
-    fn set_color_2(&mut self, color: &rgb::RGB) {} // No color 2.
-
-    fn get_gpu_tmp(&self) -> f32 {
-        // unsafe { intel_arc::GetTemperature(self.gpu_devices, 0) as f32 }
-        self.gpus[0].thermal_settings(None).unwrap()[0]
-            .current_temperature
-            .0 as f32
-    }
-
-    fn get_cpu_tmp(&self) -> f32 {
-        cpu_temperature::read()
-    }
-}
-
-// impl Drop for MachineJiji {
-//     fn drop(&mut self) {
-//         unsafe {
-//             intel_arc::FreeDevices(self.gpu_devices);
-//         }
-//     }
-// }
-
-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<nvapi::PhysicalGpu>,
-}
-
-impl MachineLyssMetal {
-    pub fn new() -> anyhow::Result<Self> {
-        let api = hidapi::HidApi::new()?;
-
-        nvapi::initialize().expect("Unable to initialize nvapi (Nvidia API)");
-
-        let machine = MachineLyssMetal {
-            crosshair_device: asus_aura_usb::Device::new(
-                &api,
-                asus_aura_usb::Motherboard::AsusCrosshairVIIIHero,
-            )?,
-            corsair_lignting_pro: corsair_lighting_pro::Device::new(
-                &api,
-                &rgb::RGB {
-                    red: 0,
-                    green: 255,
-                    blue: 40,
-                },
-            ),
-            lian_li_sl_infinity: lian_li_sl_infinity::Device::new(&api),
-            gpus: nvapi::PhysicalGpu::enumerate()?,
-        };
-
-        // machine.set_mode_3080ti();
-        Ok(machine)
-    }
-
-    // Doesn't work: "Error: NotSupported".
-    // From OpenRGB, see the following files:
-    //  * Controllers\GigabyteRGBFusion2GPUController\GigabyteRGBFusion2GPUControllerDetect.cpp
-    //  * Controllers\GigabyteRGBFusion2GPUController\RGBController_GigabyteRGBFusion2GPU.cpp
-    //  * Controllers\GigabyteRGBFusion2GPUController\GigabyteRGBFusion2GPUController.cpp
-    //  * i2c_smbus\i2c_smbus_nvapi.cpp
-    // Implementation of nvapi-rs: https://github.com/arcnmx/nvapi-rs/blob/master/src/gpu.rs#L645
-    pub fn test_i2c(&self) {
-        // Test from 'GigabyteRGBFusion2GPUControllerDetect.cpp'
-        let data = [0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
-        self.gpus[0]
-            .i2c_write(
-                0,
-                Some(1),
-                false,
-                GIGABYTE_RTX3080TI_VISION_OC_ADDR,
-                &[],
-                &data,
-                i2c::I2cSpeed::Default,
-            )
-            .expect("Error");
-    }
-
-    fn set_mode_3080ti(&self) {
-        let data = [
-            RGB_FUSION2_GPU_REG_MODE,
-            0x01, // Mode (1: static).
-            0x00, // Speed.
-            0x63, // Brightness max.
-            0x00, // Mistery flag.
-            0x01, // Zone.
-            0x00,
-            0x00,
-        ];
-        self.gpus[0]
-            .i2c_write(
-                0,
-                Some(1),
-                false,
-                GIGABYTE_RTX3080TI_VISION_OC_ADDR,
-                &[],
-                &data,
-                i2c::I2cSpeed::Default,
-            )
-            .expect("Error");
-    }
-
-    fn set_color_3080ti(&self, color: &rgb::RGB) {
-        // TODO.
-        self.test_i2c();
-    }
-}
-
-impl Machine for MachineLyssMetal {
-    fn set_color_1(&mut self, color: &rgb::RGB) {
-        self.crosshair_device.set_color(&color).unwrap();
-        self.corsair_lignting_pro.set_color(&color);
-        // self.set_color_3080ti(&color); // TODO.
-    }
-
-    fn set_color_2(&mut self, color: &rgb::RGB) {
-        self.lian_li_sl_infinity.set_color(&color);
-    }
-
-    fn get_gpu_tmp(&self) -> f32 {
-        self.gpus[0].thermal_settings(None).unwrap()[0]
-            .current_temperature
-            .0 as f32
-    }
-
-    fn get_cpu_tmp(&self) -> f32 {
-        cpu_temperature::read()
-    }
-}
diff --git a/src/machine/jiji.rs b/src/machine/jiji.rs
new file mode 100644 (file)
index 0000000..402d9a4
--- /dev/null
@@ -0,0 +1,57 @@
+use crate::{asus_aura_usb, corsair_vengeance, cpu_temperature, rgb};
+
+use super::Machine;
+
+pub struct MachineJiji {
+    ram: Vec<corsair_vengeance::Controller>,
+    b650e_device: asus_aura_usb::Device,
+    // a770: a770::A770,
+    // gpu_devices: intel_arc::Devices,
+    gpus: Vec<nvapi::PhysicalGpu>,
+}
+
+impl MachineJiji {
+    pub fn new() -> anyhow::Result<Self> {
+        let api = hidapi::HidApi::new().unwrap();
+        Ok(MachineJiji {
+            ram: vec![
+                corsair_vengeance::Controller::new(0x19),
+                corsair_vengeance::Controller::new(0x1B),
+            ],
+            b650e_device: asus_aura_usb::Device::new(&api, asus_aura_usb::Motherboard::Asus650e)?,
+            // a770: a770::A770::new()?,
+            // gpu_devices: unsafe { intel_arc::GetDevices() },
+            gpus: nvapi::PhysicalGpu::enumerate()?,
+        })
+    }
+}
+
+impl Machine for MachineJiji {
+    fn set_color_1(&mut self, color: &rgb::RGB) {
+        for controller in &self.ram {
+            controller.set_color(color);
+        }
+        self.b650e_device.set_color(color).unwrap();
+    }
+
+    fn set_color_2(&mut self, color: &rgb::RGB) {} // No color 2.
+
+    fn get_gpu_tmp(&self) -> f32 {
+        // unsafe { intel_arc::GetTemperature(self.gpu_devices, 0) as f32 }
+        self.gpus[0].thermal_settings(None).unwrap()[0]
+            .current_temperature
+            .0 as f32
+    }
+
+    fn get_cpu_tmp(&self) -> f32 {
+        cpu_temperature::read()
+    }
+}
+
+// impl Drop for MachineJiji {
+//     fn drop(&mut self) {
+//         unsafe {
+//             intel_arc::FreeDevices(self.gpu_devices);
+//         }
+//     }
+// }
diff --git a/src/machine/lyss_metal.rs b/src/machine/lyss_metal.rs
new file mode 100644 (file)
index 0000000..ba4cc43
--- /dev/null
@@ -0,0 +1,115 @@
+use nvapi::sys::i2c;
+
+use crate::{asus_aura_usb, corsair_lighting_pro, cpu_temperature, lian_li_sl_infinity, rgb};
+
+use super::Machine;
+
+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<nvapi::PhysicalGpu>,
+}
+
+impl MachineLyssMetal {
+    pub fn new() -> anyhow::Result<Self> {
+        let api = hidapi::HidApi::new()?;
+
+        nvapi::initialize().expect("Unable to initialize nvapi (Nvidia API)");
+
+        let machine = Self {
+            crosshair_device: asus_aura_usb::Device::new(
+                &api,
+                asus_aura_usb::Motherboard::AsusCrosshairVIIIHero,
+            )?,
+            corsair_lignting_pro: corsair_lighting_pro::Device::new(
+                &api,
+                &rgb::RGB {
+                    red: 0,
+                    green: 255,
+                    blue: 40,
+                },
+            ),
+            lian_li_sl_infinity: lian_li_sl_infinity::Device::new(&api),
+            gpus: nvapi::PhysicalGpu::enumerate()?,
+        };
+
+        // machine.set_mode_3080ti();
+        Ok(machine)
+    }
+
+    // Doesn't work: "Error: NotSupported".
+    // From OpenRGB, see the following files:
+    //  * Controllers\GigabyteRGBFusion2GPUController\GigabyteRGBFusion2GPUControllerDetect.cpp
+    //  * Controllers\GigabyteRGBFusion2GPUController\RGBController_GigabyteRGBFusion2GPU.cpp
+    //  * Controllers\GigabyteRGBFusion2GPUController\GigabyteRGBFusion2GPUController.cpp
+    //  * i2c_smbus\i2c_smbus_nvapi.cpp
+    // Implementation of nvapi-rs: https://github.com/arcnmx/nvapi-rs/blob/master/src/gpu.rs#L645
+    // Reference API doc: https://docs.nvidia.com/gameworks/content/gameworkslibrary/coresdk/nvapi/structNV__I2C__INFO__V3.html
+    pub fn test_i2c(&self) {
+        // Test from 'GigabyteRGBFusion2GPUControllerDetect.cpp'
+        let data = [0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+        self.gpus[0]
+            .i2c_write(
+                0,
+                Some(1),
+                false,
+                super::GIGABYTE_RTX3080TI_VISION_OC_ADDR,
+                &[],
+                &data,
+                i2c::I2cSpeed::Default,
+            )
+            .expect("Error");
+    }
+
+    fn set_mode_3080ti(&self) {
+        let data = [
+            super::RGB_FUSION2_GPU_REG_MODE,
+            0x01, // Mode (1: static).
+            0x00, // Speed.
+            0x63, // Brightness max.
+            0x00, // Mistery flag.
+            0x01, // Zone.
+            0x00,
+            0x00,
+        ];
+        self.gpus[0]
+            .i2c_write(
+                0,
+                Some(1),
+                false,
+                super::GIGABYTE_RTX3080TI_VISION_OC_ADDR,
+                &[],
+                &data,
+                i2c::I2cSpeed::Default,
+            )
+            .expect("Error");
+    }
+
+    fn set_color_3080ti(&self, color: &rgb::RGB) {
+        // TODO.
+        self.test_i2c();
+    }
+}
+
+impl Machine for MachineLyssMetal {
+    fn set_color_1(&mut self, color: &rgb::RGB) {
+        self.crosshair_device.set_color(color).unwrap();
+        self.corsair_lignting_pro.set_color(color);
+        // self.set_color_3080ti(&color); // TODO.
+    }
+
+    fn set_color_2(&mut self, color: &rgb::RGB) {
+        self.lian_li_sl_infinity.set_color(color);
+    }
+
+    fn get_gpu_tmp(&self) -> f32 {
+        self.gpus[0].thermal_settings(None).unwrap()[0]
+            .current_temperature
+            .0 as f32
+    }
+
+    fn get_cpu_tmp(&self) -> f32 {
+        cpu_temperature::read()
+    }
+}
diff --git a/src/machine/lyss_metal2.rs b/src/machine/lyss_metal2.rs
new file mode 100644 (file)
index 0000000..f96d213
--- /dev/null
@@ -0,0 +1,114 @@
+use nvapi::sys::i2c;
+
+use crate::{
+    corsair_lighting_pro, cpu_temperature, gigabyte_rgb_fusion_usb, lian_li_sl_infinity, rgb,
+};
+
+use super::Machine;
+
+pub struct MachineLyssMetal2 {
+    fusion_device: gigabyte_rgb_fusion_usb::Device,
+    corsair_lignting_pro: corsair_lighting_pro::Device,
+    lian_li_sl_infinity: lian_li_sl_infinity::Device,
+    gpus: Vec<nvapi::PhysicalGpu>,
+}
+
+impl MachineLyssMetal2 {
+    pub fn new() -> anyhow::Result<Self> {
+        let api = hidapi::HidApi::new()?;
+
+        nvapi::initialize().expect("Unable to initialize nvapi (Nvidia API)");
+
+        let machine = Self {
+            fusion_device: gigabyte_rgb_fusion_usb::Device::new(&api)?,
+            corsair_lignting_pro: corsair_lighting_pro::Device::new(
+                &api,
+                &rgb::RGB {
+                    red: 0,
+                    green: 255,
+                    blue: 40,
+                },
+            ),
+            lian_li_sl_infinity: lian_li_sl_infinity::Device::new(&api),
+            gpus: nvapi::PhysicalGpu::enumerate()?,
+        };
+
+        // machine.set_mode_3080ti();
+        Ok(machine)
+    }
+
+    // Doesn't work: "Error: NotSupported".
+    // From OpenRGB, see the following files:
+    //  * Controllers\GigabyteRGBFusion2GPUController\GigabyteRGBFusion2GPUControllerDetect.cpp
+    //  * Controllers\GigabyteRGBFusion2GPUController\RGBController_GigabyteRGBFusion2GPU.cpp
+    //  * Controllers\GigabyteRGBFusion2GPUController\GigabyteRGBFusion2GPUController.cpp
+    //  * i2c_smbus\i2c_smbus_nvapi.cpp
+    // Implementation of nvapi-rs: https://github.com/arcnmx/nvapi-rs/blob/master/src/gpu.rs#L645
+    // Reference API doc: https://docs.nvidia.com/gameworks/content/gameworkslibrary/coresdk/nvapi/structNV__I2C__INFO__V3.html
+    pub fn test_i2c(&self) {
+        // Test from 'GigabyteRGBFusion2GPUControllerDetect.cpp'
+        let data = [0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+        self.gpus[0]
+            .i2c_write(
+                0,
+                Some(1),
+                false,
+                super::GIGABYTE_RTX3080TI_VISION_OC_ADDR,
+                &[],
+                &data,
+                i2c::I2cSpeed::Default,
+            )
+            .expect("Error");
+    }
+
+    fn set_mode_3080ti(&self) {
+        let data = [
+            super::RGB_FUSION2_GPU_REG_MODE,
+            0x01, // Mode (1: static).
+            0x00, // Speed.
+            0x63, // Brightness max.
+            0x00, // Mistery flag.
+            0x01, // Zone.
+            0x00,
+            0x00,
+        ];
+        self.gpus[0]
+            .i2c_write(
+                0,
+                Some(1),
+                false,
+                super::GIGABYTE_RTX3080TI_VISION_OC_ADDR,
+                &[],
+                &data,
+                i2c::I2cSpeed::Default,
+            )
+            .expect("Error");
+    }
+
+    fn set_color_3080ti(&self, color: &rgb::RGB) {
+        // TODO.
+        self.test_i2c();
+    }
+}
+
+impl Machine for MachineLyssMetal2 {
+    fn set_color_1(&mut self, color: &rgb::RGB) {
+        self.corsair_lignting_pro.set_color(color);
+        self.fusion_device.set_color(color);
+        // self.set_color_3080ti(&color); // TODO.
+    }
+
+    fn set_color_2(&mut self, color: &rgb::RGB) {
+        self.lian_li_sl_infinity.set_color(color);
+    }
+
+    fn get_gpu_tmp(&self) -> f32 {
+        self.gpus[0].thermal_settings(None).unwrap()[0]
+            .current_temperature
+            .0 as f32
+    }
+
+    fn get_cpu_tmp(&self) -> f32 {
+        cpu_temperature::read()
+    }
+}
diff --git a/src/machine/mod.rs b/src/machine/mod.rs
new file mode 100644 (file)
index 0000000..0ed2ff5
--- /dev/null
@@ -0,0 +1,21 @@
+use crate::rgb;
+
+pub mod jiji;
+pub mod lyss_metal;
+pub mod lyss_metal2;
+
+const RGB_FUSION2_GPU_REG_COLOR: u8 = 0x40;
+const RGB_FUSION2_GPU_REG_MODE: u8 = 0x88;
+
+const GIGABYTE_RTX3080TI_VISION_OC_ADDR: u8 = 0x63;
+
+pub trait Machine {
+    fn set_color(&mut self, color: &rgb::RGB) {
+        self.set_color_1(color);
+        self.set_color_2(color);
+    }
+    fn set_color_1(&mut self, color: &rgb::RGB);
+    fn set_color_2(&mut self, color: &rgb::RGB);
+    fn get_gpu_tmp(&self) -> f32;
+    fn get_cpu_tmp(&self) -> f32;
+}
index a0443f7..ff87264 100644 (file)
@@ -38,6 +38,7 @@ mod intel_arc {
 mod a770;
 mod asus_aura_usb;
 mod corsair_lighting_pro;
+mod gigabyte_rgb_fusion_usb;
 mod lian_li_sl_infinity;
 mod machine;
 mod main_loop;
@@ -183,7 +184,7 @@ fn run_service(_arguments: Vec<OsString>) -> Result<(), windows_service::Error>
 
     let completed_event_handler = Arc::clone(&completed);
 
-    info!("Setuping the event handler...");
+    info!("Setup the event handler...");
 
     let event_handler = move |control_event| -> ServiceControlHandlerResult {
         match control_event {
index a11c36b..1d523b3 100644 (file)
@@ -35,15 +35,20 @@ pub fn main_loop(completed: Arc<AtomicBool>) {
     };
 
     let settings = settings::Settings::read(&file_conf_path).expect("Cannot load settings");
-    println!("Settings: {settings:?}");
+    println!("Settings: {settings:?} from {file_conf_path}");
 
     let mut machine: Box<dyn machine::Machine> = match settings.machine_name {
         settings::MachineName::Jiji => {
-            Box::new(machine::MachineJiji::new().expect("Unable to create MachineJiji"))
-        }
-        settings::MachineName::LyssMetal => {
-            Box::new(machine::MachineLyssMetal::new().expect("Unable to create MachineLyssMetal"))
+            Box::new(machine::jiji::MachineJiji::new().expect("Unable to create MachineJiji"))
         }
+        settings::MachineName::LyssMetal => Box::new(
+            machine::lyss_metal::MachineLyssMetal::new()
+                .expect("Unable to create MachineLyssMetal"),
+        ),
+        settings::MachineName::LyssMetal2 => Box::new(
+            machine::lyss_metal2::MachineLyssMetal2::new()
+                .expect("Unable to create MachineLyssMetal2"),
+        ),
     };
 
     let mut kernel = [0f32; consts::KERNEL_SIZE_SAMPLES];
index 7acc572..7397459 100644 (file)
@@ -88,18 +88,17 @@ impl I2c {
         );
         let mut data_block = [0u8; I2C_BLOCK_MAX + 2];
         data_block[0] = l as u8;
-        data_block[1..l + 1].copy_from_slice(&data);
+        data_block[1..l + 1].copy_from_slice(data);
 
         unsafe {
-            match self.i2c_smbus_xfer(
+            if let Err(error) = self.i2c_smbus_xfer(
                 addr,
                 AccessType::Write,
                 command,
                 TransactionType::I2cSmbusBlockData,
                 Some(&data_block),
             ) {
-                Err(error) => println!("Error when writing block (I2c): {error:?}"),
-                Ok(_) => (),
+                println!("Error when writing block (I2c): {error:?}");
             }
         }
     }
@@ -129,7 +128,7 @@ impl I2c {
             TransactionType::I2cSmbusQuick => {
                 self.write_io_port_byte(
                     SMBusAddressOffsets::Smbhstadd,
-                    addr << 1 | access_type as u8,
+                    (addr << 1) | access_type as u8,
                 );
                 Piix4TransactionType::Piix4Quick
             }
@@ -139,7 +138,7 @@ impl I2c {
             TransactionType::I2cSmbusBlockData => {
                 self.write_io_port_byte(
                     SMBusAddressOffsets::Smbhstadd,
-                    addr << 1 | access_type as u8,
+                    (addr << 1) | access_type as u8,
                 );
                 self.write_io_port_byte(SMBusAddressOffsets::Smbhstcmd, command);
                 if let AccessType::Write = access_type {
@@ -188,7 +187,7 @@ impl I2c {
                 for i in 1..=l {
                     data[i] = self.read_io_port_byte(SMBusAddressOffsets::Smbblkdat);
                 }
-                return Ok(XferResult::BlockData(data));
+                Ok(XferResult::BlockData(data))
             }
         }
     }
@@ -237,7 +236,7 @@ impl I2c {
             self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res);
         }
 
-        return Ok(());
+        Ok(())
     }
 
     unsafe fn write_io_port_byte(&self, op: SMBusAddressOffsets, value: u8) {
index 511cb8c..43ae03d 100644 (file)
@@ -12,6 +12,7 @@ use crate::rgb::RGB;
 pub enum MachineName {
     Jiji,
     LyssMetal,
+    LyssMetal2,
 }
 
 #[derive(Debug, Deserialize, Serialize)]
index b49081e..c7ea81c 100644 (file)
@@ -4,7 +4,7 @@ use wmi::{COMLibrary, Variant, WMIConnection};
 
 use crate::{
     a770, asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature,
-    lian_li_sl_infinity, machine, rgb::RGB, winring0, wrapper_winring0,
+    gigabyte_rgb_fusion_usb, lian_li_sl_infinity, machine, rgb::RGB, winring0, wrapper_winring0,
 };
 
 pub fn tests() {
@@ -14,7 +14,7 @@ pub fn tests() {
 
     // test_asus_aura_usb(asus_aura_usb::Motherboard::Asus650e);
     // test_corsair_lighting_pro();
-    test_lianli_sl_infinity();
+    // test_lianli_sl_infinity();
     // list_usb_devices();
     // test_roccat();
     // test_wmi();
@@ -24,6 +24,7 @@ pub fn tests() {
     // test_read_temperature_cpu();
     // test_read_temperature_a770();
     // test_read_temperature_3080();
+    test_gigabyte_fusion();
 
     winring0::deinit();
 
@@ -31,6 +32,17 @@ pub fn tests() {
     std::io::stdin().read_line(&mut String::new()).unwrap();
 }
 
+fn test_gigabyte_fusion() {
+    let api = hidapi::HidApi::new().unwrap();
+    let device = gigabyte_rgb_fusion_usb::Device::new(&api).unwrap();
+    // device.test_raw_data().unwrap();
+    device.set_color(&RGB {
+        red: 0xFF,
+        green: 0x00,
+        blue: 0x00,
+    });
+}
+
 fn test_wmi() {
     let com_con = COMLibrary::new().unwrap();
     let wmi_con = WMIConnection::new(com_con.into()).unwrap();
@@ -170,7 +182,8 @@ fn test_a770() {
 }
 
 fn test_3080ti() {
-    let machine: &mut dyn machine::Machine = &mut machine::MachineLyssMetal::new().unwrap();
+    let machine: &mut dyn machine::Machine =
+        &mut machine::lyss_metal::MachineLyssMetal::new().unwrap();
 
     machine.set_color(&RGB {
         red: 255,
@@ -188,7 +201,7 @@ fn test_read_temperature_cpu() {
 }
 
 fn test_read_temperature_a770() {
-    let jiji: &dyn machine::Machine = &machine::MachineJiji::new().unwrap();
+    let jiji: &dyn machine::Machine = &machine::jiji::MachineJiji::new().unwrap();
     println!("temp gpu: {}", jiji.get_gpu_tmp());
 }