From: Greg Burri Date: Wed, 19 Mar 2025 17:16:03 +0000 (+0100) Subject: Remove a lot of 'unwrap' X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=f215b5b6bdc772bfc91d54640a468fa19f0145d5;p=temp2RGB.git Remove a lot of 'unwrap' --- diff --git a/Cargo.toml b/Cargo.toml index ce95993..d14eea0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,63 +1,66 @@ -[package] -name = "temp_2_rgb" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -# [build] -# target = "i686-pc-windows-msvc" - -[dependencies] -serde = { version = "1.0", features = ["derive"] } -# Rust object notation, to load configuration files. -ron = "0.8" - -num = "0.4" - -dirs = "6.0" -anyhow = "1.0" - -flexi_logger = "0.29" -log-panics = { version = "2", features = ["with-backtrace"] } -log = "0.4" - -windows-service = "0.7" - -# HIDAPI is a library which allows an application to interface with -# USB and Bluetooth HID-Class devices. -hidapi = "2.6" - -# Nvidia API. -nvapi = "0.1" - -libc = "0.2" -wmi = "0.15" -crc = "3.2" - -# libloading = "0.8" -# netcorehost = "0.15" - -[dependencies.windows] -version = "0.59" -features = [ - "Win32_Foundation", - "Win32_Security", - "Win32_Storage_FileSystem", - "Win32_System_IO", - "Win32_System_Services", - "Win32_System_LibraryLoader", - "Win32_System_Threading", - # "Devices_I2c", - # "Devices_Enumeration", - # "Foundation", - # "Foundation_Collections", -] - -[build-dependencies] -bindgen = "0.71" - -[profile.release] -# strip = "debuginfo" -codegen-units = 1 -lto = true +[package] +name = "temp_2_rgb" +version = "0.1.0" +edition = "2024" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +# [build] +# target = "i686-pc-windows-msvc" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +# Rust object notation, to load configuration files. +ron = "0.8" + +num = "0.4" + +dirs = "6.0" +anyhow = "1.0" + +clap = { version = "4", features = ["derive"] } + +flexi_logger = "0.29" +log-panics = { version = "2", features = ["with-backtrace"] } +log = "0.4" + +windows-service = "0.8" + +# HIDAPI is a library which allows an application to interface with +# USB and Bluetooth HID-Class devices. +hidapi = "2.6" + +# Nvidia API. +nvapi = "0.1" + +libc = "0.2" +wmi = "0.15" +crc = "3.2" + +# libloading = "0.8" +# netcorehost = "0.15" + +[dependencies.windows] +version = "0.60" +features = [ + "Win32_Foundation", + "Win32_Security", + "Win32_Storage_FileSystem", + "Win32_System_IO", + "Win32_System_Services", + "Win32_System_LibraryLoader", + "Win32_System_Threading", + "Win32_System_SystemInformation", + # "Devices_I2c", + # "Devices_Enumeration", + # "Foundation", + # "Foundation_Collections", +] + +[build-dependencies] +bindgen = "0.71" + +[profile.release] +# strip = "debuginfo" +codegen-units = 1 +lto = true diff --git a/build.rs b/build.rs index 6612712..59d15d9 100644 --- a/build.rs +++ b/build.rs @@ -1,89 +1,90 @@ -extern crate bindgen; - -use std::{env, path::PathBuf}; - -// From: https://rust-lang.github.io/rust-bindgen/tutorial-0.html - -fn main() { - // Tell cargo to look for shared libraries in the specified directory - println!("cargo:rustc-link-search=winring0"); - println!("cargo:rustc-link-search=IntelArc"); - - // Tell cargo to tell rustc to link the system 'WinRing0x64' shared library. - println!("cargo:rustc-link-lib=WinRing0x64"); - println!("cargo:rustc-link-lib=IntelArc"); - - // Tell cargo to invalidate the built crate whenever the header changes - println!("cargo:rerun-if-changed=OlsApi.h"); - println!("cargo:rerun-if-changed=IntelArc.h"); - - // The bindgen::Builder is the main entry point - // to bindgen, and lets you build up options for - // the resulting bindings. - let bindings_winring0 = bindgen::Builder::default() - // The input header we would like to generate bindings for. - .header("winring0/OlsApi.h") - // .clang_arg("-target") - // .clang_arg("i686-pc-windows-msvc") - .clang_arg("-x") - .clang_arg("c++") - .clang_arg("--std") - .clang_arg("c++14") - // Commented out: not needed. - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - //.parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // Finish the builder and generate the bindings. - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings for winring0"); - - // Write the bindings to the $OUT_DIR/bindings.rs file. - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - - bindings_winring0 - .write_to_file(out_path.join("ols_api.rs")) - .expect("Couldn't write bindings for winring0!"); - - // The bindgen::Builder is the main entry point - // to bindgen, and lets you build up options for - // the resulting bindings. - let bindings_intel_arc = bindgen::Builder::default() - // The input header we would like to generate bindings for. - .header("IntelArc/IntelArc.h") - // .clang_arg("-target") - // .clang_arg("i686-pc-windows-msvc") - .clang_arg("-x") - .clang_arg("c++") - .clang_arg("--std") - .clang_arg("c++14") - // Commented out: not needed. - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - //.parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // Finish the builder and generate the bindings. - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings for IntelArc"); - - // Write the bindings to the $OUT_DIR/bindings.rs file. - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - - bindings_intel_arc - .write_to_file(out_path.join("intel_arc.rs")) - .expect("Couldn't write bindings for intel arc!"); - - // let out_dir = env::var("CARGO_TARGET_DIR").unwrap(); - // println!("out_dir: {}", out_dir); - // TODO: How to properly get the (current) target directory? - copy_file("winring0/WinRing0x64.sys", "target/debug/WinRing0x64.sys"); - copy_file("winring0/WinRing0x64.dll", "target/debug/WinRing0x64.dll"); - copy_file("winring0/WinRing0x64.sys", "target/release/WinRing0x64.sys"); - copy_file("winring0/WinRing0x64.dll", "target/release/WinRing0x64.dll"); -} - -fn copy_file(from: &str, to: &str) { - if let Err(e) = std::fs::copy(from, to) { - println!("cargo:warning={e:?} (copy {from} to {to})") - }; -} +extern crate bindgen; + +use std::{env, path::PathBuf}; + +// From: https://rust-lang.github.io/rust-bindgen/tutorial-0.html + +fn main() { + // Tell cargo to look for shared libraries in the specified directory + println!("cargo:rustc-link-search=winring0"); + // println!("cargo:rustc-link-search=IntelArc"); + + // Tell cargo to tell rustc to link the system 'WinRing0x64' shared library. + println!("cargo:rustc-link-lib=WinRing0x64"); + // println!("cargo:rustc-link-lib=IntelArc"); + + // Tell cargo to invalidate the built crate whenever the header changes + println!("cargo:rerun-if-changed=OlsApi.h"); + // println!("cargo:rerun-if-changed=IntelArc.h"); + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let bindings_winring0 = bindgen::Builder::default() + // The input header we would like to generate bindings for. + .header("winring0/OlsApi.h") + // .clang_arg("-target") + // .clang_arg("i686-pc-windows-msvc") + .clang_arg("-x") + .clang_arg("c++") + .clang_arg("--std") + .clang_arg("c++14") + // Commented out: not needed. + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + //.parse_callbacks(Box::new(bindgen::CargoCallbacks)) + // Finish the builder and generate the bindings. + .generate() + .expect("Unable to generate bindings for winring0"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + + bindings_winring0 + .write_to_file(out_path.join("ols_api.rs")) + .expect("Couldn't write bindings for winring0!"); + + /* + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let bindings_intel_arc = bindgen::Builder::default() + // The input header we would like to generate bindings for. + .header("IntelArc/IntelArc.h") + // .clang_arg("-target") + // .clang_arg("i686-pc-windows-msvc") + .clang_arg("-x") + .clang_arg("c++") + .clang_arg("--std") + .clang_arg("c++14") + // Commented out: not needed. + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + //.parse_callbacks(Box::new(bindgen::CargoCallbacks)) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings for IntelArc"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + + bindings_intel_arc + .write_to_file(out_path.join("intel_arc.rs")) + .expect("Couldn't write bindings for intel arc!"); + */ + + // let out_dir = env::var("CARGO_TARGET_DIR").unwrap(); + // println!("out_dir: {}", out_dir); + // TODO: How to properly get the (current) target directory? + copy_file("winring0/WinRing0x64.sys", "target/debug/WinRing0x64.sys"); + copy_file("winring0/WinRing0x64.dll", "target/debug/WinRing0x64.dll"); + copy_file("winring0/WinRing0x64.sys", "target/release/WinRing0x64.sys"); + copy_file("winring0/WinRing0x64.dll", "target/release/WinRing0x64.dll"); +} + +fn copy_file(from: &str, to: &str) { + if let Err(e) = std::fs::copy(from, to) { + println!("cargo:warning={e:?} (copy {from} to {to})") + }; +} diff --git a/src/a770.rs b/src/a770.rs index ed6c18e..8edfcb6 100644 --- a/src/a770.rs +++ b/src/a770.rs @@ -1,77 +1,77 @@ -// use windows::{ -// core::w, -// Win32::{self, Storage::FileSystem}, -// }; -// use netcorehost::{nethost, pdcstr}; - -// pub fn set_rgb(r: u8, g: u8, b: u8) { -// unsafe { -// let lib = libloading::Library::new("IntelOCWrapper.dll").unwrap(); - -// let fun: libloading::Symbol bool> = lib.get(b"SetLEDColor").unwrap(); -// let ctlInit: libloading::Symbol std::ffi::c_void> = lib.get(b"ctlInit").unwrap(); -// let ctlInit: libloading::Symbol std::ffi::c_void> = lib.get(b"SetLEDColor").unwrap(); -// println!("ok"); -// } - -// let hostfxr = nethost::load_hostfxr().unwrap(); -// let context = hostfxr.initialize_for_dotnet_command_line(pdcstr!("IntelOCWrapper.dll")).unwrap(); -// let result = context.run_app().value(); - -// unsafe { -// let handle = FileSystem::CreateFileW( -// // w!("\\\\.\\Intel_NF_I2C"), -// w!("\\\\.\\VIDEO\\INTC_I2C"), -// // w!("\\\\.\\WinRing0_1_2_0"), -// 3221225472, -// FileSystem::FILE_SHARE_MODE(0), -// None, -// FileSystem::FILE_CREATION_DISPOSITION(3), -// FileSystem::FILE_FLAGS_AND_ATTRIBUTES(1073741824), -// Win32::Foundation::HANDLE::default(), -// ); - -// println!("handle: {:?}", handle); -// } - -//"\\\\.\\Intel_NF_I2C" -// } - -// internal static \u0024ArrayType\u0024\u0024\u0024BY08E \u003FA0x171ed149\u002E\u003FprevData\u0040\u003F1\u003F\u003FSetLEDBehavior\u0040CVGAAdaptor\u0040\u0040UEAA_NEEEEEEEEE\u0040Z\u00404PAEA; -// public static __FnPtr<_ctl_result_t (_ctl_init_args_t*, _ctl_api_handle_t**)> __m2mep\u0040\u003FctlInit\u0040\u0040\u0024\u0024J0YA\u003FAW4_ctl_result_t\u0040\u0040PEAU_ctl_init_args_t\u0040\u0040PEAPEAU_ctl_api_handle_t\u0040\u0040\u0040Z; - -use log::error; - -use std::{ - io::prelude::*, - net::TcpStream, - process::{Child, Command}, -}; - -pub struct A770 { - process: Child, - stream: TcpStream, -} - -impl A770 { - pub fn new() -> anyhow::Result { - Ok(A770 { - process: Command::new(r"IntelOC.exe").spawn()?, - stream: TcpStream::connect("127.0.0.1:6577")?, - }) - } - - pub fn set_color(&mut self, r: u8, g: u8, b: u8) -> anyhow::Result<()> { - let buffer: [u8; 3] = [r, g, b]; - self.stream.write(&buffer).map(|_| ())?; - Ok(()) - } -} - -impl Drop for A770 { - fn drop(&mut self) { - if let Err(error) = self.process.kill().and(self.process.try_wait()) { - error!("Unable to kill the child process: {:?}", error); - } - } -} +// use windows::{ +// core::w, +// Win32::{self, Storage::FileSystem}, +// }; +// use netcorehost::{nethost, pdcstr}; + +// pub fn set_rgb(r: u8, g: u8, b: u8) { +// unsafe { +// let lib = libloading::Library::new("IntelOCWrapper.dll").unwrap(); + +// let fun: libloading::Symbol bool> = lib.get(b"SetLEDColor").unwrap(); +// let ctlInit: libloading::Symbol std::ffi::c_void> = lib.get(b"ctlInit").unwrap(); +// let ctlInit: libloading::Symbol std::ffi::c_void> = lib.get(b"SetLEDColor").unwrap(); +// println!("ok"); +// } + +// let hostfxr = nethost::load_hostfxr().unwrap(); +// let context = hostfxr.initialize_for_dotnet_command_line(pdcstr!("IntelOCWrapper.dll")).unwrap(); +// let result = context.run_app().value(); + +// unsafe { +// let handle = FileSystem::CreateFileW( +// // w!("\\\\.\\Intel_NF_I2C"), +// w!("\\\\.\\VIDEO\\INTC_I2C"), +// // w!("\\\\.\\WinRing0_1_2_0"), +// 3221225472, +// FileSystem::FILE_SHARE_MODE(0), +// None, +// FileSystem::FILE_CREATION_DISPOSITION(3), +// FileSystem::FILE_FLAGS_AND_ATTRIBUTES(1073741824), +// Win32::Foundation::HANDLE::default(), +// ); + +// println!("handle: {:?}", handle); +// } + +//"\\\\.\\Intel_NF_I2C" +// } + +// internal static \u0024ArrayType\u0024\u0024\u0024BY08E \u003FA0x171ed149\u002E\u003FprevData\u0040\u003F1\u003F\u003FSetLEDBehavior\u0040CVGAAdaptor\u0040\u0040UEAA_NEEEEEEEEE\u0040Z\u00404PAEA; +// public static __FnPtr<_ctl_result_t (_ctl_init_args_t*, _ctl_api_handle_t**)> __m2mep\u0040\u003FctlInit\u0040\u0040\u0024\u0024J0YA\u003FAW4_ctl_result_t\u0040\u0040PEAU_ctl_init_args_t\u0040\u0040PEAPEAU_ctl_api_handle_t\u0040\u0040\u0040Z; + +use log::error; + +use std::{ + io::prelude::*, + net::TcpStream, + process::{Child, Command}, +}; + +pub struct A770 { + process: Child, + stream: TcpStream, +} + +impl A770 { + pub fn new() -> anyhow::Result { + Ok(A770 { + process: Command::new(r"IntelOC.exe").spawn()?, + stream: TcpStream::connect("127.0.0.1:6577")?, + }) + } + + pub fn set_color(&mut self, r: u8, g: u8, b: u8) -> anyhow::Result<()> { + let buffer: [u8; 3] = [r, g, b]; + self.stream.write(&buffer).map(|_| ())?; + Ok(()) + } +} + +impl Drop for A770 { + fn drop(&mut self) { + if let Err(error) = self.process.kill().and(self.process.try_wait()) { + error!("Unable to kill the child process: {:?}", error); + } + } +} diff --git a/src/asus_aura_usb.rs b/src/asus_aura_usb.rs index 31a2b27..2f8591d 100644 --- a/src/asus_aura_usb.rs +++ b/src/asus_aura_usb.rs @@ -1,6 +1,6 @@ use std::str; -use crate::rgb::RGB; +use crate::rgb::Rgb; /* * Doc: @@ -48,13 +48,13 @@ impl Device { buffer[0] = 0xEC; buffer[1] = AURA_REQUEST_FIRMWARE_VERSION; let n_write = self.device.write(&buffer)?; - assert_eq!(n_write, 65); + // assert_eq!(n_write, 65); buffer.fill(0); let n_read = self.device.read(&mut buffer)?; - assert_eq!(n_read, 65); - assert_eq!(buffer[0], 0xEC); - assert_eq!(buffer[1], 0x02); + // assert_eq!(n_read, 65); + // assert_eq!(buffer[0], 0xEC); + // assert_eq!(buffer[1], 0x02); Ok(String::from(str::from_utf8(&buffer[2..17])?)) } @@ -79,13 +79,13 @@ impl Device { buffer[0] = 0xEC; buffer[1] = AURA_REQUEST_CONFIG_TABLE; let n_write = self.device.write(&buffer)?; - assert_eq!(n_write, 65); + // assert_eq!(n_write, 65); buffer.fill(0); let n_read = self.device.read(&mut buffer)?; - assert_eq!(n_read, 65); - assert_eq!(buffer[0], 0xEC); - assert_eq!(buffer[1], 0x30); + // assert_eq!(n_read, 65); + // assert_eq!(buffer[0], 0xEC); + // assert_eq!(buffer[1], 0x30); Ok(buffer[4..64].try_into()?) } @@ -100,12 +100,12 @@ impl Device { for channel_effect_id in 0..2 { buffer[2] = channel_effect_id; // Channel effect id: Fixed. let n_write = self.device.write(&buffer)?; - assert_eq!(n_write, 65); + // assert_eq!(n_write, 65); } Ok(()) } - pub fn set_color(&self, color: &RGB) -> anyhow::Result<()> { + pub fn set_color(&self, color: &Rgb) -> anyhow::Result<()> { let mut buffer = [0u8; 65]; buffer[0] = 0xEC; buffer[1] = 0x36; @@ -124,7 +124,7 @@ impl Device { } let n_write = self.device.write(&buffer)?; - assert_eq!(n_write, 65); + // assert_eq!(n_write, 65); Ok(()) } @@ -135,7 +135,7 @@ impl Device { buffer[2] = 0x55; let n_write = self.device.write(&buffer)?; - assert_eq!(n_write, 65); + // assert_eq!(n_write, 65); Ok(()) } } diff --git a/src/common.rs b/src/common.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/corsair_lighting_pro.rs b/src/corsair_lighting_pro.rs index 25bee13..957326b 100644 --- a/src/corsair_lighting_pro.rs +++ b/src/corsair_lighting_pro.rs @@ -1,4 +1,4 @@ -use crate::rgb::RGB; +use crate::rgb::Rgb; const CORSAIR_VID: u16 = 0x1B1C; const CORSAIR_LIGHTING_NODE_PRO_PID: u16 = 0x0C0B; @@ -32,65 +32,69 @@ pub struct Device { } impl Device { - pub fn new(api: &hidapi::HidApi, initial_color: &RGB) -> Self { + pub fn new(api: &hidapi::HidApi, initial_color: &Rgb) -> anyhow::Result { let device = Device { - device: api - .open(CORSAIR_VID, CORSAIR_LIGHTING_NODE_PRO_PID) - .unwrap(), + device: api.open(CORSAIR_VID, CORSAIR_LIGHTING_NODE_PRO_PID)?, }; for channel_id in 0..CHANNEL_COUNT { - device.send_reset(channel_id); - device.send_begin(channel_id); - device.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE); - device.send_effect_config(channel_id, initial_color); - device.send_commit(channel_id); + device.send_reset(channel_id)?; + device.send_begin(channel_id)?; + device.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE)?; + device.send_effect_config(channel_id, initial_color)?; + device.send_commit(channel_id)?; } - device + Ok(device) } - fn send_reset(&self, channel_id: u8) { + fn send_reset(&self, channel_id: u8) -> anyhow::Result<()> { let mut buffer = [0u8; 65]; buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_RESET; buffer[0x02] = channel_id; - let n_write = self.device.write(&buffer).unwrap(); - assert_eq!(n_write, 65); + let n_write = self.device.write(&buffer)?; + // assert_eq!(n_write, 65); - let n_read = self.device.read(&mut buffer[0..16]).unwrap(); - assert_eq!(n_read, 16); - assert_eq!(buffer[0], 0); + let n_read = self.device.read(&mut buffer[0..16])?; + // assert_eq!(n_read, 16); + // assert_eq!(buffer[0], 0); + + Ok(()) } - fn send_begin(&self, channel_id: u8) { + fn send_begin(&self, channel_id: u8) -> anyhow::Result<()> { let mut buffer = [0u8; 65]; buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_BEGIN; buffer[0x02] = channel_id; - let n_write = self.device.write(&buffer).unwrap(); - assert_eq!(n_write, 65); + let n_write = self.device.write(&buffer)?; + // assert_eq!(n_write, 65); + + let n_read = self.device.read(&mut buffer[0..16])?; + // assert_eq!(n_read, 16); + // assert_eq!(buffer[0], 0); - let n_read = self.device.read(&mut buffer[0..16]).unwrap(); - assert_eq!(n_read, 16); - assert_eq!(buffer[0], 0); + Ok(()) } - fn send_port_state(&self, channel_id: u8, state: u8) { + fn send_port_state(&self, channel_id: u8, state: u8) -> anyhow::Result<()> { let mut buffer = [0u8; 65]; buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE; buffer[0x02] = channel_id; buffer[0x03] = state; - let n_write = self.device.write(&buffer).unwrap(); - assert_eq!(n_write, 65); + let n_write = self.device.write(&buffer)?; + // assert_eq!(n_write, 65); + + let n_read = self.device.read(&mut buffer[0..16])?; + // assert_eq!(n_read, 16); + // assert_eq!(buffer[0], 0); - let n_read = self.device.read(&mut buffer[0..16]).unwrap(); - assert_eq!(n_read, 16); - assert_eq!(buffer[0], 0); + Ok(()) } - fn send_effect_config(&self, channel_id: u8, color: &RGB) { + fn send_effect_config(&self, channel_id: u8, color: &Rgb) -> anyhow::Result<()> { println!("{color:?}"); let mut buffer = [0u8; 65]; @@ -111,31 +115,35 @@ impl Device { buffer[offset_color + 3 * i + 2] = color.blue; } - let n_write = self.device.write(&buffer).unwrap(); - assert_eq!(n_write, 65); + let n_write = self.device.write(&buffer)?; + // assert_eq!(n_write, 65); - let n_read = self.device.read(&mut buffer[0..16]).unwrap(); - assert_eq!(n_read, 16); - assert_eq!(buffer[0], 0); + let n_read = self.device.read(&mut buffer[0..16])?; + // assert_eq!(n_read, 16); + // assert_eq!(buffer[0], 0); + + Ok(()) } - fn send_commit(&self, channel_id: u8) { + fn send_commit(&self, channel_id: u8) -> anyhow::Result<()> { let mut buffer = [0u8; 65]; buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT; buffer[0x02] = 0xFF; - let n_write = self.device.write(&buffer).unwrap(); - assert_eq!(n_write, 65); + let n_write = self.device.write(&buffer)?; + // assert_eq!(n_write, 65); + + let n_read = self.device.read(&mut buffer[0..16])?; + // assert_eq!(n_read, 16); + // assert_eq!(buffer[0], 0); - let n_read = self.device.read(&mut buffer[0..16]).unwrap(); - assert_eq!(n_read, 16); - assert_eq!(buffer[0], 0); + Ok(()) } - pub fn set_color(&self, color: &RGB) { + pub fn set_color(&self, color: &Rgb) -> anyhow::Result<()> { // println!("set_color: {color:?}"); for channel_id in 0..CHANNEL_COUNT { - self.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE); + self.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE)?; let mut buffer = [0u8; 65]; @@ -159,15 +167,17 @@ impl Device { buffer[0x06 + n as usize] = color_component; } - let n_write = self.device.write(&buffer).unwrap(); - assert_eq!(n_write, 65); + let n_write = self.device.write(&buffer)?; + // assert_eq!(n_write, 65); - let n_read = self.device.read(&mut buffer[0..16]).unwrap(); - assert_eq!(n_read, 16); - assert_eq!(buffer[0], 0); + let n_read = self.device.read(&mut buffer[0..16])?; + // assert_eq!(n_read, 16); + // assert_eq!(buffer[0], 0); } - self.send_commit(channel_id); + self.send_commit(channel_id)?; } + + Ok(()) } } diff --git a/src/corsair_vengeance.rs b/src/corsair_vengeance.rs index 0c574f0..f1899dc 100644 --- a/src/corsair_vengeance.rs +++ b/src/corsair_vengeance.rs @@ -1,102 +1,102 @@ -use std::time::Duration; - -use crate::{piix4_i2c, rgb::RGB, timer}; - -// use windows::{*, Win32::{System::LibraryLoader::*, Foundation::HCS_E_CONNECTION_CLOSED, Security::InitializeAcl}, Devices::I2c::*, core::HSTRING}; - -use crc::{Algorithm, Crc}; - -const CRC8_ALG: Algorithm = Algorithm { - width: 8, - poly: 0x7, - init: 0x0, - refin: false, - refout: false, - xorout: 0x00, - check: 0x00, - residue: 0x00, -}; - -const BUS: i32 = 0; -const BUS_ADDRESS: i32 = 0x0B00; - -// Called "device location" in 'CorsairDominatorPlatinumController' class. -const ADDRESS_DDR_1: i32 = 0x19; -const ADDRESS_DDR_2: i32 = 0x1B; - -const CORSAIR_LED_COUNT: usize = 12; - -pub struct Controller { - bus: piix4_i2c::I2c, - ddr_address: u8, -} - -impl Controller { - pub fn new(ddr_address: u8) -> Self { - Controller { - bus: piix4_i2c::I2c::new(0x0B00), - ddr_address, - } - } - - pub fn test(&self) { - self.bus.i2c_smbus_write_quick(self.ddr_address, 0); - } - - pub fn set_color(&self, color: &RGB) { - let mut data = [0u8; CORSAIR_LED_COUNT * 3 + 2]; - data[0] = 0xC; - - for i in 0..CORSAIR_LED_COUNT { - let offset = i * 3 + 1; - data[offset] = color.red; - data[offset + 1] = color.green; - data[offset + 2] = color.blue; - } - - let crc = Crc::::new(&CRC8_ALG); - let mut digest = crc.digest(); - digest.update(&data[0..data.len() - 1]); // '-1' to not take the last byte. - data[data.len() - 1] = digest.finalize(); - - let timer = timer::Sleep::new(); - - self.bus - .write_block_data(self.ddr_address, 0x31, &data[0..piix4_i2c::I2C_BLOCK_MAX]); - timer.wait(Duration::from_micros(800)); - - self.bus - .write_block_data(self.ddr_address, 0x32, &data[piix4_i2c::I2C_BLOCK_MAX..]); - timer.wait(Duration::from_micros(200)); - } -} - -// TESTS WITH I2C from winapi: - -// let connection_settings = I2cConnectionSettings::Create(ADDRESS_DDR_1).unwrap(); - -// // For A770: "DISPLAY\\INTC_I2C\\7&3255D98A&0&UID26040" -// // "PCI\\VEN_1022&DEV_790B&SUBSYS_88771043&REV_71\\3&11583659&0&A0" - -// let selector = I2cDevice::GetDeviceSelector().unwrap(); -// println!("{:?}", selector); - -// let devices_async = Devices::Enumeration::DeviceInformation::FindAllAsync().unwrap(); // Devices::Enumeration::DeviceInformation::FindAllAsyncAqsFilter(&selector).unwrap(); -// let devices = devices_async.get().unwrap(); - -// // println!("{:?}", devices.Size()); - -// for i in 0..devices.Size().unwrap() { -// let device = devices.GetAt(i).unwrap(); -// println!("Device Name: {:?}", device.Name().unwrap()); -// println!("Device Kind: {:?}", device.Kind().unwrap()); -// println!("Device ID: {:?}", device.Id().unwrap()); -// println!("-----------------") -// } - -// // let device_id = "PCI\\VEN_1022&DEV_790B"; - -// // let async_get_device = I2cDevice::FromIdAsync(&HSTRING::from(device_id), &connection_settings).unwrap(); -// // let device = async_get_device.get(); - -// // println!("{:?}", device); +use std::time::Duration; + +use crate::{piix4_i2c, rgb::Rgb, timer}; + +// use windows::{*, Win32::{System::LibraryLoader::*, Foundation::HCS_E_CONNECTION_CLOSED, Security::InitializeAcl}, Devices::I2c::*, core::HSTRING}; + +use crc::{Algorithm, Crc}; + +const CRC8_ALG: Algorithm = Algorithm { + width: 8, + poly: 0x7, + init: 0x0, + refin: false, + refout: false, + xorout: 0x00, + check: 0x00, + residue: 0x00, +}; + +const BUS: i32 = 0; +const BUS_ADDRESS: i32 = 0x0B00; + +// Called "device location" in 'CorsairDominatorPlatinumController' class. +const ADDRESS_DDR_1: i32 = 0x19; +const ADDRESS_DDR_2: i32 = 0x1B; + +const CORSAIR_LED_COUNT: usize = 12; + +pub struct Controller { + bus: piix4_i2c::I2c, + ddr_address: u8, +} + +impl Controller { + pub fn new(ddr_address: u8) -> Self { + Controller { + bus: piix4_i2c::I2c::new(0x0B00), + ddr_address, + } + } + + pub fn test(&self) { + self.bus.i2c_smbus_write_quick(self.ddr_address, 0); + } + + pub fn set_color(&self, color: &Rgb) { + let mut data = [0u8; CORSAIR_LED_COUNT * 3 + 2]; + data[0] = 0xC; + + for i in 0..CORSAIR_LED_COUNT { + let offset = i * 3 + 1; + data[offset] = color.red; + data[offset + 1] = color.green; + data[offset + 2] = color.blue; + } + + let crc = Crc::::new(&CRC8_ALG); + let mut digest = crc.digest(); + digest.update(&data[0..data.len() - 1]); // '-1' to not take the last byte. + data[data.len() - 1] = digest.finalize(); + + let timer = timer::Sleep::new(); + + self.bus + .write_block_data(self.ddr_address, 0x31, &data[0..piix4_i2c::I2C_BLOCK_MAX]); + timer.wait(Duration::from_micros(800)); + + self.bus + .write_block_data(self.ddr_address, 0x32, &data[piix4_i2c::I2C_BLOCK_MAX..]); + timer.wait(Duration::from_micros(200)); + } +} + +// TESTS WITH I2C from winapi: + +// let connection_settings = I2cConnectionSettings::Create(ADDRESS_DDR_1).unwrap(); + +// // For A770: "DISPLAY\\INTC_I2C\\7&3255D98A&0&UID26040" +// // "PCI\\VEN_1022&DEV_790B&SUBSYS_88771043&REV_71\\3&11583659&0&A0" + +// let selector = I2cDevice::GetDeviceSelector().unwrap(); +// println!("{:?}", selector); + +// let devices_async = Devices::Enumeration::DeviceInformation::FindAllAsync().unwrap(); // Devices::Enumeration::DeviceInformation::FindAllAsyncAqsFilter(&selector).unwrap(); +// let devices = devices_async.get().unwrap(); + +// // println!("{:?}", devices.Size()); + +// for i in 0..devices.Size().unwrap() { +// let device = devices.GetAt(i).unwrap(); +// println!("Device Name: {:?}", device.Name().unwrap()); +// println!("Device Kind: {:?}", device.Kind().unwrap()); +// println!("Device ID: {:?}", device.Id().unwrap()); +// println!("-----------------") +// } + +// // let device_id = "PCI\\VEN_1022&DEV_790B"; + +// // let async_get_device = I2cDevice::FromIdAsync(&HSTRING::from(device_id), &connection_settings).unwrap(); +// // let device = async_get_device.get(); + +// // println!("{:?}", device); diff --git a/src/gigabyte_rgb_fusion_usb.rs b/src/gigabyte_rgb_fusion_usb.rs index c9667be..0ecd9a7 100644 --- a/src/gigabyte_rgb_fusion_usb.rs +++ b/src/gigabyte_rgb_fusion_usb.rs @@ -1,6 +1,6 @@ use std::{str, time::Duration}; -use crate::rgb::RGB; +use crate::rgb::Rgb; const VID: u16 = 0x048D; // Vendor ID: Gigabyte. const PID: u16 = 0x5711; // Product ID. @@ -23,8 +23,7 @@ impl Device { .device_list() .find(|d| d.vendor_id() == VID && d.product_id() == PID && d.usage() == 204) .unwrap() - .open_device(api) - .unwrap(); + .open_device(api)?; let device = Device { device: d }; @@ -136,7 +135,7 @@ cc62390039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab const NB_LEDS_PER_PACKET: usize = 19; - fn set_color_device(&self, color: &RGB, device: u8, nb_leds: usize) -> anyhow::Result<()> { + 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]; @@ -165,7 +164,7 @@ cc62390039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab Ok(()) } - fn set_color_motherboard(&self, color: &RGB) -> anyhow::Result<()> { + fn set_color_motherboard(&self, color: &Rgb) -> anyhow::Result<()> { { let mut buffer = [0u8; 64]; buffer[0] = 0xCC; @@ -194,13 +193,15 @@ cc62390039ab4543 ab4543ab4543ab45 43ab4543ab4543ab4543ab4543ab4543ab4543ab4543ab Ok(()) } - pub fn set_color(&self, color: &RGB) { + pub fn set_color(&self, color: &Rgb) -> anyhow::Result<()> { // Motherboard & GPU power cables. - self.set_color_device(color, 0x58, 19).unwrap(); + self.set_color_device(color, 0x58, 19)?; // Arctic freezer 3. - self.set_color_device(color, 0x62, 38).unwrap(); + self.set_color_device(color, 0x62, 48)?; - self.set_color_motherboard(color).unwrap(); + self.set_color_motherboard(color)?; + + Ok(()) } } diff --git a/src/lian_li_sl_infinity.rs b/src/lian_li_sl_infinity.rs index cd3e149..af0e640 100644 --- a/src/lian_li_sl_infinity.rs +++ b/src/lian_li_sl_infinity.rs @@ -1,85 +1,91 @@ -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 { - Self { - device: api.open(LIANLI_VID, LIANLI_UNI_HUB_SLINF_PID).unwrap(), - } - } - - 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); - } - } -} +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) -> anyhow::Result { + Ok(Self { + device: api.open(LIANLI_VID, LIANLI_UNI_HUB_SLINF_PID)?, + }) + } + + fn send_start_action(&self, channel_id: u8) -> anyhow::Result<()> { + 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)?; + // assert_eq!(n_write, BUFFER_SIZE); + + Ok(()) + } + + fn send_commit_data(&self, channel_id: u8) -> anyhow::Result<()> { + 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)?; + // assert_eq!(n_write, BUFFER_SIZE); + + Ok(()) + } + + pub fn set_color(&self, color: &Rgb) -> anyhow::Result<()> { + 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 { + 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)?; + // assert_eq!(n_write, buffer.len()); + + self.send_commit_data(channel_id)?; + } + + Ok(()) + } +} diff --git a/src/machine/jiji.rs b/src/machine/jiji.rs index 402d9a4..d4e7841 100644 --- a/src/machine/jiji.rs +++ b/src/machine/jiji.rs @@ -1,57 +1,60 @@ -use crate::{asus_aura_usb, corsair_vengeance, cpu_temperature, rgb}; - -use super::Machine; - -pub struct MachineJiji { - ram: Vec, - b650e_device: asus_aura_usb::Device, - // a770: a770::A770, - // gpu_devices: intel_arc::Devices, - gpus: Vec, -} - -impl MachineJiji { - pub fn new() -> anyhow::Result { - 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); -// } -// } -// } +use crate::{asus_aura_usb, corsair_vengeance, cpu_temperature, rgb}; + +use super::Machine; + +pub struct MachineJiji { + ram: Vec, + b650e_device: asus_aura_usb::Device, + // a770: a770::A770, + // gpu_devices: intel_arc::Devices, + gpus: Vec, +} + +impl MachineJiji { + pub fn new() -> anyhow::Result { + 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) -> anyhow::Result<()> { + for controller in &self.ram { + controller.set_color(color); + } + self.b650e_device.set_color(color)?; + Ok(()) + } + + fn set_color_2(&mut self, color: &rgb::Rgb) -> anyhow::Result<()> { + Ok(()) + } // 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 index ba4cc43..adf8205 100644 --- a/src/machine/lyss_metal.rs +++ b/src/machine/lyss_metal.rs @@ -1,115 +1,117 @@ -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, -} - -impl MachineLyssMetal { - pub fn new() -> anyhow::Result { - 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() - } -} +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, +} + +impl MachineLyssMetal { + pub fn new() -> anyhow::Result { + 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) -> anyhow::Result<()> { + self.crosshair_device.set_color(color)?; + self.corsair_lignting_pro.set_color(color)?; + // self.set_color_3080ti(&color); // TODO. + Ok(()) + } + + fn set_color_2(&mut self, color: &rgb::Rgb) -> anyhow::Result<()> { + self.lian_li_sl_infinity.set_color(color)?; + Ok(()) + } + + 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 index f96d213..f5ec827 100644 --- a/src/machine/lyss_metal2.rs +++ b/src/machine/lyss_metal2.rs @@ -1,114 +1,117 @@ -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, -} - -impl MachineLyssMetal2 { - pub fn new() -> anyhow::Result { - 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() - } -} +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, +} + +impl MachineLyssMetal2 { + pub fn new() -> anyhow::Result { + 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) -> anyhow::Result<()> { + self.corsair_lignting_pro.set_color(color)?; + self.fusion_device.set_color(color)?; + Ok(()) + // self.set_color_3080ti(&color); // TODO. + } + + fn set_color_2(&mut self, color: &rgb::Rgb) -> anyhow::Result<()> { + self.lian_li_sl_infinity.set_color(color)?; + Ok(()) + } + + fn get_gpu_tmp(&self) -> f32 { + match self.gpus[0].thermal_settings(None) { + Ok(thermal) => thermal[0].current_temperature.0 as f32, + Err(_) => 0., + } + } + + fn get_cpu_tmp(&self) -> f32 { + cpu_temperature::read() + } +} diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 0ed2ff5..f6cddfe 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,21 +1,22 @@ -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; -} +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) -> anyhow::Result<()> { + self.set_color_1(color)?; + self.set_color_2(color)?; + Ok(()) + } + fn set_color_1(&mut self, color: &rgb::Rgb) -> anyhow::Result<()>; + fn set_color_2(&mut self, color: &rgb::Rgb) -> anyhow::Result<()>; + fn get_gpu_tmp(&self) -> f32; + fn get_cpu_tmp(&self) -> f32; +} diff --git a/src/main.rs b/src/main.rs index ff87264..ed4eccb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,242 +1,321 @@ -#[macro_use] -extern crate windows_service; - -use std::{ - env, - ffi::OsString, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - thread::sleep, - time::{self, Duration}, -}; - -use anyhow::Result; -use log::{debug, error, info, trace, warn}; -use windows::Win32::Foundation::{ERROR_SERVICE_DOES_NOT_EXIST, WIN32_ERROR}; -use windows_service::{ - service::{ - ServiceAccess, ServiceControl, ServiceControlAccept, ServiceErrorControl, ServiceExitCode, - ServiceInfo, ServiceStartType, ServiceState, ServiceStatus, ServiceType, - }, - service_control_handler::{self, ServiceControlHandlerResult, ServiceStatusHandle}, - service_dispatcher, - service_manager::{ServiceManager, ServiceManagerAccess}, -}; - -define_windows_service!(ffi_service_main, service_main); - -mod wrapper_winring0 { - #![allow(warnings, unused)] - include!(concat!(env!("OUT_DIR"), "/ols_api.rs")); -} -mod intel_arc { - #![allow(warnings, unused)] - include!(concat!(env!("OUT_DIR"), "/intel_arc.rs")); -} -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; -mod winring0; -// mod common; -mod consts; -mod corsair_vengeance; -mod piix4_i2c; -mod rgb; -// mod roccat; Disabled. -mod cpu_temperature; -mod settings; -mod tests; -mod timer; - -// Important: when starting as a service, the directory where the log and config files -// are put is 'C:\Windows\System32\config\systemprofile\AppData\Roaming\Temp2RGB'. -fn main() -> Result<()> { - let is_debug = cfg!(debug_assertions); - - flexi_logger::Logger::try_with_str(if is_debug { "debug" } else { "info" })? - .log_to_file( - flexi_logger::FileSpec::default() - .directory(dirs::config_dir().unwrap().join(consts::SERVICE_NAME)) - .basename(consts::SERVICE_NAME), - ) - .duplicate_to_stdout(flexi_logger::Duplicate::All) - .format(if is_debug { - flexi_logger::default_format - } else { - flexi_logger::detailed_format - }) - .rotate( - flexi_logger::Criterion::Size(1024 * 1024), - flexi_logger::Naming::Timestamps, - flexi_logger::Cleanup::KeepLogFiles(10), - ) - .print_message() - .start()?; - - log_panics::init(); - - let args: Vec = env::args().collect(); - - info!("Temperature to RGB"); - - if args.contains(&"--no-service".to_string()) { - let completed: Arc = Arc::new(AtomicBool::new(false)); - main_loop::main_loop(completed.clone()); - } else if args.contains(&"--tests".to_string()) { - tests::tests(); - } else if args.contains(&"--install-service".to_string()) { - println!("Installing service..."); - install_service()?; - } else if args.contains(&"--uninstall-service".to_string()) { - println!("Uninstalling service..."); - uninstall_service()?; - } else { - service_dispatcher::start(consts::SERVICE_NAME, ffi_service_main)?; - } - - Ok(()) -} - -fn install_service() -> windows_service::Result<()> { - let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE; - let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; - - let service_binary_path = std::env::current_exe() - .unwrap() - .with_file_name("temp_2_rgb.exe"); - - println!("Installing service: {service_binary_path:?}"); - - let service_info = ServiceInfo { - name: OsString::from(consts::SERVICE_NAME), - display_name: OsString::from(consts::SERVICE_NAME), - service_type: ServiceType::OWN_PROCESS, - start_type: ServiceStartType::AutoStart, - error_control: ServiceErrorControl::Normal, - executable_path: service_binary_path, - launch_arguments: vec![], - dependencies: vec![], - account_name: None, // run as System - account_password: None, - }; - let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?; - service.set_description( - "A service to set the color of hardware according to the temperature of GPU and CPU", - )?; - Ok(()) -} - -fn uninstall_service() -> windows_service::Result<()> { - let manager_access = ServiceManagerAccess::CONNECT; - let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; - - let service_access = ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE; - let service = service_manager.open_service(consts::SERVICE_NAME, service_access)?; - - // The service will be marked for deletion as long as this function call succeeds. - // However, it will not be deleted from the database until it is stopped and all open handles to it are closed. - service.delete()?; - - // Our handle to it is not closed yet. So we can still query it. - if service.query_status()?.current_state != ServiceState::Stopped { - // If the service cannot be stopped, it will be deleted when the system restarts. - service.stop()?; - } - - // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope. - drop(service); - - // Win32 API does not give us a way to wait for service deletion. - // To check if the service is deleted from the database, we have to poll it ourselves. - let start = time::Instant::now(); - let timeout = Duration::from_secs(5); - while start.elapsed() < timeout { - if let Err(windows_service::Error::Winapi(e)) = - service_manager.open_service(consts::SERVICE_NAME, ServiceAccess::QUERY_STATUS) - { - let WIN32_ERROR(error_num) = ERROR_SERVICE_DOES_NOT_EXIST; - if e.raw_os_error() == Some(error_num as i32) { - println!("{} is deleted.", consts::SERVICE_NAME); - return Ok(()); - } - } - sleep(Duration::from_secs(1)); - } - println!("{} is marked for deletion.", consts::SERVICE_NAME); - - Ok(()) -} - -fn service_main(arguments: Vec) { - if let Err(error) = run_service(arguments) { - error!("{error}"); - } -} - -fn run_service(_arguments: Vec) -> Result<(), windows_service::Error> { - let completed: Arc = Arc::new(AtomicBool::new(false)); - - let completed_event_handler = Arc::clone(&completed); - - info!("Setup the event handler..."); - - let event_handler = move |control_event| -> ServiceControlHandlerResult { - match control_event { - ServiceControl::Stop => { - completed_event_handler.store(true, Ordering::Relaxed); - // Handle stop event and return control back to the system. - ServiceControlHandlerResult::NoError - } - ServiceControl::Shutdown => { - completed_event_handler.store(true, Ordering::Relaxed); - // Handle stop event and return control back to the system. - ServiceControlHandlerResult::NoError - } - // ServiceControl::Preshutdown => { - // completed_event_handler.store(true, Ordering::Relaxed); - // ServiceControlHandlerResult::NoError - // } - // ServiceControl::PowerEvent(param) => { - // ServiceControlHandlerResult::NotImplemented - // } - // All services must accept Interrogate even if it's a no-op. - ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, - _ => ServiceControlHandlerResult::NotImplemented, - } - }; - - // Register system service event handler - let status_handle = service_control_handler::register(consts::SERVICE_NAME, event_handler)?; - - status_handle.set_service_status(ServiceStatus { - service_type: ServiceType::OWN_PROCESS, - current_state: ServiceState::Running, - controls_accepted: ServiceControlAccept::STOP | ServiceControlAccept::SHUTDOWN, - exit_code: ServiceExitCode::Win32(0), - checkpoint: 0, - wait_hint: Duration::default(), - process_id: None, //Some(std::process::id()), - })?; - - main_loop::main_loop(completed.clone()); - - status_handle.set_service_status(ServiceStatus { - service_type: ServiceType::OWN_PROCESS, - current_state: ServiceState::Stopped, - controls_accepted: ServiceControlAccept::empty(), - exit_code: ServiceExitCode::Win32(0), - checkpoint: 0, - wait_hint: Duration::default(), - process_id: None, //Some(std::process::id()), - })?; - - info!("Main loop stopped: Temperature to RGB will now shut down"); - - Ok(()) -} +#[macro_use] +extern crate windows_service; + +use std::{ + ffi::OsString, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, + thread::sleep, + time::{self, Duration}, +}; + +use anyhow::Result; +use clap::Parser; +use log::{error, info}; +use windows::Win32::Foundation::{ERROR_SERVICE_DOES_NOT_EXIST, WIN32_ERROR}; +use windows_service::{ + service::{ + ServiceAccess, ServiceControl, ServiceControlAccept, ServiceErrorControl, ServiceExitCode, + ServiceInfo, ServiceStartType, ServiceState, ServiceStatus, ServiceType, + }, + service_control_handler::{self, ServiceControlHandlerResult}, + service_dispatcher, + service_manager::{ServiceManager, ServiceManagerAccess}, +}; + +define_windows_service!(ffi_service_main, service_main); + +mod wrapper_winring0 { + #![allow(warnings, unused)] + include!(concat!(env!("OUT_DIR"), "/ols_api.rs")); +} +// mod intel_arc { +// #![allow(warnings, unused)] +// include!(concat!(env!("OUT_DIR"), "/intel_arc.rs")); +// } +mod a770; +mod asus_aura_usb; +mod consts; +mod corsair_lighting_pro; +mod corsair_vengeance; +mod gigabyte_rgb_fusion_usb; +mod lian_li_sl_infinity; +mod machine; +mod main_loop; +mod piix4_i2c; +mod rgb; +mod winring0; +// mod roccat; Disabled. +mod cpu_temperature; +mod settings; +mod tests; +mod timer; + +#[derive(Parser, Debug)] +#[command( + author = "Greg Burri", + version = "1.0", + about = "Set RGB according to CPU and GPU temperaturess" +)] +struct Args { + /// Launch without service. + #[arg(group = "main", long)] + no_service: bool, + + /// Run tests. + #[arg(group = "main", long)] + tests: bool, + + /// Install driver winring0. + #[arg(group = "main", long)] + install_winring0: bool, + + /// Install the service. + #[arg(group = "main", long)] + install_service: bool, + + /// Uninstall the service. + #[arg(group = "main", long)] + uninstall_service: bool, +} + +// Important: when starting as a service, the directory where the log and config files +// are put is 'C:\Windows\System32\config\systemprofile\AppData\Roaming\Temp2RGB'. +fn main() -> Result<()> { + let is_debug = cfg!(debug_assertions); + + flexi_logger::Logger::try_with_str(if is_debug { "debug" } else { "info" })? + .log_to_file( + flexi_logger::FileSpec::default() + .directory(dirs::config_dir().unwrap().join(consts::SERVICE_NAME)) + .basename(consts::SERVICE_NAME), + ) + .duplicate_to_stdout(flexi_logger::Duplicate::All) + .format(if is_debug { + flexi_logger::default_format + } else { + flexi_logger::detailed_format + }) + .rotate( + flexi_logger::Criterion::Size(1024 * 1024), + flexi_logger::Naming::Timestamps, + flexi_logger::Cleanup::KeepLogFiles(10), + ) + .print_message() + .start()?; + + log_panics::init(); + + let args = Args::parse(); + + info!("Temperature to RGB"); + + if args.no_service { + let completed: Arc = Arc::new(AtomicBool::new(false)); + main_loop::main_loop(completed.clone()); + } else if args.tests { + tests::tests(); + } else if args.install_winring0 { + println!("Installing winring0 service..."); + install_winring0()?; + } else if args.install_service { + println!("Installing service..."); + install_service()?; + } else if args.uninstall_service { + println!("Uninstalling service..."); + uninstall_service()?; + } else { + service_dispatcher::start(consts::SERVICE_NAME, ffi_service_main)?; + } + + Ok(()) +} + +fn install_winring0() -> windows_service::Result<()> { + let system_dir = unsafe { + let mut system_dir = [0u8; windows::Win32::Foundation::MAX_PATH as usize]; + let l = + windows::Win32::System::SystemInformation::GetSystemDirectoryA(Some(&mut system_dir)) + as usize; + assert_ne!(l, 0); + String::from_utf8(system_dir[0..l].into()).unwrap() + }; + // TODO: to const. + let winring0_filename = "WinRing0x64.sys"; + let driver_name = "WinRing0x64"; + + let winring0_path = std::env::current_exe() + .unwrap() + .with_file_name(winring0_filename); + + let destination = std::path::Path::new(&system_dir) + .join("drivers") + .join(winring0_filename); + + std::fs::copy(winring0_path, &destination).unwrap(); + + let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE; + let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; + + // println!("Installing service: {service_binary_path:?}"); + + let service_info = ServiceInfo { + name: OsString::from(driver_name), + display_name: OsString::from(driver_name), + service_type: ServiceType::KERNEL_DRIVER, + start_type: ServiceStartType::AutoStart, + error_control: ServiceErrorControl::Normal, + executable_path: destination, + launch_arguments: vec![], + dependencies: vec![], + account_name: None, // run as System + account_password: None, + }; + + let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?; + service.set_description("Winring0")?; + + Ok(()) +} + +fn install_service() -> windows_service::Result<()> { + let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE; + let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; + + let service_binary_path = std::env::current_exe() + .unwrap() + .with_file_name("temp_2_rgb.exe"); + + println!("Installing service: {service_binary_path:?}"); + + let service_info = ServiceInfo { + name: OsString::from(consts::SERVICE_NAME), + display_name: OsString::from(consts::SERVICE_NAME), + service_type: ServiceType::OWN_PROCESS, + start_type: ServiceStartType::AutoStart, + error_control: ServiceErrorControl::Normal, + executable_path: service_binary_path, + launch_arguments: vec![], + dependencies: vec![], + account_name: None, // run as System + account_password: None, + }; + + let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?; + service.set_description( + "A service to set the color of hardware according to the temperature of GPU and CPU", + )?; + + Ok(()) +} + +fn uninstall_service() -> windows_service::Result<()> { + let manager_access = ServiceManagerAccess::CONNECT; + let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; + + let service_access = ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE; + let service = service_manager.open_service(consts::SERVICE_NAME, service_access)?; + + // The service will be marked for deletion as long as this function call succeeds. + // However, it will not be deleted from the database until it is stopped and all open handles to it are closed. + service.delete()?; + + // Our handle to it is not closed yet. So we can still query it. + if service.query_status()?.current_state != ServiceState::Stopped { + // If the service cannot be stopped, it will be deleted when the system restarts. + service.stop()?; + } + + // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope. + drop(service); + + // Win32 API does not give us a way to wait for service deletion. + // To check if the service is deleted from the database, we have to poll it ourselves. + let start = time::Instant::now(); + let timeout = Duration::from_secs(5); + while start.elapsed() < timeout { + if let Err(windows_service::Error::Winapi(e)) = + service_manager.open_service(consts::SERVICE_NAME, ServiceAccess::QUERY_STATUS) + { + let WIN32_ERROR(error_num) = ERROR_SERVICE_DOES_NOT_EXIST; + if e.raw_os_error() == Some(error_num as i32) { + println!("{} is deleted.", consts::SERVICE_NAME); + return Ok(()); + } + } + sleep(Duration::from_secs(1)); + } + println!("{} is marked for deletion.", consts::SERVICE_NAME); + + Ok(()) +} + +fn service_main(arguments: Vec) { + if let Err(error) = run_service(arguments) { + error!("{error}"); + } +} + +fn run_service(_arguments: Vec) -> Result<(), windows_service::Error> { + let completed: Arc = Arc::new(AtomicBool::new(false)); + + let completed_event_handler = Arc::clone(&completed); + + info!("Setup the event handler..."); + + let event_handler = move |control_event| -> ServiceControlHandlerResult { + match control_event { + ServiceControl::Stop => { + completed_event_handler.store(true, Ordering::Relaxed); + // Handle stop event and return control back to the system. + ServiceControlHandlerResult::NoError + } + ServiceControl::Shutdown => { + completed_event_handler.store(true, Ordering::Relaxed); + // Handle stop event and return control back to the system. + ServiceControlHandlerResult::NoError + } + // ServiceControl::Preshutdown => { + // completed_event_handler.store(true, Ordering::Relaxed); + // ServiceControlHandlerResult::NoError + // } + // ServiceControl::PowerEvent(param) => { + // ServiceControlHandlerResult::NotImplemented + // } + // All services must accept Interrogate even if it's a no-op. + ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, + _ => ServiceControlHandlerResult::NotImplemented, + } + }; + + // Register system service event handler + let status_handle = service_control_handler::register(consts::SERVICE_NAME, event_handler)?; + + status_handle.set_service_status(ServiceStatus { + service_type: ServiceType::OWN_PROCESS, + current_state: ServiceState::Running, + controls_accepted: ServiceControlAccept::STOP | ServiceControlAccept::SHUTDOWN, + exit_code: ServiceExitCode::Win32(0), + checkpoint: 0, + wait_hint: Duration::default(), + process_id: None, //Some(std::process::id()), + })?; + + main_loop::main_loop(completed.clone()); + + status_handle.set_service_status(ServiceStatus { + service_type: ServiceType::OWN_PROCESS, + current_state: ServiceState::Stopped, + controls_accepted: ServiceControlAccept::empty(), + exit_code: ServiceExitCode::Win32(0), + checkpoint: 0, + wait_hint: Duration::default(), + process_id: None, //Some(std::process::id()), + })?; + + info!("Main loop stopped: Temperature to RGB will now shut down"); + + Ok(()) +} diff --git a/src/main_loop.rs b/src/main_loop.rs index 1d523b3..a8b7618 100644 --- a/src/main_loop.rs +++ b/src/main_loop.rs @@ -1,11 +1,13 @@ use std::{ sync::{ - atomic::{AtomicBool, Ordering}, Arc, + atomic::{AtomicBool, Ordering}, }, time::{self, Duration}, }; +use log::warn; + use crate::{consts, machine, rgb, settings, timer, winring0}; pub fn main_loop(completed: Arc) { @@ -98,12 +100,15 @@ pub fn main_loop(completed: Arc) { if tick % (consts::FREQ_TEMP_POLLING / consts::FREQ_REFRESHING_RGB) as i64 == 0 { println!("Update RGB: {color_1:?}/{color_2:?}, temp: {mean_temp}"); - machine.set_color_1(&color_1); - if color_2.is_some() { - machine.set_color_2(&color_2.unwrap()); - } else { - machine.set_color_2(&color_1); - } + if let Err(error) = machine.set_color_1(&color_1) { + warn!("Unable to set color 1: {}", error); + }; + + if let Err(error) = + machine.set_color_2(&if let Some(c) = color_2 { c } else { color_1 }) + { + warn!("Unable to set color 2: {}", error); + }; } let elapsed = time::Instant::now() - time_beginning_loop; diff --git a/src/piix4_i2c.rs b/src/piix4_i2c.rs index 7397459..8138e06 100644 --- a/src/piix4_i2c.rs +++ b/src/piix4_i2c.rs @@ -1,274 +1,273 @@ -// Partial implementation for PCI IDE ISA Xcelerator. -// https://www.kernel.org/doc/html/latest/i2c/summary.html - -use std::time::Duration; - -use crate::{timer, wrapper_winring0}; - -pub const I2C_BLOCK_MAX: usize = 32; - -#[repr(u16)] -#[derive(Clone, Copy, Debug)] -enum TransactionType { - I2cSmbusQuick = 0, - I2cSmbusByte = 1, - I2cSmbusByteData = 2, - I2cSmbusWordData = 3, - I2cSmbusProcCall = 4, - I2cSmbusBlockData = 5, - I2cSmbusI2cBlockBroken = 6, - I2cSmbusBlockProcCall = 7, /* SMBus 2.0 */ - I2cSmbusI2cBlockData = 8, -} - -#[repr(u16)] -#[derive(Clone, Copy, Debug)] -enum Piix4TransactionType { - Piix4Quick = 0x00, - Piix4Byte = 0x04, - Piix4ByteData = 0x08, - Piix4WordData = 0x0C, - Piix4BlockData = 0x14, -} - -// PIIX4 SMBus address offsets - -#[repr(u16)] -#[derive(Clone, Copy, Debug)] -enum SMBusAddressOffsets { - Smbhststs = 0, - Smbhslvsts = 1, - Smbhstcnt = 2, - Smbhstcmd = 3, - Smbhstadd = 4, - Smbhstdat0 = 5, - Smbhstdat1 = 6, - Smbblkdat = 7, - Smbslvcnt = 8, - Smbshdwcmd = 9, - Smbslvevt = 0xA, - Smbslvdat = 0xC, -} - -#[repr(u8)] -#[derive(Clone, Copy)] -enum AccessType { - Write = 0, - Read = 1, -} - -pub struct I2c { - base_address: u16, -} - -enum XferResult { - Ok, - BlockData(Vec), -} - -#[derive(Debug)] -enum Error { - Busy, - Timeout, - IO, - Data, -} - -impl I2c { - pub fn new(base_address: u16) -> Self { - I2c { base_address } - } - - pub fn write_block_data(&self, addr: u8, command: u8, data: &[u8]) { - let l = data.len(); - assert!( - l <= I2C_BLOCK_MAX, - "Data length must not exceed {}", - I2C_BLOCK_MAX - ); - let mut data_block = [0u8; I2C_BLOCK_MAX + 2]; - data_block[0] = l as u8; - data_block[1..l + 1].copy_from_slice(data); - - unsafe { - if let Err(error) = self.i2c_smbus_xfer( - addr, - AccessType::Write, - command, - TransactionType::I2cSmbusBlockData, - Some(&data_block), - ) { - println!("Error when writing block (I2c): {error:?}"); - } - } - } - - pub fn i2c_smbus_write_quick(&self, addr: u8, value: u8) { - unsafe { - self.i2c_smbus_xfer( - addr, - AccessType::Write, - value, - TransactionType::I2cSmbusQuick, - None, - ) - .unwrap(); - } - } - - unsafe fn i2c_smbus_xfer( - &self, - addr: u8, - access_type: AccessType, - command: u8, - transaction_type: TransactionType, // Called 'size' in 'i2c_smbus\i2c_smbus_piix4.cpp'. - data: Option<&[u8]>, - ) -> Result { - let piix4_transaction_type = match transaction_type { - TransactionType::I2cSmbusQuick => { - self.write_io_port_byte( - SMBusAddressOffsets::Smbhstadd, - (addr << 1) | access_type as u8, - ); - Piix4TransactionType::Piix4Quick - } - TransactionType::I2cSmbusByte => todo!(), - TransactionType::I2cSmbusByteData => todo!(), // Here 'data' should be a byte, maybe using a enum?. - TransactionType::I2cSmbusWordData => todo!(), // Here 'data' should be a u16, maybe using a enum?. - TransactionType::I2cSmbusBlockData => { - self.write_io_port_byte( - SMBusAddressOffsets::Smbhstadd, - (addr << 1) | access_type as u8, - ); - self.write_io_port_byte(SMBusAddressOffsets::Smbhstcmd, command); - if let AccessType::Write = access_type { - let len = data.unwrap()[0]; - if len == 0 || len > I2C_BLOCK_MAX as u8 { - panic!("Invalid len value: {}", len); - } - - self.write_io_port_byte(SMBusAddressOffsets::Smbhstdat0, len); - self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); // TODO: do something of the result!? - for i in 1..=len { - self.write_io_port_byte( - SMBusAddressOffsets::Smbblkdat, - data.unwrap()[i as usize], - ); - } - } - Piix4TransactionType::Piix4BlockData - } - _ => panic!("Not supported: {:?}", transaction_type), - }; - - self.write_io_port_byte( - SMBusAddressOffsets::Smbhstcnt, - piix4_transaction_type as u8 & 0x1C, - ); - - self.piix4_transaction()?; - - // if let (AccessType::Write, Piix4TransactionType::Piix4Quick) = (access_type, piix4_transaction_type) { - // return Ok(()) - // } - - match piix4_transaction_type { - Piix4TransactionType::Piix4Quick => Ok(XferResult::Ok), - Piix4TransactionType::Piix4Byte => todo!(), - Piix4TransactionType::Piix4ByteData => todo!(), - Piix4TransactionType::Piix4WordData => todo!(), - Piix4TransactionType::Piix4BlockData => { - let l = self.read_io_port_byte(SMBusAddressOffsets::Smbhstdat0) as usize; - if l == 0 || l > I2C_BLOCK_MAX { - return Err(Error::Data); - } - self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); - let mut data = vec![0; l + 1]; - for i in 1..=l { - data[i] = self.read_io_port_byte(SMBusAddressOffsets::Smbblkdat); - } - Ok(XferResult::BlockData(data)) - } - } - } - - unsafe fn piix4_transaction(&self) -> Result<(), Error> { - let timer = timer::Sleep::new(); - - // Make sure the SMBus is ready to start transmitting. - let mut res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); - if res != 0x00 { - self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res); - res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); - if res != 0x00 { - return Err(Error::Busy); - } - } - - // Start the transaction by setting bit 6. - res = self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); - self.write_io_port_byte(SMBusAddressOffsets::Smbhstcnt, res | 0x40); - - // let duration: i64 = -2_500; // 250 us. - let mut n = 0; - loop { - timer.wait(Duration::from_micros(250)); - - res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); - // println!("Res: {}", res); - if res > 0x01 { - break; - } - - if n >= 100 { - return Err(Error::Timeout); - } - n += 1; - } - // println!("-----"); - - if res & 0x10 != 0x00 || res & 0x08 != 0x0 || res & 0x04 != 0x0 { - return Err(Error::IO); - } - - res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); - if res != 0x00 { - self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res); - } - - Ok(()) - } - - unsafe fn write_io_port_byte(&self, op: SMBusAddressOffsets, value: u8) { - wrapper_winring0::WriteIoPortByte(self.base_address + op as u16, value); - } - - unsafe fn read_io_port_byte(&self, op: SMBusAddressOffsets) -> u8 { - wrapper_winring0::ReadIoPortByte(self.base_address + op as u16) - } -} - -/* -type ADL_MAIN_MALLOC_CALLBACK = unsafe fn(c_int) -> *mut c_void; -type ADL_CONTEXT_HANDLE = *mut c_void; - -type ADL2_MAIN_CONTROL_CREATE = unsafe extern "C" fn(ADL_MAIN_MALLOC_CALLBACK, c_int, *mut ADL_CONTEXT_HANDLE) -> c_int; -type ADL2_MAIN_CONTROL_DESTROY = unsafe extern "C" fn(ADL_CONTEXT_HANDLE) -> c_int; -type ADL2_ADAPTER_NUMBEROFADAPTERS_GET = unsafe extern "C" fn(ADL_CONTEXT_HANDLE, *mut c_int) -> c_int; - -pub fn test() { - unsafe { - let hDLL = LoadLibraryW(w!("atiadlxx.dll")).unwrap(); - println!("{:?}", hDLL); - - let ADL2_Main_Control_Create: ADL2_MAIN_CONTROL_CREATE = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Create")).unwrap()); - let ADL2_Main_Control_Destroy: ADL2_MAIN_CONTROL_DESTROY = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Destroy")).unwrap()); - let ADL2_Adapter_NumberOfAdapters_Get: ADL2_ADAPTER_NUMBEROFADAPTERS_GET = transmute(&GetProcAddress(hDLL, s!("ADL2_Adapter_NumberOfAdapters_Get")).unwrap()); - - - let m: *mut c_void = libc::malloc(4); - - - } -} -*/ +// Partial implementation for PCI IDE ISA Xcelerator. +// https://www.kernel.org/doc/html/latest/i2c/summary.html + +use std::time::Duration; + +use crate::{timer, wrapper_winring0}; + +pub const I2C_BLOCK_MAX: usize = 32; + +#[repr(u16)] +#[derive(Clone, Copy, Debug)] +enum TransactionType { + I2cSmbusQuick = 0, + I2cSmbusByte = 1, + I2cSmbusByteData = 2, + I2cSmbusWordData = 3, + I2cSmbusProcCall = 4, + I2cSmbusBlockData = 5, + I2cSmbusI2cBlockBroken = 6, + I2cSmbusBlockProcCall = 7, /* SMBus 2.0 */ + I2cSmbusI2cBlockData = 8, +} + +#[repr(u16)] +#[derive(Clone, Copy, Debug)] +enum Piix4TransactionType { + Piix4Quick = 0x00, + Piix4Byte = 0x04, + Piix4ByteData = 0x08, + Piix4WordData = 0x0C, + Piix4BlockData = 0x14, +} + +// PIIX4 SMBus address offsets + +#[repr(u16)] +#[derive(Clone, Copy, Debug)] +enum SMBusAddressOffsets { + Smbhststs = 0, + Smbhslvsts = 1, + Smbhstcnt = 2, + Smbhstcmd = 3, + Smbhstadd = 4, + Smbhstdat0 = 5, + Smbhstdat1 = 6, + Smbblkdat = 7, + Smbslvcnt = 8, + Smbshdwcmd = 9, + Smbslvevt = 0xA, + Smbslvdat = 0xC, +} + +#[repr(u8)] +#[derive(Clone, Copy)] +enum AccessType { + Write = 0, + Read = 1, +} + +pub struct I2c { + base_address: u16, +} + +enum XferResult { + Ok, + BlockData(Vec), +} + +#[derive(Debug)] +enum Error { + Busy, + Timeout, + IO, + Data, +} + +impl I2c { + pub fn new(base_address: u16) -> Self { + I2c { base_address } + } + + pub fn write_block_data(&self, addr: u8, command: u8, data: &[u8]) { + let l = data.len(); + assert!( + l <= I2C_BLOCK_MAX, + "Data length must not exceed {}", + I2C_BLOCK_MAX + ); + let mut data_block = [0u8; I2C_BLOCK_MAX + 2]; + data_block[0] = l as u8; + data_block[1..l + 1].copy_from_slice(data); + + unsafe { + if let Err(error) = self.i2c_smbus_xfer( + addr, + AccessType::Write, + command, + TransactionType::I2cSmbusBlockData, + Some(&data_block), + ) { + println!("Error when writing block (I2c): {error:?}"); + } + } + } + + pub fn i2c_smbus_write_quick(&self, addr: u8, value: u8) { + unsafe { + let _ = self.i2c_smbus_xfer( + addr, + AccessType::Write, + value, + TransactionType::I2cSmbusQuick, + None, + ); + } + } + + unsafe fn i2c_smbus_xfer( + &self, + addr: u8, + access_type: AccessType, + command: u8, + transaction_type: TransactionType, // Called 'size' in 'i2c_smbus\i2c_smbus_piix4.cpp'. + data: Option<&[u8]>, + ) -> Result { + let piix4_transaction_type = match transaction_type { + TransactionType::I2cSmbusQuick => { + self.write_io_port_byte( + SMBusAddressOffsets::Smbhstadd, + (addr << 1) | access_type as u8, + ); + Piix4TransactionType::Piix4Quick + } + TransactionType::I2cSmbusByte => todo!(), + TransactionType::I2cSmbusByteData => todo!(), // Here 'data' should be a byte, maybe using a enum?. + TransactionType::I2cSmbusWordData => todo!(), // Here 'data' should be a u16, maybe using a enum?. + TransactionType::I2cSmbusBlockData => { + self.write_io_port_byte( + SMBusAddressOffsets::Smbhstadd, + (addr << 1) | access_type as u8, + ); + self.write_io_port_byte(SMBusAddressOffsets::Smbhstcmd, command); + if let AccessType::Write = access_type { + let len = data.unwrap()[0]; + if len == 0 || len > I2C_BLOCK_MAX as u8 { + panic!("Invalid len value: {}", len); + } + + self.write_io_port_byte(SMBusAddressOffsets::Smbhstdat0, len); + self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); // TODO: do something of the result!? + for i in 1..=len { + self.write_io_port_byte( + SMBusAddressOffsets::Smbblkdat, + data.unwrap()[i as usize], + ); + } + } + Piix4TransactionType::Piix4BlockData + } + _ => panic!("Not supported: {:?}", transaction_type), + }; + + self.write_io_port_byte( + SMBusAddressOffsets::Smbhstcnt, + piix4_transaction_type as u8 & 0x1C, + ); + + self.piix4_transaction()?; + + // if let (AccessType::Write, Piix4TransactionType::Piix4Quick) = (access_type, piix4_transaction_type) { + // return Ok(()) + // } + + match piix4_transaction_type { + Piix4TransactionType::Piix4Quick => Ok(XferResult::Ok), + Piix4TransactionType::Piix4Byte => todo!(), + Piix4TransactionType::Piix4ByteData => todo!(), + Piix4TransactionType::Piix4WordData => todo!(), + Piix4TransactionType::Piix4BlockData => { + let l = self.read_io_port_byte(SMBusAddressOffsets::Smbhstdat0) as usize; + if l == 0 || l > I2C_BLOCK_MAX { + return Err(Error::Data); + } + self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); + let mut data = vec![0; l + 1]; + for i in 1..=l { + data[i] = self.read_io_port_byte(SMBusAddressOffsets::Smbblkdat); + } + Ok(XferResult::BlockData(data)) + } + } + } + + unsafe fn piix4_transaction(&self) -> Result<(), Error> { + let timer = timer::Sleep::new(); + + // Make sure the SMBus is ready to start transmitting. + let mut res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); + if res != 0x00 { + self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res); + res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); + if res != 0x00 { + return Err(Error::Busy); + } + } + + // Start the transaction by setting bit 6. + res = self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); + self.write_io_port_byte(SMBusAddressOffsets::Smbhstcnt, res | 0x40); + + // let duration: i64 = -2_500; // 250 us. + let mut n = 0; + loop { + timer.wait(Duration::from_micros(250)); + + res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); + // println!("Res: {}", res); + if res > 0x01 { + break; + } + + if n >= 100 { + return Err(Error::Timeout); + } + n += 1; + } + // println!("-----"); + + if res & 0x10 != 0x00 || res & 0x08 != 0x0 || res & 0x04 != 0x0 { + return Err(Error::IO); + } + + res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs); + if res != 0x00 { + self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res); + } + + Ok(()) + } + + unsafe fn write_io_port_byte(&self, op: SMBusAddressOffsets, value: u8) { + wrapper_winring0::WriteIoPortByte(self.base_address + op as u16, value); + } + + unsafe fn read_io_port_byte(&self, op: SMBusAddressOffsets) -> u8 { + wrapper_winring0::ReadIoPortByte(self.base_address + op as u16) + } +} + +/* +type ADL_MAIN_MALLOC_CALLBACK = unsafe fn(c_int) -> *mut c_void; +type ADL_CONTEXT_HANDLE = *mut c_void; + +type ADL2_MAIN_CONTROL_CREATE = unsafe extern "C" fn(ADL_MAIN_MALLOC_CALLBACK, c_int, *mut ADL_CONTEXT_HANDLE) -> c_int; +type ADL2_MAIN_CONTROL_DESTROY = unsafe extern "C" fn(ADL_CONTEXT_HANDLE) -> c_int; +type ADL2_ADAPTER_NUMBEROFADAPTERS_GET = unsafe extern "C" fn(ADL_CONTEXT_HANDLE, *mut c_int) -> c_int; + +pub fn test() { + unsafe { + let hDLL = LoadLibraryW(w!("atiadlxx.dll")).unwrap(); + println!("{:?}", hDLL); + + let ADL2_Main_Control_Create: ADL2_MAIN_CONTROL_CREATE = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Create")).unwrap()); + let ADL2_Main_Control_Destroy: ADL2_MAIN_CONTROL_DESTROY = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Destroy")).unwrap()); + let ADL2_Adapter_NumberOfAdapters_Get: ADL2_ADAPTER_NUMBEROFADAPTERS_GET = transmute(&GetProcAddress(hDLL, s!("ADL2_Adapter_NumberOfAdapters_Get")).unwrap()); + + + let m: *mut c_void = libc::malloc(4); + + + } +} +*/ diff --git a/src/rgb.rs b/src/rgb.rs index a6217c7..9152459 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -1,17 +1,17 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)] -pub struct RGB { - pub red: u8, - pub green: u8, - pub blue: u8, -} - -// 'value' is between 0 and 1. -pub fn linear_interpolation(color1: RGB, color2: RGB, value: f32) -> RGB { - let red = (color1.red as f32 + (color2.red as f32 - color1.red as f32) * value) as u8; - let green = (color1.green as f32 + (color2.green as f32 - color1.green as f32) * value) as u8; - let blue = (color1.blue as f32 + (color2.blue as f32 - color1.blue as f32) * value) as u8; - - RGB { red, green, blue } -} +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)] +pub struct Rgb { + pub red: u8, + pub green: u8, + pub blue: u8, +} + +// 'value' is between 0 and 1. +pub fn linear_interpolation(color1: Rgb, color2: Rgb, value: f32) -> Rgb { + let red = (color1.red as f32 + (color2.red as f32 - color1.red as f32) * value) as u8; + let green = (color1.green as f32 + (color2.green as f32 - color1.green as f32) * value) as u8; + let blue = (color1.blue as f32 + (color2.blue as f32 - color1.blue as f32) * value) as u8; + + Rgb { red, green, blue } +} diff --git a/src/settings.rs b/src/settings.rs index 43ae03d..54c880b 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,64 +1,64 @@ -use std::fs::File; - -use ron::{ - de::from_reader, - ser::{to_writer_pretty, PrettyConfig}, -}; -use serde::{Deserialize, Serialize}; - -use crate::rgb::RGB; - -#[derive(Debug, Deserialize, Serialize)] -pub enum MachineName { - Jiji, - LyssMetal, - LyssMetal2, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct Settings { - pub machine_name: MachineName, - pub cold_color_1: RGB, - pub hot_color_1: RGB, - pub cold_color_2: Option, - pub hot_color_2: Option, - // Average temperature between CPU and GPU. - pub cold_temperature: f32, - pub hot_temperature: f32, -} - -type Result = std::result::Result>; - -impl Settings { - fn default() -> Self { - Settings { - machine_name: MachineName::Jiji, - cold_color_1: RGB { - red: 0, - green: 255, - blue: 40, - }, - hot_color_1: RGB { - red: 255, - green: 0, - blue: 0, - }, - cold_color_2: None, - hot_color_2: None, - cold_temperature: 55., - hot_temperature: 75., - } - } - - pub fn read(file_path: &str) -> Result { - match File::open(file_path) { - Ok(file) => from_reader(file).map_err(|e| e.into()), - Err(_) => { - let file = File::create(file_path)?; - let default_config = Settings::default(); - to_writer_pretty(file, &default_config, PrettyConfig::new())?; - Ok(default_config) - } - } - } -} +use std::fs::File; + +use ron::{ + de::from_reader, + ser::{PrettyConfig, to_writer_pretty}, +}; +use serde::{Deserialize, Serialize}; + +use crate::rgb::Rgb; + +#[derive(Debug, Deserialize, Serialize)] +pub enum MachineName { + Jiji, + LyssMetal, + LyssMetal2, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Settings { + pub machine_name: MachineName, + pub cold_color_1: Rgb, + pub hot_color_1: Rgb, + pub cold_color_2: Option, + pub hot_color_2: Option, + // Average temperature between CPU and GPU. + pub cold_temperature: f32, + pub hot_temperature: f32, +} + +type Result = std::result::Result>; + +impl Settings { + fn default() -> Self { + Settings { + machine_name: MachineName::Jiji, + cold_color_1: Rgb { + red: 0, + green: 255, + blue: 40, + }, + hot_color_1: Rgb { + red: 255, + green: 0, + blue: 0, + }, + cold_color_2: None, + hot_color_2: None, + cold_temperature: 55., + hot_temperature: 75., + } + } + + pub fn read(file_path: &str) -> Result { + match File::open(file_path) { + Ok(file) => from_reader(file).map_err(|e| e.into()), + Err(_) => { + let file = File::create(file_path)?; + let default_config = Settings::default(); + to_writer_pretty(file, &default_config, PrettyConfig::new())?; + Ok(default_config) + } + } + } +} diff --git a/src/tests.rs b/src/tests.rs index c7ea81c..c0d0ad4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,221 +1,230 @@ -use std::collections::HashMap; - -use wmi::{COMLibrary, Variant, WMIConnection}; - -use crate::{ - a770, asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature, - gigabyte_rgb_fusion_usb, lian_li_sl_infinity, machine, rgb::RGB, winring0, wrapper_winring0, -}; - -pub fn tests() { - println!("Running some tests..."); - - winring0::init(); - - // test_asus_aura_usb(asus_aura_usb::Motherboard::Asus650e); - // test_corsair_lighting_pro(); - // test_lianli_sl_infinity(); - // list_usb_devices(); - // test_roccat(); - // test_wmi(); - // test_corsair(); - // test_a770(); - // test_3080ti(); - // test_read_temperature_cpu(); - // test_read_temperature_a770(); - // test_read_temperature_3080(); - test_gigabyte_fusion(); - - winring0::deinit(); - - println!("Press any key to continue..."); - 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(); - - //let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'").unwrap(); - //let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE 'Intel(R) NF I2C Host Controller'").unwrap(); - let results: Vec> = wmi_con - .raw_query("SELECT * FROM Win32_PnPSignedDriver") - .unwrap(); - //let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_PnPAllocatedResource").unwrap(); - - for os in results { - println!("-------------------"); - println!("{:#?}", os); - } -} - -fn list_usb_devices() { - let api = hidapi::HidApi::new().unwrap(); - for device in api.device_list() { - println!("{:?}", device); - println!("name: {}", device.product_string().unwrap()); - println!("interface number: {}", device.interface_number()); - println!("page: {}", device.usage_page()); - println!("usage: {}", device.usage()); - println!("----"); - } -} - -// fn test_roccat() { -// let api = hidapi::HidApi::new().unwrap(); -// let roccat_device = roccat::get_device(&api); - -// let manufacturer = roccat_device.get_manufacturer_string().unwrap(); -// dbg!(manufacturer); - -// let product = roccat_device.get_product_string().unwrap(); -// dbg!(product); - -// let serial = roccat_device.get_serial_number_string().unwrap(); -// dbg!(serial); - -// roccat::init(&roccat_device); -// roccat::set_color( -// &roccat_device, -// &RGB { -// red: 0, -// green: 255, -// blue: 40, -// }, -// ); -// } - -fn test_asus_aura_usb(motherboard: asus_aura_usb::Motherboard) { - let api = hidapi::HidApi::new().unwrap(); - - let device = asus_aura_usb::Device::new(&api, motherboard).unwrap(); - - println!("Firmware: {}", device.get_firmware_string().unwrap()); - - let configuration = device.get_configuration_table().unwrap(); - println!("Configuration:"); - for i in 0..60 { - print!("{:02X} ", configuration[i]); - if (i + 1) % 6 == 0 { - println!(""); - } - } - println!("Number of addressable header: {}", configuration[0x02]); - println!("Number of leds: {}", configuration[0x1B]); - println!("Number of RGB headers: {}", configuration[0x1D]); - - device - .set_color(&RGB { - red: 0, - green: 0, - blue: 255, - }) - .unwrap(); - - device.save_current_color().unwrap(); -} - -fn test_corsair_lighting_pro() { - let api = hidapi::HidApi::new().unwrap(); - let device = corsair_lighting_pro::Device::new( - &api, - &RGB { - red: 0, - green: 255, - blue: 0, - }, - ); - - for i in 0..=255 { - if i % 10 == 0 || i == 255 || i == 0 { - device.set_color(&RGB { - red: i as u8, - green: 255u8 - i as u8, - blue: 0, - }); - std::thread::sleep(std::time::Duration::from_millis(200)); - } - } -} - -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), - corsair_vengeance::Controller::new(0x1B), - ]; - - for controller in corsair_controllers { - controller.set_color(&RGB { - red: 0, - green: 0, - blue: 255, - }); - } -} - -fn test_a770() { - // a770::set_rgb(255, 0, 0); - let mut a770 = a770::A770::new().unwrap(); - a770.set_color(255, 0, 0).unwrap(); -} - -fn test_3080ti() { - let machine: &mut dyn machine::Machine = - &mut machine::lyss_metal::MachineLyssMetal::new().unwrap(); - - machine.set_color(&RGB { - red: 255, - green: 0, - blue: 0, - }); -} - -const F17H_M01H_THM_TCON_CUR_TMP: u32 = 0x00059800; -const F17H_TEMP_OFFSET_FLAG: u32 = 0x80000; -const FAMILY_17H_PCI_CONTROL_REGISTER: u32 = 0x60; - -fn test_read_temperature_cpu() { - println!("temp cpu: {}", cpu_temperature::read()) -} - -fn test_read_temperature_a770() { - let jiji: &dyn machine::Machine = &machine::jiji::MachineJiji::new().unwrap(); - println!("temp gpu: {}", jiji.get_gpu_tmp()); -} - -fn test_read_temperature_3080() { - nvapi::initialize().expect("Unable to initialize nvapi (Nvidia API)"); - // if let Ok(gpus) = { - // for gpu in gpus { - // let thermal = gpu.thermal_settings(None).unwrap()[0]; - // println!("{:?}", thermal.current_temperature.0) - // } - // } - let gpus = nvapi::PhysicalGpu::enumerate().unwrap(); - let gpu = &gpus[0]; - let sensor = gpu.thermal_settings(None).unwrap()[0]; - println!("{:?}", sensor.current_temperature.0); - nvapi::unload().unwrap(); -} +use std::collections::HashMap; + +use wmi::{COMLibrary, Variant, WMIConnection}; + +use crate::{ + a770, asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature, + gigabyte_rgb_fusion_usb, lian_li_sl_infinity, machine, rgb::Rgb, winring0, +}; + +pub fn tests() { + println!("Running some tests..."); + + winring0::init(); + + // test_asus_aura_usb(asus_aura_usb::Motherboard::Asus650e); + // test_corsair_lighting_pro(); + // test_lianli_sl_infinity(); + // list_usb_devices(); + // test_roccat(); + // test_wmi(); + // test_corsair(); + // test_a770(); + // test_3080ti(); + // test_read_temperature_cpu(); + // test_read_temperature_a770(); + // test_read_temperature_3080(); + test_gigabyte_fusion(); + + winring0::deinit(); + + println!("Press any key to continue..."); + 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, + // }) + // .unwrap(); +} + +fn test_wmi() { + let com_con = COMLibrary::new().unwrap(); + let wmi_con = WMIConnection::new(com_con).unwrap(); + + //let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'").unwrap(); + //let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE 'Intel(R) NF I2C Host Controller'").unwrap(); + let results: Vec> = wmi_con + .raw_query("SELECT * FROM Win32_PnPSignedDriver") + .unwrap(); + //let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_PnPAllocatedResource").unwrap(); + + for os in results { + println!("-------------------"); + println!("{:#?}", os); + } +} + +fn list_usb_devices() { + let api = hidapi::HidApi::new().unwrap(); + for device in api.device_list() { + println!("{:?}", device); + println!("name: {}", device.product_string().unwrap()); + println!("interface number: {}", device.interface_number()); + println!("page: {}", device.usage_page()); + println!("usage: {}", device.usage()); + println!("----"); + } +} + +// fn test_roccat() { +// let api = hidapi::HidApi::new().unwrap(); +// let roccat_device = roccat::get_device(&api); + +// let manufacturer = roccat_device.get_manufacturer_string().unwrap(); +// dbg!(manufacturer); + +// let product = roccat_device.get_product_string().unwrap(); +// dbg!(product); + +// let serial = roccat_device.get_serial_number_string().unwrap(); +// dbg!(serial); + +// roccat::init(&roccat_device); +// roccat::set_color( +// &roccat_device, +// &RGB { +// red: 0, +// green: 255, +// blue: 40, +// }, +// ); +// } + +fn test_asus_aura_usb(motherboard: asus_aura_usb::Motherboard) { + let api = hidapi::HidApi::new().unwrap(); + + let device = asus_aura_usb::Device::new(&api, motherboard).unwrap(); + + println!("Firmware: {}", device.get_firmware_string().unwrap()); + + let configuration = device.get_configuration_table().unwrap(); + println!("Configuration:"); + for i in 0..60 { + print!("{:02X} ", configuration[i]); + if (i + 1) % 6 == 0 { + println!(); + } + } + println!("Number of addressable header: {}", configuration[0x02]); + println!("Number of leds: {}", configuration[0x1B]); + println!("Number of RGB headers: {}", configuration[0x1D]); + + device + .set_color(&Rgb { + red: 0, + green: 0, + blue: 255, + }) + .unwrap(); + + device.save_current_color().unwrap(); +} + +fn test_corsair_lighting_pro() { + let api = hidapi::HidApi::new().unwrap(); + let device = corsair_lighting_pro::Device::new( + &api, + &Rgb { + red: 0, + green: 255, + blue: 0, + }, + ) + .unwrap(); + + for i in 0..=255 { + if i % 10 == 0 || i == 255 || i == 0 { + device + .set_color(&Rgb { + red: i as u8, + green: 255u8 - i as u8, + blue: 0, + }) + .unwrap(); + std::thread::sleep(std::time::Duration::from_millis(200)); + } + } +} + +fn test_lianli_sl_infinity() { + let api = hidapi::HidApi::new().unwrap(); + let device = lian_li_sl_infinity::Device::new(&api).unwrap(); + + device + .set_color(&Rgb { + red: 0, + green: 0, + blue: 255, + }) + .unwrap(); +} + +fn test_corsair() { + let corsair_controllers = [ + corsair_vengeance::Controller::new(0x19), + corsair_vengeance::Controller::new(0x1B), + ]; + + for controller in corsair_controllers { + controller.set_color(&Rgb { + red: 0, + green: 0, + blue: 255, + }); + } +} + +fn test_a770() { + // a770::set_rgb(255, 0, 0); + let mut a770 = a770::A770::new().unwrap(); + a770.set_color(255, 0, 0).unwrap(); +} + +fn test_3080ti() { + let machine: &mut dyn machine::Machine = + &mut machine::lyss_metal::MachineLyssMetal::new().unwrap(); + + machine + .set_color(&Rgb { + red: 255, + green: 0, + blue: 0, + }) + .unwrap(); +} + +const F17H_M01H_THM_TCON_CUR_TMP: u32 = 0x00059800; +const F17H_TEMP_OFFSET_FLAG: u32 = 0x80000; +const FAMILY_17H_PCI_CONTROL_REGISTER: u32 = 0x60; + +fn test_read_temperature_cpu() { + println!("temp cpu: {}", cpu_temperature::read()) +} + +fn test_read_temperature_a770() { + let jiji: &dyn machine::Machine = &machine::jiji::MachineJiji::new().unwrap(); + println!("temp gpu: {}", jiji.get_gpu_tmp()); +} + +fn test_read_temperature_3080() { + nvapi::initialize().expect("Unable to initialize nvapi (Nvidia API)"); + // if let Ok(gpus) = { + // for gpu in gpus { + // let thermal = gpu.thermal_settings(None).unwrap()[0]; + // println!("{:?}", thermal.current_temperature.0) + // } + // } + let gpus = nvapi::PhysicalGpu::enumerate().unwrap(); + let gpu = &gpus[0]; + let sensor = gpu.thermal_settings(None).unwrap()[0]; + println!("{:?}", sensor.current_temperature.0); + nvapi::unload().unwrap(); +}