From df85fed256d816770034fd4290cf2d3d22e43975 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Wed, 20 Sep 2023 14:14:42 +0200 Subject: [PATCH] Add support for Corsair Lighting Pro --- src/{AsusAuraUSB.rs => asus_aura_usb.rs} | 0 src/corsair_lighting_pro.rs | 135 +++++++++++++++++++++++ src/cpu_temperature.rs | 34 ++++++ src/machine.rs | 23 ++-- src/main.rs | 10 +- src/main_loop.rs | 19 +--- src/piix4_i2c.rs | 6 +- src/sensors_jiji.rs | 57 ---------- src/tests.rs | 46 ++++++-- src/winring0.rs | 20 ++++ 10 files changed, 252 insertions(+), 98 deletions(-) rename src/{AsusAuraUSB.rs => asus_aura_usb.rs} (100%) create mode 100644 src/corsair_lighting_pro.rs create mode 100644 src/cpu_temperature.rs delete mode 100644 src/sensors_jiji.rs create mode 100644 src/winring0.rs diff --git a/src/AsusAuraUSB.rs b/src/asus_aura_usb.rs similarity index 100% rename from src/AsusAuraUSB.rs rename to src/asus_aura_usb.rs diff --git a/src/corsair_lighting_pro.rs b/src/corsair_lighting_pro.rs new file mode 100644 index 0000000..48bef11 --- /dev/null +++ b/src/corsair_lighting_pro.rs @@ -0,0 +1,135 @@ +use crate::rgb::RGB; + +const CORSAIR_VID: u16 = 0x1B1C; +const CORSAIR_LIGHTING_NODE_PRO_PID: u16 = 0x0C0B; + +const CORSAIR_LIGHTING_NODE_PACKET_ID_FIRMWARE: u8 = 0x02; // Get firmware version +const CORSAIR_LIGHTING_NODE_PACKET_ID_DIRECT: u8 = 0x32; // Direct mode LED update packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT: u8 = 0x33; // Commit changes packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_BEGIN: u8 = 0x34; // Begin effect packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG: u8 = 0x35; // Effect mode configuration packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_TEMPERATURE: u8 = 0x36; // Update temperature value packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_RESET: u8 = 0x37; // Reset channel packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE: u8 = 0x38; // Set port state packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_BRIGHTNESS: u8 = 0x39; // Set brightness packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_LED_COUNT: u8 = 0x3A; // Set LED count packet +const CORSAIR_LIGHTING_NODE_PACKET_ID_PROTOCOL: u8 = 0x3B; // Set protocol packet + +const CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE: u8 = 0x01; // Effect hardware control of channel +const CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE: u8 = 0x02; // Direct software control of channel + +const CORSAIR_LIGHTING_NODE_MODE_STATIC: u8 = 0x04; // Static mode + +const CHANNEL_COUNT: u8 = 2; + +pub struct Device { + device: hidapi::HidDevice, +} + +impl Device { + pub fn new(api: &hidapi::HidApi) -> Self { + let device = Device { + device: api + .open(CORSAIR_VID, CORSAIR_LIGHTING_NODE_PRO_PID) + .unwrap(), + }; + + 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, + &RGB { + red: 0x00, + green: 0x00, + blue: 0x00, + }, + ); + device.send_commit(channel_id); + } + + device + } + + pub fn set_color(&self, color: &RGB) { + for channel_id in 0..CHANNEL_COUNT { + self.send_effect_config(channel_id, color); + } + } + + fn send_reset(&self, channel_id: u8) { + 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_read = self.device.read(&mut buffer[0..16]).unwrap(); + assert_eq!(n_read, 16); + } + + fn send_begin(&self, channel_id: u8) { + 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_read = self.device.read(&mut buffer[0..16]).unwrap(); + assert_eq!(n_read, 16); + } + + fn send_port_state(&self, channel_id: u8, state: u8) { + 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_read = self.device.read(&mut buffer[0..16]).unwrap(); + assert_eq!(n_read, 16); + } + + fn send_effect_config(&self, channel_id: u8, color: &RGB) { + let mut buffer = [0u8; 65]; + buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG; + buffer[0x02] = channel_id; + buffer[0x03] = 0x00; // count. + buffer[0x04] = 0x1E; // led type. + buffer[0x05] = CORSAIR_LIGHTING_NODE_MODE_STATIC; // mode: static. + buffer[0x06] = 0x00; // speed. + buffer[0x07] = 0x00; // direction. + buffer[0x08] = 0x00; // change style (random). + buffer[0x09] = 0x00; + + let offset_color = 0x0A; + for i in 0..3 { + buffer[offset_color + 3 * i] = color.red; + buffer[offset_color + 3 * i + 1] = color.green; + buffer[offset_color + 3 * i + 2] = color.blue; + } + + let n_write = self.device.write(&buffer).unwrap(); + assert_eq!(n_write, 65); + + let n_read = self.device.read(&mut buffer[0..16]).unwrap(); + assert_eq!(n_read, 16); + } + + fn send_commit(&self, channel_id: u8) { + 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_read = self.device.read(&mut buffer[0..16]).unwrap(); + assert_eq!(n_read, 16); + } +} diff --git a/src/cpu_temperature.rs b/src/cpu_temperature.rs new file mode 100644 index 0000000..21150c0 --- /dev/null +++ b/src/cpu_temperature.rs @@ -0,0 +1,34 @@ +use crate::wrapper_winring0; + +const OLS_TYPE: u32 = 40000; + +const F17H_M01H_THM_TCON_CUR_TMP: u32 = 0x00059800; +const F17H_TEMP_OFFSET_FLAG: u32 = 0x80000; +const FAMILY_17H_PCI_CONTROL_REGISTER: u32 = 0x60; + +pub fn read() -> f32 { + unsafe { + wrapper_winring0::WritePciConfigDwordEx( + 0x00, + FAMILY_17H_PCI_CONTROL_REGISTER, + F17H_M01H_THM_TCON_CUR_TMP, + ); + + let output: &mut u32 = &mut 0; + let ok = wrapper_winring0::ReadPciConfigDwordEx( + 0x00, + FAMILY_17H_PCI_CONTROL_REGISTER + 4, + output, + ); + let offset_flag = *output & F17H_TEMP_OFFSET_FLAG != 0; + let mut temperature = ((*output >> 21) * 125) as f32 * 0.001; + if offset_flag { + temperature -= 49.; + } + + // dbg!(ok); + // dbg!(temperature); + + temperature + } +} diff --git a/src/machine.rs b/src/machine.rs index d1ff5c4..6bb3bfc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,4 +1,4 @@ -use crate::{a770, corsair_vengeance, rgb, sensors_jiji, winring0, AsusAuraUSB}; +use crate::{a770, asus_aura_usb, corsair_vengeance, cpu_temperature, intel_arc, rgb}; pub trait Machine { fn set_color(&mut self, color: &rgb::RGB); @@ -8,9 +8,9 @@ pub trait Machine { pub struct MachineJiji { ram: Vec, - b650e_device: AsusAuraUSB::Device, + b650e_device: asus_aura_usb::Device, a770: a770::A770, - sensors: sensors_jiji::Sensors, + gpu_devices: intel_arc::Devices, } impl MachineJiji { @@ -21,9 +21,9 @@ impl MachineJiji { corsair_vengeance::Controller::new(0x19), corsair_vengeance::Controller::new(0x1B), ], - b650e_device: AsusAuraUSB::Device::new(&api, AsusAuraUSB::Motherboard::Asus650e), + b650e_device: asus_aura_usb::Device::new(&api, asus_aura_usb::Motherboard::Asus650e), a770: a770::A770::new(), - sensors: sensors_jiji::Sensors::new(), + gpu_devices: unsafe { intel_arc::GetDevices() }, }; machine.b650e_device.set_fixed_mode(); machine @@ -38,12 +38,21 @@ impl Machine for MachineJiji { self.b650e_device.set_color(&color); self.a770.set_color(color.red, color.green, color.blue); } + fn get_gpu_tmp(&self) -> f32 { - self.sensors.read_gpu_temp() + unsafe { intel_arc::GetTemperature(self.gpu_devices, 0) as f32 } } fn get_cpu_tmp(&self) -> f32 { - self.sensors.read_cpu_temp() + cpu_temperature::read() + } +} + +impl Drop for MachineJiji { + fn drop(&mut self) { + unsafe { + intel_arc::FreeDevices(self.gpu_devices); + } } } diff --git a/src/main.rs b/src/main.rs index a819b71..34feec7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,27 +27,27 @@ use windows_service::{ define_windows_service!(ffi_service_main, service_main); -mod winring0 { +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 AsusAuraUSB; mod a770; +mod asus_aura_usb; +mod corsair_lighting_pro; mod machine; mod main_loop; +mod winring0; // mod common; mod consts; mod corsair_vengeance; mod piix4_i2c; mod rgb; // mod roccat; Disabled. -mod sensors_jiji; +mod cpu_temperature; mod settings; mod tests; mod timer; diff --git a/src/main_loop.rs b/src/main_loop.rs index 6e7dd74..ae4c221 100644 --- a/src/main_loop.rs +++ b/src/main_loop.rs @@ -17,7 +17,7 @@ pub fn main_loop(completed: Arc) { panic!("Polling frequency must be a multiple of RGB refresh frequency"); } - init_winring0(); + winring0::init(); let sleep = timer::Sleep::new(); let settings = settings::Settings::read(consts::FILE_CONF).expect("Cannot load settings"); @@ -77,20 +77,5 @@ pub fn main_loop(completed: Arc) { // println!("Press any key to continue..."); // std::io::stdin().read_line(&mut String::new()).unwrap(); - unsafe { - winring0::DeinitializeOls(); - } -} - -fn init_winring0() { - unsafe { - let ols_ok = winring0::InitializeOls() != 0; - if !ols_ok { - panic!("Unable to initalize WingRing0"); - } - let dll_status = winring0::GetDllStatus(); - if dll_status != 0 { - panic!("WingRing0 DLL status error: {}", dll_status); - } - } + winring0::deinit(); } diff --git a/src/piix4_i2c.rs b/src/piix4_i2c.rs index 2294a9f..ae974b7 100644 --- a/src/piix4_i2c.rs +++ b/src/piix4_i2c.rs @@ -2,7 +2,7 @@ use std::time::Duration; -use crate::{timer, winring0}; +use crate::{timer, wrapper_winring0}; pub const I2C_BLOCK_MAX: usize = 32; @@ -240,11 +240,11 @@ impl I2c { } unsafe fn write_io_port_byte(&self, op: SMBusAddressOffsets, value: u8) { - winring0::WriteIoPortByte(self.base_address + op as u16, value); + wrapper_winring0::WriteIoPortByte(self.base_address + op as u16, value); } unsafe fn read_io_port_byte(&self, op: SMBusAddressOffsets) -> u8 { - winring0::ReadIoPortByte(self.base_address + op as u16) + wrapper_winring0::ReadIoPortByte(self.base_address + op as u16) } } diff --git a/src/sensors_jiji.rs b/src/sensors_jiji.rs deleted file mode 100644 index 5e57005..0000000 --- a/src/sensors_jiji.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::{intel_arc, winring0}; - -const OLS_TYPE: u32 = 40000; - -const F17H_M01H_THM_TCON_CUR_TMP: u32 = 0x00059800; -const F17H_TEMP_OFFSET_FLAG: u32 = 0x80000; -const FAMILY_17H_PCI_CONTROL_REGISTER: u32 = 0x60; - -pub struct Sensors { - gpu_devices: intel_arc::Devices, -} - -impl Sensors { - pub fn new() -> Self { - unsafe { - Sensors { - gpu_devices: intel_arc::GetDevices(), - } - } - } - - pub fn read_cpu_temp(&self) -> f32 { - unsafe { - winring0::WritePciConfigDwordEx( - 0x00, - FAMILY_17H_PCI_CONTROL_REGISTER, - F17H_M01H_THM_TCON_CUR_TMP, - ); - - let output: &mut u32 = &mut 0; - let ok = - winring0::ReadPciConfigDwordEx(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, output); - let offset_flag = *output & F17H_TEMP_OFFSET_FLAG != 0; - let mut temperature = ((*output >> 21) * 125) as f32 * 0.001; - if offset_flag { - temperature -= 49.; - } - - // dbg!(ok); - // dbg!(temperature); - - temperature - } - } - - pub fn read_gpu_temp(&self) -> f32 { - unsafe { intel_arc::GetTemperature(self.gpu_devices, 0) as f32 } - } -} - -impl Drop for Sensors { - fn drop(&mut self) { - unsafe { - intel_arc::FreeDevices(self.gpu_devices); - } - } -} diff --git a/src/tests.rs b/src/tests.rs index 08e6bd0..1321005 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -2,18 +2,27 @@ use std::collections::HashMap; use wmi::{COMLibrary, Variant, WMIConnection}; -use crate::{a770, corsair_vengeance, rgb::RGB, sensors_jiji, AsusAuraUSB}; +use crate::{ + a770, asus_aura_usb, corsair_lighting_pro, corsair_vengeance, cpu_temperature, machine, + rgb::RGB, winring0, wrapper_winring0, +}; pub fn tests() { println!("Running some tests..."); - test_asus_aura_usb(AsusAuraUSB::Motherboard::AsusCrosshairVIIIHero); + winring0::init(); + + // test_asus_aura_usb(asus_aura_usb::Motherboard::AsusCrosshairVIIIHero); + // test_corsair_lighting_pro(); // list_usb_devices(); // test_roccat(); // test_wmi(); // test_corsair(); // test_a770(); - // test_read_temp(); + test_read_temperature_cpu(); + // test_read_temperatur_a770 + + winring0::deinit(); println!("Press any key to continue..."); std::io::stdin().read_line(&mut String::new()).unwrap(); @@ -72,10 +81,10 @@ fn list_usb_devices() { // ); // } -fn test_asus_aura_usb(motherboard: AsusAuraUSB::Motherboard) { +fn test_asus_aura_usb(motherboard: asus_aura_usb::Motherboard) { let api = hidapi::HidApi::new().unwrap(); - let device = AsusAuraUSB::Device::new(&api, motherboard); + let device = asus_aura_usb::Device::new(&api, motherboard); println!("Firmware: {}", device.get_firmware_string()); @@ -103,6 +112,17 @@ fn test_asus_aura_usb(motherboard: AsusAuraUSB::Motherboard) { device.save_current_color(); } +fn test_corsair_lighting_pro() { + let api = hidapi::HidApi::new().unwrap(); + let device = corsair_lighting_pro::Device::new(&api); + + device.set_color(&RGB { + red: 0, + green: 0, + blue: 255, + }); +} + fn test_corsair() { let corsair_controllers = [ corsair_vengeance::Controller::new(0x19), @@ -123,8 +143,16 @@ fn test_a770() { a770.set_color(255, 0, 0); } -fn test_read_temp() { - let sensors = sensors_jiji::Sensors::new(); - println!("temp cpu: {}", sensors.read_cpu_temp()); - println!("temp gpu: {}", sensors.read_gpu_temp()); +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_temperatur_a770() { + let jiji: &dyn machine::Machine = &machine::MachineJiji::new(); + println!("temp gpu: {}", jiji.get_gpu_tmp()); +} + diff --git a/src/winring0.rs b/src/winring0.rs new file mode 100644 index 0000000..dbbaae6 --- /dev/null +++ b/src/winring0.rs @@ -0,0 +1,20 @@ +use crate::wrapper_winring0; + +pub fn init() { + unsafe { + let ols_ok = wrapper_winring0::InitializeOls() != 0; + if !ols_ok { + panic!("Unable to initalize WingRing0"); + } + let dll_status = wrapper_winring0::GetDllStatus(); + if dll_status != 0 { + panic!("WingRing0 DLL status error: {}", dll_status); + } + } +} + +pub fn deinit() { + unsafe { + wrapper_winring0::DeinitializeOls(); + } +} -- 2.45.1