mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Merge branch 'fluke/fan_curves_v9' into 'main'
Fluke/fan curves v9 See merge request asus-linux/asusctl!77
This commit is contained in:
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
+ `BREAKING:` plain `Image` with time period is changed and old anime configs break as a result (sorry)
|
||||
- LED:
|
||||
+ By popular request LED prev/next cycle is added
|
||||
+ Add led modes for GX551Q
|
||||
### BREAKING CHANGES
|
||||
- Graphics control:
|
||||
+ graphics control is pulled out of asusd and moved to new package; https://gitlab.com/asus-linux/supergfxctl
|
||||
@@ -19,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
+ profiles now depend on power-profile-daemon plus kernel patches for support of platform_profile
|
||||
- if your system supports fan-curves you will also require upcoming kernel patches for this
|
||||
+ profiles are now moved to a new file
|
||||
+ fan-curves are only partially completed due to this release needing to be done sooner
|
||||
|
||||
# [3.7.2] - 2021-08-02
|
||||
### Added
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -938,6 +938,7 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"udev",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
|
||||
@@ -375,7 +375,9 @@ fn handle_profile(
|
||||
supported: &PlatformProfileFunctions,
|
||||
cmd: &ProfileCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if !cmd.next && !cmd.list && !cmd.active_name && !cmd.active_data && !cmd.profiles_data {
|
||||
println!("Warning: Profiles should work fine but now depend on power-profiles-daemon v0.9+");
|
||||
println!("Warning: Fan-curve support is coming in a 4.1.x release");
|
||||
if !cmd.next && !cmd.list {
|
||||
if !cmd.help {
|
||||
println!("Missing arg or command\n");
|
||||
}
|
||||
@@ -394,14 +396,18 @@ fn handle_profile(
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
|
||||
println!("Note: turbo, frequency, fan preset and fan curve options will apply to");
|
||||
println!(" to the currently active profile unless a profile name is specified");
|
||||
// println!("Note: turbo, frequency, fan preset and fan curve options will apply to");
|
||||
// println!(" to the currently active profile unless a profile name is specified");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if cmd.next {
|
||||
dbus.proxies().profile().next_profile()?;
|
||||
}
|
||||
if cmd.list {
|
||||
let res = dbus.proxies().profile().profiles()?;
|
||||
res.iter().for_each(|p| println!("{:?}", p));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,4 @@ pub struct ProfileCommand {
|
||||
pub next: bool,
|
||||
#[options(help = "list available profiles")]
|
||||
pub list: bool,
|
||||
#[options(help = "get active profile name")]
|
||||
pub active_name: bool,
|
||||
#[options(help = "get active profile data")]
|
||||
pub active_data: bool,
|
||||
#[options(help = "get all profile data")]
|
||||
pub profiles_data: bool,
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ logind-zbus = "^0.7.1"
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
serde_json = "^1.0"
|
||||
toml = "^0.5"
|
||||
toml = "^0.5.8"
|
||||
|
||||
# Device control
|
||||
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use log::{error, warn};
|
||||
use rog_profiles::{FanCurves, Profile};
|
||||
use rog_profiles::fan_curve_set::FanCurveSet;
|
||||
use rog_profiles::{FanCurveProfiles, Profile};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
@@ -9,23 +10,24 @@ pub struct ProfileConfig {
|
||||
#[serde(skip)]
|
||||
config_path: String,
|
||||
/// For restore on boot
|
||||
pub active: Profile,
|
||||
pub active_profile: Profile,
|
||||
/// States to restore
|
||||
pub fan_curves: Option<FanCurves>,
|
||||
pub fan_curves: Option<FanCurveProfiles>,
|
||||
}
|
||||
|
||||
impl ProfileConfig {
|
||||
fn new(config_path: String) -> Self {
|
||||
let mut platform = ProfileConfig {
|
||||
config_path,
|
||||
active: Profile::Balanced,
|
||||
active_profile: Profile::get_active_profile().unwrap_or(Profile::Balanced),
|
||||
fan_curves: None,
|
||||
};
|
||||
|
||||
if FanCurves::is_fan_curves_supported() {
|
||||
let mut curves = FanCurves::default();
|
||||
curves.update_from_platform();
|
||||
platform.fan_curves = Some(curves);
|
||||
if let Ok(res) = FanCurveSet::is_supported() {
|
||||
if res {
|
||||
let curves = FanCurveProfiles::default();
|
||||
platform.fan_curves = Some(curves);
|
||||
}
|
||||
}
|
||||
|
||||
platform
|
||||
@@ -43,7 +45,7 @@ impl ProfileConfig {
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len == 0 {
|
||||
config = Self::new(config_path);
|
||||
} else if let Ok(data) = serde_json::from_str(&buf) {
|
||||
} else if let Ok(data) = toml::from_str(&buf) {
|
||||
config = data;
|
||||
config.config_path = config_path;
|
||||
} else {
|
||||
@@ -68,7 +70,7 @@ impl ProfileConfig {
|
||||
if l == 0 {
|
||||
warn!("File is empty {}", self.config_path);
|
||||
} else {
|
||||
let mut data: ProfileConfig = serde_json::from_str(&buf)
|
||||
let mut data: ProfileConfig = toml::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", self.config_path));
|
||||
// copy over serde skipped values
|
||||
data.config_path = self.config_path.clone();
|
||||
@@ -79,8 +81,8 @@ impl ProfileConfig {
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = File::create(&self.config_path).expect("Couldn't overwrite config");
|
||||
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
||||
file.write_all(json.as_bytes())
|
||||
let data = toml::to_string(self).expect("Parse config to toml failed");
|
||||
file.write_all(data.as_bytes())
|
||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,37 +2,16 @@ use crate::error::RogError;
|
||||
use crate::GetSupported;
|
||||
use log::{info, warn};
|
||||
use rog_profiles::error::ProfileError;
|
||||
use rog_profiles::{FanCurves, Profile};
|
||||
use rog_profiles::fan_curve_set::FanCurveSet;
|
||||
use rog_profiles::Profile;
|
||||
use rog_supported::PlatformProfileFunctions;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use udev::Device;
|
||||
|
||||
use super::config::ProfileConfig;
|
||||
|
||||
pub struct CtrlPlatformTask {
|
||||
config: Arc<Mutex<ProfileConfig>>,
|
||||
}
|
||||
|
||||
impl CtrlPlatformTask {
|
||||
pub fn new(config: Arc<Mutex<ProfileConfig>>) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::CtrlTask for CtrlPlatformTask {
|
||||
fn do_task(&self) -> Result<(), RogError> {
|
||||
if let Ok(mut lock) = self.config.try_lock() {
|
||||
// Refresh the config in-case the user has edited it
|
||||
if let Some(curves) = &mut lock.fan_curves {
|
||||
curves.update_from_platform();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlPlatformProfile {
|
||||
pub config: Arc<Mutex<ProfileConfig>>,
|
||||
pub config: ProfileConfig,
|
||||
pub fan_device: Option<Device>,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlPlatformProfile {
|
||||
@@ -48,7 +27,14 @@ https://lkml.org/lkml/2021/8/18/1022
|
||||
"#
|
||||
);
|
||||
}
|
||||
if !FanCurves::is_fan_curves_supported() {
|
||||
|
||||
let res = FanCurveSet::is_supported();
|
||||
let mut fan_curve_supported = res.is_err();
|
||||
if let Ok(r) = res {
|
||||
fan_curve_supported = r;
|
||||
};
|
||||
|
||||
if fan_curve_supported {
|
||||
info!(
|
||||
r#"
|
||||
fan curves kernel interface not found, your laptop does not support this, or the interface is missing.
|
||||
@@ -58,9 +44,10 @@ Please note that as of 24/08/2021 this is not final.
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
PlatformProfileFunctions {
|
||||
platform_profile: Profile::is_platform_profile_supported(),
|
||||
fan_curves: FanCurves::is_fan_curves_supported(),
|
||||
fan_curves: fan_curve_supported,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,9 +55,9 @@ Please note that as of 24/08/2021 this is not final.
|
||||
impl crate::Reloadable for CtrlPlatformProfile {
|
||||
/// Fetch the active profile and use that to set all related components up
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(cfg) = self.config.clone().try_lock() {
|
||||
if let Some(curves) = &cfg.fan_curves {
|
||||
curves.update_platform();
|
||||
if let Some(curves) = &self.config.fan_curves {
|
||||
if let Ok(mut device) = FanCurveSet::get_device() {
|
||||
curves.write_to_platform(self.config.active_profile, &mut device);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -78,43 +65,56 @@ impl crate::Reloadable for CtrlPlatformProfile {
|
||||
}
|
||||
|
||||
impl CtrlPlatformProfile {
|
||||
pub fn new(config: Arc<Mutex<ProfileConfig>>) -> Result<Self, RogError> {
|
||||
pub fn new(mut config: ProfileConfig, fan_device: Option<Device>) -> Result<Self, RogError> {
|
||||
if Profile::is_platform_profile_supported() {
|
||||
info!("Device has profile control available");
|
||||
return Ok(CtrlPlatformProfile { config });
|
||||
|
||||
if let Some(ref device) = fan_device {
|
||||
let profile = config.active_profile;
|
||||
config
|
||||
.fan_curves
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.read_from_dev_profile(profile, device);
|
||||
}
|
||||
config.write();
|
||||
|
||||
return Ok(CtrlPlatformProfile { config, fan_device });
|
||||
}
|
||||
|
||||
Err(ProfileError::NotSupported.into())
|
||||
}
|
||||
|
||||
pub fn get_device(&self) -> Option<Device> {
|
||||
self.fan_device.clone()
|
||||
}
|
||||
|
||||
pub fn save_config(&self) {
|
||||
if let Ok(lock) = self.config.lock() {
|
||||
lock.write();
|
||||
}
|
||||
self.config.write();
|
||||
}
|
||||
|
||||
/// Toggle to next profile in list. This will first read the config, switch, then write out
|
||||
pub(super) fn set_next_profile(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
config.read();
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
self.config.read();
|
||||
|
||||
match config.active {
|
||||
Profile::Balanced => {
|
||||
Profile::set_profile(Profile::Performance)?;
|
||||
config.active = Profile::Performance;
|
||||
}
|
||||
Profile::Performance => {
|
||||
Profile::set_profile(Profile::Quiet)?;
|
||||
config.active = Profile::Quiet;
|
||||
}
|
||||
Profile::Quiet => {
|
||||
Profile::set_profile(Profile::Balanced)?;
|
||||
config.active = Profile::Balanced;
|
||||
}
|
||||
match self.config.active_profile {
|
||||
Profile::Balanced => {
|
||||
Profile::set_profile(Profile::Performance)?;
|
||||
self.config.active_profile = Profile::Performance;
|
||||
}
|
||||
Profile::Performance => {
|
||||
Profile::set_profile(Profile::Quiet)?;
|
||||
self.config.active_profile = Profile::Quiet;
|
||||
}
|
||||
Profile::Quiet => {
|
||||
Profile::set_profile(Profile::Balanced)?;
|
||||
self.config.active_profile = Profile::Balanced;
|
||||
}
|
||||
|
||||
config.write();
|
||||
}
|
||||
|
||||
self.config.write();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use log::warn;
|
||||
use rog_profiles::FanCurve;
|
||||
use rog_profiles::fan_curve_set::CurveData;
|
||||
use rog_profiles::fan_curve_set::FanCurveSet;
|
||||
use rog_profiles::Profile;
|
||||
|
||||
use std::sync::Arc;
|
||||
@@ -45,11 +46,9 @@ impl ProfileZbus {
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn active_profile(&mut self) -> zbus::fdo::Result<Profile> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
return Ok(cfg.active);
|
||||
}
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
return Ok(ctrl.config.active_profile);
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile name".to_string(),
|
||||
@@ -58,15 +57,14 @@ impl ProfileZbus {
|
||||
|
||||
/// Set this platform_profile name as active
|
||||
fn set_active_profile(&self, profile: Profile) {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
cfg.read();
|
||||
Profile::set_profile(profile)
|
||||
.map_err(|e| warn!("Profile::set_profile, {}", e))
|
||||
.ok();
|
||||
cfg.active = profile;
|
||||
}
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
ctrl.config.read();
|
||||
Profile::set_profile(profile)
|
||||
.map_err(|e| warn!("Profile::set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.config.active_profile = profile;
|
||||
|
||||
ctrl.save_config();
|
||||
}
|
||||
self.do_notification();
|
||||
@@ -74,14 +72,26 @@ impl ProfileZbus {
|
||||
|
||||
/// Get a list of profiles that have fan-curves enabled.
|
||||
fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result<Vec<Profile>> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(curves) = &cfg.fan_curves {
|
||||
return Ok(curves.get_enabled_curve_names().to_vec());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &ctrl.config.fan_curves {
|
||||
return Ok(curves.get_enabled_curve_profiles().to_vec());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get enabled fan curve names".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Get a list of profiles that have fan-curves enabled.
|
||||
fn set_enabled_fan_profiles(&mut self, profiles: Vec<Profile>) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &mut ctrl.config.fan_curves {
|
||||
curves.set_enabled_curve_profiles(profiles);
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get enabled fan curve names".to_string(),
|
||||
@@ -89,43 +99,42 @@ impl ProfileZbus {
|
||||
}
|
||||
|
||||
/// Get the fan-curve data for the currently active Profile
|
||||
fn active_fan_curve_data(&mut self) -> zbus::fdo::Result<FanCurve> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(curves) = &cfg.fan_curves {
|
||||
return Ok((*curves.get_active_fan_curves()).clone());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
fn active_fan_curve_data(&mut self) -> zbus::fdo::Result<FanCurveSet> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &ctrl.config.fan_curves {
|
||||
return Ok((*curves.get_active_fan_curves()).clone());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
Err(Error::Failed("Failed to get fan curve data".to_string()))
|
||||
}
|
||||
|
||||
/// Get fan-curve data for each Profile as an array of objects
|
||||
fn fan_curves(&self) -> zbus::fdo::Result<Vec<FanCurve>> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(curves) = &cfg.fan_curves {
|
||||
return Ok(curves.get_all_fan_curves());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
fn fan_curves(&self) -> zbus::fdo::Result<Vec<FanCurveSet>> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &ctrl.config.fan_curves {
|
||||
return Ok(curves.get_all_fan_curves());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
Err(Error::Failed("Failed to get all fan curves".to_string()))
|
||||
}
|
||||
|
||||
/// Set this fan-curve data
|
||||
fn set_fan_curve(&self, curve: FanCurve) -> zbus::fdo::Result<()> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(curves) = &mut cfg.fan_curves {
|
||||
curves.set_fan_curve(curve);
|
||||
fn set_fan_curve(&self, curve: CurveData) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
let profile = ctrl.config.active_profile;
|
||||
if let Some(mut device) = ctrl.get_device() {
|
||||
if let Some(curves) = &mut ctrl.config.fan_curves {
|
||||
curves.write_and_set_fan_curve(curve, profile, &mut device);
|
||||
}
|
||||
} else {
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
|
||||
ctrl.save_config();
|
||||
}
|
||||
|
||||
@@ -139,10 +148,8 @@ impl ProfileZbus {
|
||||
impl ProfileZbus {
|
||||
fn do_notification(&self) {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(cfg) = ctrl.config.clone().try_lock() {
|
||||
self.notify_profile(&cfg.active)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
self.notify_profile(&ctrl.config.active_profile)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use daemon::ctrl_aura::controller::{
|
||||
};
|
||||
use daemon::ctrl_charge::CtrlCharge;
|
||||
use daemon::ctrl_profiles::config::ProfileConfig;
|
||||
use daemon::ctrl_profiles::controller::CtrlPlatformTask;
|
||||
use daemon::{
|
||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||
};
|
||||
@@ -21,6 +20,7 @@ use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
||||
use log::LevelFilter;
|
||||
use log::{error, info, warn};
|
||||
use rog_dbus::DBUS_NAME;
|
||||
use rog_profiles::fan_curve_set::FanCurveSet;
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::io::Write;
|
||||
@@ -108,16 +108,19 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
let profile_config = Arc::new(Mutex::new(ProfileConfig::load(PROFILE_CONFIG_PATH.into())));
|
||||
match CtrlPlatformProfile::new(profile_config.clone()) {
|
||||
let fan_device = if let Ok(res) = FanCurveSet::get_device() {
|
||||
Some(res)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let profile_config = ProfileConfig::load(PROFILE_CONFIG_PATH.into());
|
||||
match CtrlPlatformProfile::new(profile_config, fan_device) {
|
||||
Ok(mut ctrl) => {
|
||||
ctrl.reload()
|
||||
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
||||
|
||||
let tmp = Arc::new(Mutex::new(ctrl));
|
||||
ProfileZbus::new(tmp).add_to_server(&mut object_server);
|
||||
|
||||
tasks.push(Box::new(CtrlPlatformTask::new(profile_config)));
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Profile control: {}", err);
|
||||
|
||||
@@ -109,3 +109,10 @@ board_names = ["GX550L"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = false
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus Duo 15 SE"
|
||||
board_name = ["GX551Q"]
|
||||
standard ["Static", "Breathe", "Pulse", "Rainbow", "Strobe"]
|
||||
multizone = false
|
||||
per_key = true
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use rog_profiles::{FanCurve, Profile};
|
||||
use rog_profiles::{fan_curve_set::FanCurveSet, Profile};
|
||||
use zbus::{dbus_proxy, Connection, Result};
|
||||
|
||||
#[dbus_proxy(
|
||||
@@ -29,29 +29,29 @@ use zbus::{dbus_proxy, Connection, Result};
|
||||
default_path = "/org/asuslinux/Profile"
|
||||
)]
|
||||
trait Daemon {
|
||||
/// Profiles method
|
||||
fn profiles(&self) -> zbus::Result<Vec<Profile>>;
|
||||
|
||||
/// NextProfile method
|
||||
fn next_profile(&self) -> zbus::Result<()>;
|
||||
/// Get the active `Profile` data
|
||||
fn active_fan_curve_data(&self) -> zbus::Result<FanCurveSet>;
|
||||
|
||||
/// Profile, get the active profile
|
||||
fn active_profile(&self) -> zbus::Result<Profile>;
|
||||
|
||||
/// Set the specific profile as active
|
||||
fn set_active_profile(&self, profile: Profile) -> zbus::Result<()>;
|
||||
|
||||
/// Get enabled fan curves
|
||||
fn enabled_fan_profiles(&self) -> zbus::Result<Vec<Profile>>;
|
||||
|
||||
/// Get the active `Profile` data
|
||||
fn active_fan_data(&self) -> zbus::Result<FanCurve>;
|
||||
|
||||
/// Get all fan curve data
|
||||
fn fan_curves(&self) -> zbus::Result<Vec<FanCurve>>;
|
||||
fn fan_curves(&self) -> zbus::Result<Vec<FanCurveSet>>;
|
||||
|
||||
/// NextProfile method
|
||||
fn next_profile(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Profiles method
|
||||
fn profiles(&self) -> zbus::Result<Vec<Profile>>;
|
||||
|
||||
/// Set the specific profile as active
|
||||
fn set_active_profile(&self, profile: Profile) -> zbus::Result<()>;
|
||||
|
||||
/// Set a fan curve. If a field is empty then the exisiting saved curve is used
|
||||
fn set_fan_curve(&self, curve: FanCurve) -> zbus::Result<()>;
|
||||
fn set_fan_curve(&self, curve: FanCurveSet) -> zbus::Result<()>;
|
||||
|
||||
/// NotifyProfile signal
|
||||
#[dbus_proxy(signal)]
|
||||
|
||||
@@ -9,6 +9,7 @@ default = ["dbus"]
|
||||
dbus = ["zvariant", "zvariant_derive"]
|
||||
|
||||
[dependencies]
|
||||
udev = "^0.6"
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
|
||||
|
||||
139
rog-profiles/src/fan_curve_set.rs
Normal file
139
rog-profiles/src/fan_curve_set.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use udev::Device;
|
||||
#[cfg(feature = "dbus")]
|
||||
use zvariant_derive::Type;
|
||||
|
||||
use crate::{error::ProfileError, write_to_fan, FanCurvePU};
|
||||
|
||||
pub fn pwm_str(fan: char, index: char) -> String {
|
||||
let mut buf = "pwm1_auto_point1_pwm".to_string();
|
||||
unsafe {
|
||||
let tmp = buf.as_bytes_mut();
|
||||
tmp[3] = fan as u8;
|
||||
tmp[15] = index as u8;
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn temp_str(fan: char, index: char) -> String {
|
||||
let mut buf = "pwm1_auto_point1_temp".to_string();
|
||||
unsafe {
|
||||
let tmp = buf.as_bytes_mut();
|
||||
tmp[3] = fan as u8;
|
||||
tmp[15] = index as u8;
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Deserialize, Serialize, Default, Debug, Clone)]
|
||||
pub struct CurveData {
|
||||
pub fan: FanCurvePU,
|
||||
pub pwm: [u8; 8],
|
||||
pub temp: [u8; 8],
|
||||
}
|
||||
|
||||
/// A `FanCurveSet` contains both CPU and GPU fan curve data
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct FanCurveSet {
|
||||
pub cpu: CurveData,
|
||||
pub gpu: CurveData,
|
||||
}
|
||||
|
||||
impl Default for FanCurveSet {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cpu: CurveData {
|
||||
fan: FanCurvePU::CPU,
|
||||
pwm: [0u8; 8],
|
||||
temp: [0u8; 8],
|
||||
},
|
||||
gpu: CurveData {
|
||||
fan: FanCurvePU::GPU,
|
||||
pwm: [0u8; 8],
|
||||
temp: [0u8; 8],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FanCurveSet {
|
||||
pub fn get_device() -> Result<Device, ProfileError> {
|
||||
let mut enumerator = udev::Enumerator::new()?;
|
||||
enumerator.match_subsystem("hwmon")?;
|
||||
|
||||
for device in enumerator.scan_devices().unwrap() {
|
||||
if device.parent_with_subsystem("platform").unwrap().is_some() {
|
||||
if let Some(name) = device.attribute_value("name") {
|
||||
if name == "asus_custom_fan_curve" {
|
||||
return Ok(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ProfileError::NotSupported)
|
||||
}
|
||||
|
||||
pub fn is_supported() -> Result<bool, ProfileError> {
|
||||
if Self::get_device().is_ok() {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn new() -> Result<(Self, Device), ProfileError> {
|
||||
if let Ok(device) = Self::get_device() {
|
||||
let mut fans = Self {
|
||||
cpu: CurveData::default(),
|
||||
gpu: CurveData::default(),
|
||||
};
|
||||
|
||||
fans.cpu.fan = FanCurvePU::CPU;
|
||||
fans.cpu.fan = FanCurvePU::GPU;
|
||||
|
||||
fans.read_from_device(&device);
|
||||
|
||||
return Ok((fans, device));
|
||||
}
|
||||
|
||||
Err(ProfileError::NotSupported)
|
||||
}
|
||||
|
||||
fn set_val_from_attr(tmp: &str, device: &Device, buf: &mut [u8; 8]) {
|
||||
if let Some(n) = tmp.chars().nth(15) {
|
||||
let i = n.to_digit(10).unwrap() as usize;
|
||||
let d = device.attribute_value(tmp).unwrap();
|
||||
let d: u8 = d.to_string_lossy().parse().unwrap();
|
||||
buf[i - 1] = d;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_from_device(&mut self, device: &Device) {
|
||||
for attr in device.attributes() {
|
||||
let tmp = attr.name().to_string_lossy();
|
||||
if tmp.starts_with("pwm1") && tmp.ends_with("_temp") {
|
||||
Self::set_val_from_attr(tmp.as_ref(), device, &mut self.cpu.temp)
|
||||
}
|
||||
if tmp.starts_with("pwm1") && tmp.ends_with("_pwm") {
|
||||
Self::set_val_from_attr(tmp.as_ref(), device, &mut self.cpu.pwm)
|
||||
}
|
||||
if tmp.starts_with("pwm2") && tmp.ends_with("_temp") {
|
||||
Self::set_val_from_attr(tmp.as_ref(), device, &mut self.gpu.temp)
|
||||
}
|
||||
if tmp.starts_with("pwm2") && tmp.ends_with("_pwm") {
|
||||
Self::set_val_from_attr(tmp.as_ref(), device, &mut self.gpu.pwm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_cpu_fan(&self, device: &mut Device) {
|
||||
write_to_fan(&self.cpu, '1', device);
|
||||
}
|
||||
|
||||
pub fn write_gpu_fan(&self, device: &mut Device) {
|
||||
write_to_fan(&self.gpu, '2', device);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,42 @@
|
||||
pub mod error;
|
||||
pub mod fan_curve_set;
|
||||
|
||||
use std::{
|
||||
fs::OpenOptions,
|
||||
io::{Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use error::ProfileError;
|
||||
use fan_curve_set::{CurveData, FanCurveSet};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use udev::Device;
|
||||
#[cfg(feature = "dbus")]
|
||||
use zvariant_derive::Type;
|
||||
|
||||
pub static PLATFORM_PROFILE: &str = "/sys/firmware/acpi/platform_profile";
|
||||
pub static PLATFORM_PROFILES: &str = "/sys/firmware/acpi/platform_profile_choices";
|
||||
|
||||
pub static FAN_CURVE_BASE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/";
|
||||
pub static FAN_CURVE_ACTIVE_FILE: &str = "enabled_fan_curve_profiles";
|
||||
pub static FAN_CURVE_FILENAME_PART: &str = "_fan_curve_";
|
||||
|
||||
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
pub fn find_fan_curve_node() -> Result<Option<Device>, ProfileError> {
|
||||
let mut enumerator = udev::Enumerator::new()?;
|
||||
enumerator.match_subsystem("hwmon")?;
|
||||
|
||||
for device in enumerator.scan_devices()? {
|
||||
if device.parent_with_subsystem("platform")?.is_some() {
|
||||
if let Some(name) = device.attribute_value("name") {
|
||||
if name == "asus_custom_fan_curve" {
|
||||
return Ok(Some(device));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(ProfileError::NotSupported)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
|
||||
pub enum Profile {
|
||||
@@ -116,82 +132,47 @@ impl Default for FanCurvePU {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Deserialize, Serialize, Default, Debug, Clone)]
|
||||
pub struct FanCurve {
|
||||
pub profile: Profile,
|
||||
pub cpu: String,
|
||||
pub gpu: String,
|
||||
}
|
||||
|
||||
/// Main purpose of `FanCurves` is to enable retoring state on system boot
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct FanCurves {
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
pub struct FanCurveProfiles {
|
||||
enabled: Vec<Profile>,
|
||||
balanced: FanCurve,
|
||||
performance: FanCurve,
|
||||
quiet: FanCurve,
|
||||
balanced: FanCurveSet,
|
||||
performance: FanCurveSet,
|
||||
quiet: FanCurveSet,
|
||||
}
|
||||
|
||||
impl Default for FanCurves {
|
||||
fn default() -> Self {
|
||||
let mut curves = Self {
|
||||
enabled: Default::default(),
|
||||
balanced: Default::default(),
|
||||
performance: Default::default(),
|
||||
quiet: Default::default(),
|
||||
impl FanCurveProfiles {
|
||||
///
|
||||
pub fn read_from_dev_profile(&mut self, profile: Profile, device: &Device) {
|
||||
let mut tmp = FanCurveSet::default();
|
||||
tmp.read_from_device(device);
|
||||
match profile {
|
||||
Profile::Balanced => self.balanced = tmp,
|
||||
Profile::Performance => self.performance = tmp,
|
||||
Profile::Quiet => self.quiet = tmp,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_to_platform(&self, profile: Profile, device: &mut Device) {
|
||||
let fans = match profile {
|
||||
Profile::Balanced => &self.balanced,
|
||||
Profile::Performance => &self.performance,
|
||||
Profile::Quiet => &self.quiet,
|
||||
};
|
||||
curves.balanced.profile = Profile::Balanced;
|
||||
curves.performance.profile = Profile::Performance;
|
||||
curves.quiet.profile = Profile::Quiet;
|
||||
curves
|
||||
}
|
||||
}
|
||||
|
||||
impl FanCurves {
|
||||
pub fn is_fan_curves_supported() -> bool {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(FAN_CURVE_BASE_PATH);
|
||||
path.push(FAN_CURVE_ACTIVE_FILE);
|
||||
path.exists()
|
||||
fans.write_cpu_fan(device);
|
||||
fans.write_gpu_fan(device);
|
||||
}
|
||||
|
||||
pub fn update_from_platform(&mut self) {
|
||||
self.balanced.cpu = Self::get_fan_curve_from_file(Profile::Balanced, FanCurvePU::CPU);
|
||||
self.balanced.gpu = Self::get_fan_curve_from_file(Profile::Balanced, FanCurvePU::GPU);
|
||||
|
||||
self.performance.cpu = Self::get_fan_curve_from_file(Profile::Performance, FanCurvePU::CPU);
|
||||
self.performance.gpu = Self::get_fan_curve_from_file(Profile::Performance, FanCurvePU::GPU);
|
||||
|
||||
self.quiet.cpu = Self::get_fan_curve_from_file(Profile::Quiet, FanCurvePU::CPU);
|
||||
self.quiet.gpu = Self::get_fan_curve_from_file(Profile::Quiet, FanCurvePU::GPU);
|
||||
}
|
||||
|
||||
pub fn update_platform(&self) {
|
||||
Self::set_fan_curve_for_platform(Profile::Balanced, FanCurvePU::CPU, &self.balanced.cpu);
|
||||
Self::set_fan_curve_for_platform(Profile::Balanced, FanCurvePU::GPU, &self.balanced.gpu);
|
||||
|
||||
Self::set_fan_curve_for_platform(
|
||||
Profile::Performance,
|
||||
FanCurvePU::CPU,
|
||||
&self.performance.cpu,
|
||||
);
|
||||
Self::set_fan_curve_for_platform(
|
||||
Profile::Performance,
|
||||
FanCurvePU::GPU,
|
||||
&self.performance.gpu,
|
||||
);
|
||||
|
||||
Self::set_fan_curve_for_platform(Profile::Quiet, FanCurvePU::CPU, &self.quiet.cpu);
|
||||
Self::set_fan_curve_for_platform(Profile::Quiet, FanCurvePU::GPU, &self.quiet.gpu);
|
||||
}
|
||||
|
||||
pub fn get_enabled_curve_names(&self) -> &[Profile] {
|
||||
pub fn get_enabled_curve_profiles(&self) -> &[Profile] {
|
||||
&self.enabled
|
||||
}
|
||||
|
||||
pub fn get_all_fan_curves(&self) -> Vec<FanCurve> {
|
||||
pub fn set_enabled_curve_profiles(&mut self, profiles: Vec<Profile>) {
|
||||
self.enabled = profiles
|
||||
}
|
||||
|
||||
pub fn get_all_fan_curves(&self) -> Vec<FanCurveSet> {
|
||||
vec![
|
||||
self.balanced.clone(),
|
||||
self.performance.clone(),
|
||||
@@ -199,7 +180,7 @@ impl FanCurves {
|
||||
]
|
||||
}
|
||||
|
||||
pub fn get_active_fan_curves(&self) -> &FanCurve {
|
||||
pub fn get_active_fan_curves(&self) -> &FanCurveSet {
|
||||
match Profile::get_active_profile().unwrap() {
|
||||
Profile::Balanced => &self.balanced,
|
||||
Profile::Performance => &self.performance,
|
||||
@@ -207,7 +188,7 @@ impl FanCurves {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fan_curves_for(&self, name: Profile) -> &FanCurve {
|
||||
pub fn get_fan_curves_for(&self, name: Profile) -> &FanCurveSet {
|
||||
match name {
|
||||
Profile::Balanced => &self.balanced,
|
||||
Profile::Performance => &self.performance,
|
||||
@@ -215,23 +196,7 @@ impl FanCurves {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fan_curve_from_file(name: Profile, pu: FanCurvePU) -> String {
|
||||
let mut file: String = FAN_CURVE_BASE_PATH.into();
|
||||
file.push_str(pu.into());
|
||||
file.push_str(FAN_CURVE_FILENAME_PART);
|
||||
file.push_str(name.into());
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&file)
|
||||
.unwrap_or_else(|_| panic!("{} not found", &file));
|
||||
|
||||
let mut buf = String::new();
|
||||
file.read_to_string(&mut buf).unwrap();
|
||||
buf.trim().to_string()
|
||||
}
|
||||
|
||||
pub fn get_fan_curve_for(&self, name: &Profile, pu: &FanCurvePU) -> &str {
|
||||
pub fn get_fan_curve_for(&self, name: &Profile, pu: &FanCurvePU) -> &CurveData {
|
||||
match name {
|
||||
Profile::Balanced => match pu {
|
||||
FanCurvePU::CPU => &self.balanced.cpu,
|
||||
@@ -248,38 +213,60 @@ impl FanCurves {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_fan_curve_for_platform(name: Profile, pu: FanCurvePU, curve: &str) {
|
||||
let mut file: String = FAN_CURVE_BASE_PATH.into();
|
||||
file.push_str(pu.into());
|
||||
file.push_str(FAN_CURVE_FILENAME_PART);
|
||||
file.push_str(name.into());
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.open(&file)
|
||||
.unwrap_or_else(|_| panic!("{} not found", &file));
|
||||
|
||||
file.write_all(curve.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
pub fn set_fan_curve(&mut self, curve: FanCurve) {
|
||||
// First, set the profiles.
|
||||
Self::set_fan_curve_for_platform(curve.profile, FanCurvePU::CPU, &curve.cpu);
|
||||
match curve.profile {
|
||||
Profile::Balanced => self.balanced.cpu = curve.cpu,
|
||||
Profile::Performance => self.performance.cpu = curve.cpu,
|
||||
Profile::Quiet => self.quiet.cpu = curve.cpu,
|
||||
};
|
||||
|
||||
Self::set_fan_curve_for_platform(curve.profile, FanCurvePU::GPU, &curve.gpu);
|
||||
match curve.profile {
|
||||
Profile::Balanced => self.balanced.gpu = curve.gpu,
|
||||
Profile::Performance => self.performance.gpu = curve.gpu,
|
||||
Profile::Quiet => self.quiet.cpu = curve.gpu,
|
||||
};
|
||||
|
||||
// Any curve that was blank will have been reset, so repopulate the settings
|
||||
// Note: successfully set curves will just be re-read in.
|
||||
self.update_from_platform();
|
||||
pub fn write_and_set_fan_curve(
|
||||
&mut self,
|
||||
curve: CurveData,
|
||||
profile: Profile,
|
||||
device: &mut Device,
|
||||
) {
|
||||
match curve.fan {
|
||||
FanCurvePU::CPU => write_to_fan(&curve, '1', device),
|
||||
FanCurvePU::GPU => write_to_fan(&curve, '2', device),
|
||||
}
|
||||
match profile {
|
||||
Profile::Balanced => match curve.fan {
|
||||
FanCurvePU::CPU => self.balanced.cpu = curve,
|
||||
FanCurvePU::GPU => self.balanced.gpu = curve,
|
||||
},
|
||||
Profile::Performance => match curve.fan {
|
||||
FanCurvePU::CPU => self.performance.cpu = curve,
|
||||
FanCurvePU::GPU => self.performance.gpu = curve,
|
||||
},
|
||||
Profile::Quiet => match curve.fan {
|
||||
FanCurvePU::CPU => self.quiet.cpu = curve,
|
||||
FanCurvePU::GPU => self.quiet.gpu = curve,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_to_fan(curve: &CurveData, pwm_num: char, device: &mut Device) {
|
||||
let mut pwm = "pwmN_auto_pointN_pwm".to_string();
|
||||
|
||||
dbg!(&device);
|
||||
for (index, out) in curve.pwm.iter().enumerate() {
|
||||
unsafe {
|
||||
let buf = pwm.as_bytes_mut();
|
||||
buf[3] = pwm_num as u8;
|
||||
// Should be quite safe to unwrap as we're not going over 8
|
||||
buf[15] = char::from_digit(index as u32 + 1, 10).unwrap() as u8;
|
||||
}
|
||||
let out = out.to_string();
|
||||
dbg!(&pwm);
|
||||
dbg!(&out);
|
||||
device.set_attribute_value(&pwm, &out).unwrap();
|
||||
}
|
||||
|
||||
let mut pwm = "pwmN_auto_pointN_temp".to_string();
|
||||
|
||||
for (index, out) in curve.temp.iter().enumerate() {
|
||||
unsafe {
|
||||
let buf = pwm.as_bytes_mut();
|
||||
buf[3] = pwm_num as u8;
|
||||
// Should be quite safe to unwrap as we're not going over 8
|
||||
buf[15] = char::from_digit(index as u32 + 1, 10).unwrap() as u8;
|
||||
}
|
||||
let out = out.to_string();
|
||||
device.set_attribute_value(&pwm, &out).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user