diff --git a/Cargo.lock b/Cargo.lock index 0a29491a..c3e4811e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,6 @@ dependencies = [ "rog_anime", "rog_aura", "rog_dbus", - "rog_fan_curve 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rog_profiles", "rog_types", "tinybmp", @@ -109,9 +108,9 @@ checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2b_simd" @@ -214,7 +213,6 @@ dependencies = [ "rog_anime", "rog_aura", "rog_dbus", - "rog_fan_curve 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rog_profiles", "rog_types", "rusb", @@ -253,7 +251,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -305,7 +303,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -403,7 +401,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -497,7 +495,7 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -524,16 +522,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "intel-pstate" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dbd48c2f4886e44c137f4acb6ba3cf8df15154a2c996a65ee5e57c54a04c01f" -dependencies = [ - "smart-default", - "thiserror", -] - [[package]] name = "itoa" version = "0.4.7" @@ -548,9 +536,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" [[package]] name = "libudev-sys" @@ -620,9 +608,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "miniz_oxide" @@ -650,7 +638,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "cc", "cfg-if 0.1.10", "libc", @@ -861,7 +849,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", ] [[package]] @@ -939,26 +927,10 @@ dependencies = [ "zvariant", ] -[[package]] -name = "rog_fan_curve" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a810b86236d51df31d9098ba1a1876c9f470573f903d13b78f5ee48d4e99ee90" -dependencies = [ - "serde", -] - -[[package]] -name = "rog_fan_curve" -version = "0.1.10" -source = "git+https://github.com/Yarn/rog_fan_curve.git#d46ead0db7c8c4870dae960c3a43b4ac6ab57c2d" - [[package]] name = "rog_profiles" version = "0.1.2" dependencies = [ - "intel-pstate", - "rog_fan_curve 0.1.10 (git+https://github.com/Yarn/rog_fan_curve.git)", "serde", "serde_derive", "zvariant", @@ -1012,22 +984,22 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "1056a0db1978e9dbf0f6e4fca677f6f9143dc1c19de346f22cac23e422196834" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "13af2fbb8b60a8950d6c72a56d2095c28870367cc8e10c55e9745bac4995a2c4" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1049,7 +1021,7 @@ checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1058,17 +1030,6 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote 1.0.9", - "syn 1.0.74", -] - [[package]] name = "socket2" version = "0.4.1" @@ -1114,9 +1075,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.74" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ "proc-macro2", "quote 1.0.9", @@ -1167,7 +1128,7 @@ checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1375,7 +1336,7 @@ dependencies = [ "proc-macro-crate 0.1.5", "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1400,5 +1361,5 @@ dependencies = [ "proc-macro-crate 1.0.0", "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index 71910957..83f96401 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -1,7 +1,7 @@ use notify_rust::{Hint, Notification, NotificationHandle}; use rog_aura::AuraEffect; use rog_dbus::{DbusProxies, Signals}; -use rog_profiles::profiles::{FanLevel, Profile}; +use rog_profiles::Profile; use rog_types::gfx_vendors::GfxRequiredUserAction; use rog_types::gfx_vendors::GfxVendors; use std::error::Error; @@ -88,19 +88,17 @@ fn main() -> Result<(), Box> { } fn do_thermal_notif(profile: &Profile) -> Result> { - let fan = profile.fan_preset; - let turbo = if profile.turbo { "enabled" } else { "disabled" }; - let icon = match fan { - FanLevel::Normal => "asus_notif_yellow", - FanLevel::Boost => "asus_notif_red", - FanLevel::Silent => "asus_notif_green", + let icon = match profile { + Profile::Balanced => "asus_notif_yellow", + Profile::Performance => "asus_notif_red", + Profile::Quiet => "asus_notif_green", }; + let profile: &str = (*profile).into(); let x = Notification::new() .summary("ASUS ROG") .body(&format!( - "Thermal profile changed to {}, turbo {}", - profile.name.to_uppercase(), - turbo + "Thermal profile changed to {}", + profile.to_uppercase(), )) .hint(Hint::Resident(true)) .timeout(2000) diff --git a/asusctl/Cargo.toml b/asusctl/Cargo.toml index b9cbd593..c84f1d2b 100644 --- a/asusctl/Cargo.toml +++ b/asusctl/Cargo.toml @@ -13,7 +13,6 @@ rog_dbus = { path = "../rog-dbus" } rog_profiles = { path = "../rog-profiles" } rog_types = { path = "../rog-types" } daemon = { path = "../daemon" } -rog_fan_curve = { version = "^0.1", features = ["serde"] } gumdrop = "^0.8" yansi-term = "^0.1" diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index cf736f8c..6e41a292 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -9,11 +9,10 @@ use profiles_cli::ProfileCommand; use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN}; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClient; -use rog_profiles::profiles::Profile; use rog_types::{ gfx_vendors::{GfxRequiredUserAction, GfxVendors}, supported::{ - AnimeSupportedFunctions, FanCpuSupportedFunctions, LedSupportedFunctions, + AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions, RogBiosSupportedFunctions, }, }; @@ -152,7 +151,7 @@ fn main() -> Result<(), Box> { match parsed.command { Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?, - Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?, + Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.platform_profile, &cmd)?, Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?, Some(CliCommand::Anime(cmd)) => handle_anime(&dbus, &supported.anime_ctrl, &cmd)?, Some(CliCommand::Bios(cmd)) => handle_bios_option(&dbus, &supported.rog_bios_ctrl, &cmd)?, @@ -384,24 +383,10 @@ fn handle_led_mode( fn handle_profile( dbus: &RogDbusClient, - supported: &FanCpuSupportedFunctions, + supported: &PlatformProfileFunctions, cmd: &ProfileCommand, ) -> Result<(), Box> { - if !cmd.next - && !cmd.create // TODO - && !cmd.list - && cmd.profile.is_none() - && !cmd.active_name - && !cmd.active_data - && !cmd.profiles_data - && cmd.remove.is_none() - && cmd.curve.is_none() // TODO - && cmd.fan_preset.is_none() // TODO - && cmd.turbo.is_none() // TODO - && cmd.max_percentage.is_none() // TODO - && cmd.min_percentage.is_none() - // TODO - { + if !cmd.next && !cmd.list && !cmd.active_name && !cmd.active_data && !cmd.profiles_data { if !cmd.help { println!("Missing arg or command\n"); } @@ -411,7 +396,7 @@ fn handle_profile( .collect(); for line in usage .iter() - .filter(|line| !line.contains("--curve") || supported.fan_curve_set) + .filter(|line| !line.contains("--curve") || supported.fan_curves) { println!("{}", line); } @@ -426,78 +411,8 @@ fn handle_profile( } if cmd.next { - dbus.proxies().profile().next_fan()?; + dbus.proxies().profile().next_profile()?; } - if let Some(profile) = &cmd.remove { - dbus.proxies().profile().remove(profile)? - } - if cmd.list { - let profile_names = dbus.proxies().profile().profile_names()?; - println!("Available profiles are {:?}", profile_names); - } - if cmd.active_name { - println!( - "Active profile: {:?}", - dbus.proxies().profile().active_name()? - ); - } - if cmd.active_data { - println!("Active profile:"); - println!("{:?}", dbus.proxies().profile().active_data()?); - } - if cmd.profiles_data { - println!("Profiles:"); - for s in dbus.proxies().profile().all_profile_data()? { - println!("{:?}", s); - } - } - - let mut set_profile = false; - let mut profile = Profile::default(); - if cmd.create { - set_profile = true; - } else if let Some(ref name) = cmd.profile { - let profiles = dbus.proxies().profile().all_profile_data()?; - for p in profiles { - if p.name == *name { - profile = p; - break; - } - } - if profile.name != *name { - println!("The requested profile doesn't exist, you may need to create it"); - std::process::exit(-1); - } - } - - if let Some(turbo) = cmd.turbo { - set_profile = true; - profile.turbo = turbo; - } - if let Some(min) = cmd.min_percentage { - set_profile = true; - profile.min_percentage = min; - } - if let Some(max) = cmd.max_percentage { - set_profile = true; - profile.max_percentage = max; - } - if let Some(preset) = cmd.fan_preset { - set_profile = true; - profile.fan_preset = preset; - } - if let Some(ref curve) = cmd.curve { - set_profile = true; - profile.fan_curve = curve.as_config_string(); - } - if let Some(ref name) = cmd.profile { - set_profile = true; - profile.name = name.clone(); - } - if set_profile { - dbus.proxies().profile().new_or_modify(&profile)?; - } - Ok(()) } diff --git a/asusctl/src/profiles_cli.rs b/asusctl/src/profiles_cli.rs index ada243f1..921ba7a2 100644 --- a/asusctl/src/profiles_cli.rs +++ b/asusctl/src/profiles_cli.rs @@ -1,6 +1,4 @@ use gumdrop::Options; -use rog_fan_curve::{Curve, Fan}; -use rog_profiles::profiles::FanLevel; #[derive(Debug, Clone, Options)] pub struct ProfileCommand { @@ -8,10 +6,6 @@ pub struct ProfileCommand { pub help: bool, #[options(help = "toggle to next profile in list")] pub next: bool, - #[options(help = "create the profile if it doesn't exist")] - pub create: bool, - #[options(meta = "", help = "remove a profile by name")] - pub remove: Option, #[options(help = "list available profiles")] pub list: bool, #[options(help = "get active profile name")] @@ -20,34 +14,4 @@ pub struct ProfileCommand { pub active_data: bool, #[options(help = "get all profile data")] pub profiles_data: bool, - - // Options for profile - #[options(meta = "", help = "enable or disable cpu turbo")] - pub turbo: Option, - #[options(meta = "", help = "set min cpu scaling (intel)")] - pub min_percentage: Option, - #[options(meta = "", help = "set max cpu scaling (intel)")] - pub max_percentage: Option, - - #[options(meta = "", help = "")] - pub fan_preset: Option, - #[options( - meta = "", - parse(try_from_str = "parse_fan_curve"), - help = "set fan curve" - )] - pub curve: Option, - #[options(free)] - pub profile: Option, -} - -fn parse_fan_curve(data: &str) -> Result { - let curve = Curve::from_config_str(data)?; - if let Err(err) = curve.check_safety(Fan::Cpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - if let Err(err) = curve.check_safety(Fan::Gpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - Ok(curve) } diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index c54010ab..60e167f8 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -43,4 +43,3 @@ toml = "^0.5" # Device control sysfs-class = "^0.1.2" # used for backlight control and baord ID -rog_fan_curve = { version = "0.1", features = ["serde"] } diff --git a/daemon/src/config.rs b/daemon/src/config.rs index b194802d..5d7c73c3 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -1,8 +1,6 @@ use log::{error, info, warn}; -use rog_profiles::profiles::{FanLevel, Profile}; use rog_types::gfx_vendors::GfxVendors; use serde_derive::{Deserialize, Serialize}; -use std::collections::BTreeMap; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; @@ -20,61 +18,18 @@ pub struct Config { pub gfx_tmp_mode: Option, pub gfx_managed: bool, pub gfx_vfio_enable: bool, - pub active_profile: String, - pub toggle_profiles: Vec, - #[serde(skip)] - pub curr_fan_mode: u8, + /// Save charge limit for restoring on boot pub bat_charge_limit: u8, - pub power_profiles: BTreeMap, } impl Default for Config { fn default() -> Self { - let mut pwr = BTreeMap::new(); - pwr.insert( - "normal".into(), - Profile::new( - "normal".into(), - 0, - 100, - true, - FanLevel::Normal, - "".to_string(), - ), - ); - pwr.insert( - "boost".into(), - Profile::new( - "boost".into(), - 0, - 100, - true, - FanLevel::Boost, - "".to_string(), - ), - ); - pwr.insert( - "silent".into(), - Profile::new( - "silent".into(), - 0, - 100, - false, - FanLevel::Silent, - "".to_string(), - ), - ); - Config { gfx_mode: GfxVendors::Hybrid, gfx_tmp_mode: None, gfx_managed: true, gfx_vfio_enable: false, - active_profile: "normal".into(), - toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()], - curr_fan_mode: 0, bat_charge_limit: 100, - power_profiles: pwr, } } } @@ -125,6 +80,7 @@ impl Config { fn create_default(file: &mut File) -> Self { let config = Config::default(); + // Should be okay to unwrap this as is since it is a Default let json = serde_json::to_string_pretty(&config).unwrap(); file.write_all(json.as_bytes()) @@ -146,7 +102,6 @@ impl Config { .unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH)); // copy over serde skipped values x.gfx_tmp_mode = self.gfx_tmp_mode; - x.curr_fan_mode = self.curr_fan_mode; *self = x; } } diff --git a/daemon/src/config_anime.rs b/daemon/src/config_anime.rs deleted file mode 100644 index e189ad8e..00000000 --- a/daemon/src/config_anime.rs +++ /dev/null @@ -1,257 +0,0 @@ -use crate::VERSION; -use log::{error, info, warn}; -use rog_anime::Fade; -use rog_anime::{error::AnimeError, ActionData, ActionLoader, AnimTime, Vec2}; -use serde_derive::{Deserialize, Serialize}; -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; -use std::time::Duration; - -pub static ANIME_CONFIG_PATH: &str = "/etc/asusd/anime.conf"; -pub static ANIME_CACHE_PATH: &str = "/etc/asusd/anime-cache.conf"; - -#[derive(Deserialize, Serialize)] -pub struct AnimeConfigV341 { - pub system: Option, - pub boot: Option, - pub suspend: Option, - pub shutdown: Option, -} - -impl AnimeConfigV341 { - pub(crate) fn into_current(self) -> AnimeConfig { - AnimeConfig { - system: if let Some(ani) = self.system { - vec![ani] - } else { - vec![] - }, - boot: if let Some(ani) = self.boot { - vec![ani] - } else { - vec![] - }, - wake: if let Some(ani) = self.suspend { - vec![ani] - } else { - vec![] - }, - shutdown: if let Some(ani) = self.shutdown { - vec![ani] - } else { - vec![] - }, - brightness: 1.0, - awake_enabled: true, - boot_anim_enabled: true, - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct AnimeConfigV352 { - pub system: Vec, - pub boot: Vec, - pub wake: Vec, - pub shutdown: Vec, - pub brightness: f32, -} - -impl AnimeConfigV352 { - pub(crate) fn into_current(self) -> AnimeConfig { - AnimeConfig { - system: self.system, - boot: self.boot, - wake: self.wake, - shutdown: self.shutdown, - brightness: 1.0, - awake_enabled: true, - boot_anim_enabled: true, - } - } -} - -#[derive(Deserialize, Serialize, Default)] -pub struct AnimeConfigCached { - pub system: Vec, - pub boot: Vec, - pub wake: Vec, - pub shutdown: Vec, -} - -impl AnimeConfigCached { - pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> { - let mut sys = Vec::with_capacity(config.system.len()); - for ani in config.system.iter() { - sys.push(ActionData::from_anime_action(ani)?); - } - self.system = sys; - - let mut boot = Vec::with_capacity(config.boot.len()); - for ani in config.boot.iter() { - boot.push(ActionData::from_anime_action(ani)?); - } - self.boot = boot; - - let mut wake = Vec::with_capacity(config.wake.len()); - for ani in config.wake.iter() { - wake.push(ActionData::from_anime_action(ani)?); - } - self.wake = wake; - - let mut shutdown = Vec::with_capacity(config.shutdown.len()); - for ani in config.shutdown.iter() { - shutdown.push(ActionData::from_anime_action(ani)?); - } - self.shutdown = shutdown; - Ok(()) - } -} - -/// Config for base system actions for the anime display -#[derive(Deserialize, Serialize)] -pub struct AnimeConfig { - pub system: Vec, - pub boot: Vec, - pub wake: Vec, - pub shutdown: Vec, - pub brightness: f32, - pub awake_enabled: bool, - pub boot_anim_enabled: bool, -} - -impl Default for AnimeConfig { - fn default() -> Self { - AnimeConfig { - system: Vec::new(), - boot: Vec::new(), - wake: Vec::new(), - shutdown: Vec::new(), - brightness: 1.0, - awake_enabled: true, - boot_anim_enabled: true, - } - } -} - -impl AnimeConfig { - /// `load` will attempt to read the config, and panic if the dir is missing - pub fn load() -> Self { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(&ANIME_CONFIG_PATH) - .unwrap_or_else(|_| { - panic!( - "The file {} or directory /etc/asusd/ is missing", - ANIME_CONFIG_PATH - ) - }); // okay to cause panic here - let mut buf = String::new(); - if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len == 0 { - return AnimeConfig::create_default(&mut file); - } else { - if let Ok(data) = serde_json::from_str(&buf) { - return data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated config version to: {}", VERSION); - return config; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated config version to: {}", VERSION); - return config; - } - AnimeConfig::write_backup(buf); - warn!( - "Could not deserialise {}. Backed up as *-old", - ANIME_CONFIG_PATH - ); - } - } - AnimeConfig::create_default(&mut file) - } - - fn create_default(file: &mut File) -> Self { - // create a default config here - let config = AnimeConfig { - system: vec![], - boot: vec![ActionLoader::ImageAnimation { - file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(), - scale: 0.9, - angle: 0.65, - translation: Vec2::default(), - brightness: 1.0, - time: AnimTime::Fade(Fade::new( - Duration::from_secs(2), - Some(Duration::from_secs(2)), - Duration::from_secs(2), - )), - }], - wake: vec![ActionLoader::ImageAnimation { - file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(), - scale: 0.9, - angle: 0.65, - translation: Vec2::default(), - brightness: 1.0, - time: AnimTime::Fade(Fade::new( - Duration::from_secs(2), - Some(Duration::from_secs(2)), - Duration::from_secs(2), - )), - }], - shutdown: vec![ActionLoader::ImageAnimation { - file: "/usr/share/asusd/anime/custom/sonic-wait.gif".into(), - scale: 0.9, - angle: 0.0, - translation: Vec2::new(3.0, 2.0), - brightness: 1.0, - time: AnimTime::Infinite, - }], - brightness: 1.0, - awake_enabled: true, - boot_anim_enabled: true, - }; - // Should be okay to unwrap this as is since it is a Default - let json = serde_json::to_string_pretty(&config).unwrap(); - file.write_all(json.as_bytes()) - .unwrap_or_else(|_| panic!("Could not write {}", ANIME_CONFIG_PATH)); - config - } - - pub fn read(&mut self) { - let mut file = OpenOptions::new() - .read(true) - .open(&ANIME_CONFIG_PATH) - .unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err)); - let mut buf = String::new(); - if let Ok(l) = file.read_to_string(&mut buf) { - if l == 0 { - warn!("File is empty {}", ANIME_CONFIG_PATH); - } else { - let x: AnimeConfig = serde_json::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", ANIME_CONFIG_PATH)); - *self = x; - } - } - } - - pub fn write(&self) { - let mut file = File::create(ANIME_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()) - .unwrap_or_else(|err| error!("Could not write config: {}", err)); - } - - fn write_backup(buf: String) { - let mut path = ANIME_CONFIG_PATH.to_string(); - path.push_str("-old"); - let mut file = File::create(&path).expect("Couldn't overwrite config"); - file.write_all(buf.as_bytes()) - .unwrap_or_else(|err| error!("Could not write config: {}", err)); - } -} diff --git a/daemon/src/config_aura.rs b/daemon/src/config_aura.rs deleted file mode 100644 index 6e5d3778..00000000 --- a/daemon/src/config_aura.rs +++ /dev/null @@ -1,267 +0,0 @@ -use crate::laptops::LaptopLedData; -use log::{error, info, warn}; -use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness}; -use serde_derive::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; - -pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; - -#[derive(Deserialize, Serialize)] -pub struct AuraConfigV320 { - pub brightness: u32, - pub current_mode: AuraModeNum, - pub builtins: BTreeMap, - pub multizone: Option, -} - -impl AuraConfigV320 { - pub(crate) fn into_current(self) -> AuraConfig { - AuraConfig { - brightness: ::from(self.brightness), - current_mode: self.current_mode, - builtins: self.builtins, - multizone: self.multizone, - awake_enabled: true, - sleep_anim_enabled: true, - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct AuraConfigV352 { - pub brightness: LedBrightness, - pub current_mode: AuraModeNum, - pub builtins: BTreeMap, - pub multizone: Option, -} - -impl AuraConfigV352 { - pub(crate) fn into_current(self) -> AuraConfig { - AuraConfig { - brightness: self.brightness, - current_mode: self.current_mode, - builtins: self.builtins, - multizone: self.multizone, - awake_enabled: true, - sleep_anim_enabled: true, - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct AuraConfig { - pub brightness: LedBrightness, - pub current_mode: AuraModeNum, - pub builtins: BTreeMap, - pub multizone: Option, - pub awake_enabled: bool, - pub sleep_anim_enabled: bool, -} - -impl Default for AuraConfig { - fn default() -> Self { - AuraConfig { - brightness: LedBrightness::Med, - current_mode: AuraModeNum::Static, - builtins: BTreeMap::new(), - multizone: None, - awake_enabled: true, - sleep_anim_enabled: true, - } - } -} - -impl AuraConfig { - /// `load` will attempt to read the config, and panic if the dir is missing - pub fn load(supported_led_modes: &LaptopLedData) -> Self { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(&AURA_CONFIG_PATH) - .unwrap_or_else(|_| { - panic!( - "The file {} or directory /etc/asusd/ is missing", - AURA_CONFIG_PATH - ) - }); // okay to cause panic here - let mut buf = String::new(); - if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len == 0 { - return AuraConfig::create_default(&mut file, supported_led_modes); - } else { - if let Ok(data) = serde_json::from_str(&buf) { - return data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated AuraConfig version"); - return config; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated AuraConfig version"); - return config; - } - warn!("Could not deserialise {}", AURA_CONFIG_PATH); - panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH); - } - } - AuraConfig::create_default(&mut file, supported_led_modes) - } - - fn create_default(file: &mut File, support_data: &LaptopLedData) -> Self { - // create a default config here - let mut config = AuraConfig::default(); - - for n in &support_data.standard { - config - .builtins - .insert(*n, AuraEffect::default_with_mode(*n)); - } - - // Should be okay to unwrap this as is since it is a Default - let json = serde_json::to_string(&config).unwrap(); - file.write_all(json.as_bytes()) - .unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH)); - config - } - - pub fn read(&mut self) { - let mut file = OpenOptions::new() - .read(true) - .open(&AURA_CONFIG_PATH) - .unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err)); - let mut buf = String::new(); - if let Ok(l) = file.read_to_string(&mut buf) { - if l == 0 { - warn!("File is empty {}", AURA_CONFIG_PATH); - } else { - let x: AuraConfig = serde_json::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH)); - *self = x; - } - } - } - - pub fn write(&self) { - let mut file = File::create(AURA_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()) - .unwrap_or_else(|err| error!("Could not write config: {}", err)); - } - - /// Multipurpose, will accept AuraEffect with zones and put in the correct store - pub fn set_builtin(&mut self, effect: AuraEffect) { - match effect.zone() { - AuraZone::None => { - self.builtins.insert(*effect.mode(), effect); - } - _ => { - if let Some(multi) = self.multizone.as_mut() { - multi.set(effect) - } - } - } - } - - pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect; 4]> { - if let Some(multi) = &self.multizone { - if aura_type == AuraModeNum::Static { - return Some(multi.static_()); - } else if aura_type == AuraModeNum::Breathe { - return Some(multi.breathe()); - } - } - None - } -} - -#[derive(Deserialize, Serialize)] -pub struct AuraMultiZone { - static_: [AuraEffect; 4], - breathe: [AuraEffect; 4], -} - -impl AuraMultiZone { - pub fn set(&mut self, effect: AuraEffect) { - if effect.mode == AuraModeNum::Static { - match effect.zone { - AuraZone::None => {} - AuraZone::One => self.static_[0] = effect, - AuraZone::Two => self.static_[1] = effect, - AuraZone::Three => self.static_[2] = effect, - AuraZone::Four => self.static_[3] = effect, - } - } else if effect.mode == AuraModeNum::Breathe { - match effect.zone { - AuraZone::None => {} - AuraZone::One => self.breathe[0] = effect, - AuraZone::Two => self.breathe[1] = effect, - AuraZone::Three => self.breathe[2] = effect, - AuraZone::Four => self.breathe[3] = effect, - } - } - } - - pub fn static_(&self) -> &[AuraEffect; 4] { - &self.static_ - } - - pub fn breathe(&self) -> &[AuraEffect; 4] { - &self.breathe - } -} - -impl Default for AuraMultiZone { - fn default() -> Self { - Self { - static_: [ - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::One, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::Two, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::Three, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::Four, - ..Default::default() - }, - ], - breathe: [ - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::One, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::Two, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::Three, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::Four, - ..Default::default() - }, - ], - } - } -} diff --git a/daemon/src/config_old.rs b/daemon/src/config_old.rs index 1a1fe159..49254b3e 100644 --- a/daemon/src/config_old.rs +++ b/daemon/src/config_old.rs @@ -1,5 +1,3 @@ -use rog_fan_curve::Curve; -use rog_profiles::profiles::Profile; use rog_types::gfx_vendors::GfxVendors; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -31,11 +29,7 @@ impl ConfigV317 { gfx_tmp_mode: None, gfx_managed: self.gfx_managed, gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), } } } @@ -59,11 +53,7 @@ impl ConfigV324 { gfx_tmp_mode: None, gfx_managed: self.gfx_managed, gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), } } } @@ -88,11 +78,7 @@ impl ConfigV341 { gfx_tmp_mode: None, gfx_managed: self.gfx_managed, gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), } } } @@ -119,43 +105,32 @@ impl ConfigV352 { gfx_tmp_mode: None, gfx_managed: self.gfx_managed, gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), } } } +#[derive(Deserialize, Serialize)] +pub struct ConfigV372 { + pub gfx_mode: GfxVendors, + /// Only for informational purposes. + #[serde(skip)] + pub gfx_tmp_mode: Option, + pub gfx_managed: bool, + pub gfx_vfio_enable: bool, + pub active_profile: String, + pub toggle_profiles: Vec, + #[serde(skip)] + pub curr_fan_mode: u8, + pub bat_charge_limit: u8, + pub power_profiles: BTreeMap, +} + #[derive(Debug, Clone, Deserialize, Serialize)] pub struct ProfileV317 { pub min_percentage: u8, pub max_percentage: u8, pub turbo: bool, pub fan_preset: u8, - pub fan_curve: Option, -} - -impl ProfileV317 { - fn into_current(self, name: String) -> Profile { - Profile { - name, - min_percentage: self.min_percentage, - max_percentage: self.max_percentage, - turbo: self.turbo, - fan_preset: self.fan_preset.into(), - fan_curve: self - .fan_curve - .map_or_else(|| "".to_string(), |c| c.as_config_string()), - } - } - - fn transform_map(map: BTreeMap) -> BTreeMap { - let mut new_map = BTreeMap::new(); - map.iter().for_each(|(k, v)| { - new_map.insert(k.to_string(), v.clone().into_current(k.to_string())); - }); - new_map - } + pub fan_curve: Option<()>, } diff --git a/daemon/src/ctrl_anime.rs b/daemon/src/ctrl_anime.rs deleted file mode 100644 index e1400f2e..00000000 --- a/daemon/src/ctrl_anime.rs +++ /dev/null @@ -1,456 +0,0 @@ -use log::{error, info, warn}; -use logind_zbus::ManagerProxy; -use rog_anime::{ - usb::{ - pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID, - VENDOR_ID, - }, - ActionData, AnimeDataBuffer, AnimePacketType, AnimePowerStates, ANIME_DATA_LEN, -}; -use rog_types::supported::AnimeSupportedFunctions; -use rusb::{Device, DeviceHandle}; -use std::{ - error::Error, - sync::{Arc, Mutex}, - thread::sleep, -}; -use std::{ - sync::atomic::{AtomicBool, Ordering}, - time::Duration, -}; -use zbus::{dbus_interface, Connection}; -use zvariant::ObjectPath; - -use crate::{ - config_anime::{AnimeConfig, AnimeConfigCached}, - error::RogError, - GetSupported, -}; - -impl GetSupported for CtrlAnime { - type A = AnimeSupportedFunctions; - - fn get_supported() -> Self::A { - AnimeSupportedFunctions(CtrlAnime::get_device(VENDOR_ID, PROD_ID).is_ok()) - } -} - -pub struct CtrlAnime { - handle: DeviceHandle, - cache: AnimeConfigCached, - config: AnimeConfig, - // set to force thread to exit - thread_exit: Arc, - // Set to false when the thread exits - thread_running: Arc, -} - -impl CtrlAnime { - #[inline] - pub fn new(config: AnimeConfig) -> Result> { - // We don't expect this ID to ever change - let device = CtrlAnime::get_device(0x0b05, 0x193b)?; - - let mut device = device.open()?; - device.reset()?; - - device.set_auto_detach_kernel_driver(true).map_err(|err| { - error!("Auto-detach kernel driver failed: {}", err); - err - })?; - - device.claim_interface(0).map_err(|err| { - error!("Could not claim device interface: {}", err); - err - })?; - - info!("Device has an AniMe Matrix display"); - let mut cache = AnimeConfigCached::default(); - cache.init_from_config(&config)?; - - let ctrl = CtrlAnime { - handle: device, - cache, - config, - thread_exit: Arc::new(AtomicBool::new(false)), - thread_running: Arc::new(AtomicBool::new(false)), - }; - ctrl.do_initialization(); - - Ok(ctrl) - } - - fn get_device(vendor: u16, product: u16) -> Result, rusb::Error> { - for device in rusb::devices()?.iter() { - let device_desc = device.device_descriptor()?; - if device_desc.vendor_id() == vendor && device_desc.product_id() == product { - return Ok(device); - } - } - Err(rusb::Error::NoDevice) - } - - /// Start an action thread. This is classed as a singleton and there should be only - /// one running - so the thread uses atomics to signal run/exit. - /// - /// Because this also writes to the usb device, other write tries (display only) *must* - /// get the mutex lock and set the thread_exit atomic. - fn run_thread(inner: Arc>, actions: Vec, mut once: bool) { - if actions.is_empty() { - warn!("AniMe system actions was empty"); - return; - } - // Loop rules: - // - Lock the mutex **only when required**. That is, the lock must be held for the shortest duration possible. - // - An AtomicBool used for thread exit should be checked in every loop, including nested - - // The only reason for this outer thread is to prevent blocking while waiting for the - // next spawned thread to exit - std::thread::Builder::new() - .name("AniMe system thread start".into()) - .spawn(move || { - info!("AniMe system thread started"); - // Getting copies of these Atomics is done *in* the thread to ensure - // we don't block other threads/main - let thread_exit; - let thread_running; - // First two loops are to ensure we *do* aquire a lock on the mutex - // The reason the loop is required is because the USB writes can block - // for up to 10ms. We can't fail to get the atomics. - loop { - if let Ok(lock) = inner.try_lock() { - thread_exit = lock.thread_exit.clone(); - thread_running = lock.thread_running.clone(); - // Make any running loop exit first - thread_exit.store(true, Ordering::SeqCst); - break; - } - } - - loop { - // wait for other threads to set not running so we know they exited - if !thread_running.load(Ordering::SeqCst) { - thread_exit.store(false, Ordering::SeqCst); - info!("AniMe forced a thread to exit"); - break; - } - } - - 'main: loop { - if thread_exit.load(Ordering::SeqCst) { - break 'main; - } - for action in actions.iter() { - match action { - ActionData::Animation(frames) => { - rog_anime::run_animation(frames, thread_exit.clone(), &|frame| { - if let Ok(lock) = inner.try_lock() { - lock.write_data_buffer(frame); - } - }) - .unwrap(); - - if thread_exit.load(Ordering::SeqCst) { - break 'main; - } - } - ActionData::Image(image) => { - once = false; - if let Ok(lock) = inner.try_lock() { - lock.write_data_buffer(image.as_ref().clone()) - } - } - ActionData::Pause(duration) => sleep(*duration), - ActionData::AudioEq => {} - ActionData::SystemInfo => {} - ActionData::TimeDate => {} - ActionData::Matrix => {} - } - } - if once || actions.is_empty() { - break 'main; - } - } - // Clear the display on exit - if let Ok(lock) = inner.try_lock() { - let data = AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec()); - lock.write_data_buffer(data); - } - // Loop ended, set the atmonics - thread_exit.store(false, Ordering::SeqCst); - thread_running.store(false, Ordering::SeqCst); - info!("AniMe system thread exited"); - }) - .map(|err| info!("AniMe system thread: {:?}", err)) - .ok(); - } - - fn write_bytes(&self, message: &[u8]) { - match self.handle.write_control( - 0x21, // request_type - 0x09, // request - 0x35e, // value - 0x00, // index - message, - Duration::from_millis(200), - ) { - Ok(_) => {} - Err(err) => match err { - rusb::Error::Timeout => {} - _ => error!("Failed to write to led interrupt: {}", err), - }, - } - } - - /// Write only a data packet. This will modify the leds brightness using the - /// global brightness set in config. - fn write_data_buffer(&self, mut buffer: AnimeDataBuffer) { - for led in buffer.get_mut()[7..].iter_mut() { - let mut bright = *led as f32 * self.config.brightness; - if bright > 254.0 { - bright = 254.0; - } - *led = bright as u8; - } - let data = AnimePacketType::from(buffer); - for row in data.iter() { - self.write_bytes(row); - } - self.write_bytes(&pkt_for_flush()); - } - - fn do_initialization(&self) { - let pkts = pkts_for_init(); - self.write_bytes(&pkts[0]); - self.write_bytes(&pkts[1]); - } -} - -pub struct CtrlAnimeTask<'a> { - inner: Arc>, - _c: Connection, - manager: ManagerProxy<'a>, -} - -impl<'a> CtrlAnimeTask<'a> { - pub fn new(inner: Arc>) -> Self { - let connection = Connection::new_system().unwrap(); - - let manager = ManagerProxy::new(&connection).unwrap(); - - let c1 = inner.clone(); - // Run this action when the system starts shutting down - manager - .connect_prepare_for_shutdown(move |shutdown| { - if shutdown { - 'outer: loop { - if let Ok(lock) = c1.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - CtrlAnime::run_thread(c1.clone(), lock.cache.shutdown.clone(), false); - break 'outer; - } - } - } - Ok(()) - }) - .map_err(|err| { - warn!("CtrlAnimeTask: new() {}", err); - err - }) - .ok(); - - let c1 = inner.clone(); - // Run this action when the system wakes up from sleep - manager - .connect_prepare_for_sleep(move |sleep| { - if !sleep { - // wait a fraction for things to wake up properly - std::thread::sleep(Duration::from_millis(100)); - 'outer: loop { - if let Ok(lock) = c1.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - CtrlAnime::run_thread(c1.clone(), lock.cache.wake.clone(), true); - break 'outer; - } - } - } - Ok(()) - }) - .map_err(|err| { - warn!("CtrlAnimeTask: new() {}", err); - err - }) - .ok(); - - Self { - inner, - _c: connection, - manager, - } - } -} - -impl<'a> crate::CtrlTask for CtrlAnimeTask<'a> { - fn do_task(&self) -> Result<(), RogError> { - if let Ok(mut lock) = self.inner.try_lock() { - // Refresh the config and cache incase the user has edited it - let config = AnimeConfig::load(); - lock.cache - .init_from_config(&config) - .map_err(|err| { - warn!("CtrlAnimeTask: do_task {}", err); - err - }) - .ok(); - } - - // Check for signals on each task iteration, this will run the callbacks - // if any signal is recieved - self.manager.next_signal()?; - Ok(()) - } -} - -pub struct CtrlAnimeReloader(pub Arc>); - -impl crate::Reloadable for CtrlAnimeReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_on(lock.config.awake_enabled)); - lock.write_bytes(&pkt_for_apply()); - lock.write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled)); - lock.write_bytes(&pkt_for_apply()); - - let action = lock.cache.boot.clone(); - CtrlAnime::run_thread(self.0.clone(), action, true); - } - Ok(()) - } -} - -pub struct CtrlAnimeZbus(pub Arc>); - -/// The struct with the main dbus methods requires this trait -impl crate::ZbusAdd for CtrlAnimeZbus { - fn add_to_server(self, server: &mut zbus::ObjectServer) { - server - .at( - &ObjectPath::from_str_unchecked("/org/asuslinux/Anime"), - self, - ) - .map_err(|err| { - warn!("CtrlAnimeDisplay: add_to_server {}", err); - err - }) - .ok(); - } -} - -// None of these calls can be guarnateed to succeed unless we loop until okay -// If the try_lock *does* succeed then any other thread trying to lock will not grab it -// until we finish. -#[dbus_interface(name = "org.asuslinux.Daemon")] -impl CtrlAnimeZbus { - /// Writes a data stream of length. Will force system thread to exit until it is restarted - fn write(&self, input: AnimeDataBuffer) { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - lock.write_data_buffer(input); - break 'outer; - } - } - } - - /// Set the global AniMe brightness - fn set_brightness(&self, bright: f32) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - let mut bright = bright; - if bright < 0.0 { - bright = 0.0 - } else if bright > 254.0 { - bright = 254.0; - } - lock.config.brightness = bright; - lock.config.write(); - break 'outer; - } - } - } - - /// Set whether the AniMe is displaying images/data - fn set_on_off(&self, status: bool) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_on(status)); - lock.config.awake_enabled = status; - lock.config.write(); - - let states = AnimePowerStates { - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }; - self.notify_power_states(&states) - .unwrap_or_else(|err| warn!("{}", err)); - break 'outer; - } - } - } - - /// Set whether the AniMe will show boot, suspend, or off animations - fn set_boot_on_off(&self, on: bool) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_boot(on)); - lock.write_bytes(&pkt_for_apply()); - lock.config.boot_anim_enabled = on; - lock.config.write(); - - let states = AnimePowerStates { - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }; - self.notify_power_states(&states) - .unwrap_or_else(|err| warn!("{}", err)); - break 'outer; - } - } - } - - /// The main loop is the base system set action if the user isn't running - /// the user daemon - fn run_main_loop(&self, start: bool) { - if start { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); - break 'outer; - } - } - } - } - - /// Get status of if the AniMe LEDs are on - #[dbus_interface(property)] - fn awake_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.awake_enabled; - } - true - } - - /// Get the status of if factory system-status animations are enabled - #[dbus_interface(property)] - fn boot_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.boot_anim_enabled; - } - true - } - - /// Notify listeners of the status of AniMe LED power and factory system-status animations - #[dbus_interface(signal)] - fn notify_power_states(&self, data: &AnimePowerStates) -> zbus::Result<()>; -} diff --git a/daemon/src/ctrl_gfx/controller.rs b/daemon/src/ctrl_gfx/controller.rs index 6a2f23b2..9fa83233 100644 --- a/daemon/src/ctrl_gfx/controller.rs +++ b/daemon/src/ctrl_gfx/controller.rs @@ -264,13 +264,16 @@ impl CtrlGraphics { let unbinds = devices.iter().map(|dev| dev.unbind()); // Remove NVIDIA graphics devices and their functions let removes = devices.iter().map(|dev| dev.remove()); - unbinds.chain(removes).collect::>() + unbinds + .chain(removes) + .collect::>() .map_err(|err| RogError::Command("device unbind error".into(), err)) } fn unbind_only(devices: &[GraphicsDevice]) -> Result<(), RogError> { let unbinds = devices.iter().map(|dev| dev.unbind()); - unbinds.collect::>() + unbinds + .collect::>() .map_err(|err| RogError::Command("device unbind error".into(), err)) } diff --git a/daemon/src/ctrl_gfx/mod.rs b/daemon/src/ctrl_gfx/mod.rs index 2a2e997b..183fc2a9 100644 --- a/daemon/src/ctrl_gfx/mod.rs +++ b/daemon/src/ctrl_gfx/mod.rs @@ -4,7 +4,7 @@ pub mod controller; pub mod system; -pub mod zbus_gfx; +pub mod zbus; const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"]; diff --git a/daemon/src/ctrl_gfx/zbus_gfx.rs b/daemon/src/ctrl_gfx/zbus_gfx.rs deleted file mode 100644 index 8c66ac1d..00000000 --- a/daemon/src/ctrl_gfx/zbus_gfx.rs +++ /dev/null @@ -1,56 +0,0 @@ -use ::zbus::dbus_interface; -use log::{error, info, warn}; -use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; -use zvariant::ObjectPath; - -use crate::ZbusAdd; - -use super::controller::CtrlGraphics; - -#[dbus_interface(name = "org.asuslinux.Daemon")] -impl CtrlGraphics { - fn vendor(&self) -> zbus::fdo::Result { - self.get_gfx_mode().map_err(|err| { - error!("GFX: {}", err); - zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) - }) - } - - fn power(&self) -> zbus::fdo::Result { - Self::get_runtime_status().map_err(|err| { - error!("GFX: {}", err); - zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) - }) - } - - fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result { - info!("GFX: Switching gfx mode to {}", <&str>::from(vendor)); - let msg = self.set_gfx_mode(vendor).map_err(|err| { - error!("GFX: {}", err); - zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) - })?; - self.notify_gfx(&vendor) - .unwrap_or_else(|err| warn!("GFX: {}", err)); - self.notify_action(&msg) - .unwrap_or_else(|err| warn!("GFX: {}", err)); - Ok(msg) - } - - #[dbus_interface(signal)] - fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {} - - #[dbus_interface(signal)] - fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {} -} - -impl ZbusAdd for CtrlGraphics { - fn add_to_server(self, server: &mut zbus::ObjectServer) { - server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self) - .map_err(|err| { - warn!("GFX: CtrlGraphics: add_to_server {}", err); - err - }) - .ok(); - } -} diff --git a/daemon/src/ctrl_leds/controller.rs b/daemon/src/ctrl_leds/controller.rs deleted file mode 100644 index d9e0a64f..00000000 --- a/daemon/src/ctrl_leds/controller.rs +++ /dev/null @@ -1,394 +0,0 @@ -// Only these two packets must be 17 bytes -static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness"; - -use crate::{ - config_aura::AuraConfig, - error::RogError, - laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, - CtrlTask, -}; -use log::{info, warn}; -use logind_zbus::ManagerProxy; -use rog_aura::{ - usb::{ - LED_APPLY, LED_AWAKE_OFF_SLEEP_OFF, LED_AWAKE_OFF_SLEEP_ON, LED_AWAKE_ON_SLEEP_OFF, - LED_AWAKE_ON_SLEEP_ON, LED_SET, - }, - AuraEffect, LedBrightness, LED_MSG_LEN, -}; -use rog_types::supported::LedSupportedFunctions; -use std::io::{Read, Write}; -use std::path::Path; -use std::sync::Arc; -use std::sync::Mutex; -use std::{fs::OpenOptions, thread::spawn}; -use zbus::Connection; - -use crate::GetSupported; - -impl GetSupported for CtrlKbdLed { - type A = LedSupportedFunctions; - - fn get_supported() -> Self::A { - // let mode = <&str>::from(&::from(*mode)); - let multizone_led_mode = false; - let per_key_led_mode = false; - let laptop = LaptopLedData::get_data(); - let stock_led_modes = laptop.standard; - - LedSupportedFunctions { - brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), - stock_led_modes, - multizone_led_mode, - per_key_led_mode, - } - } -} - -pub struct CtrlKbdLed { - pub led_node: Option, - pub bright_node: String, - pub supported_modes: LaptopLedData, - pub flip_effect_write: bool, - pub config: AuraConfig, -} - -pub struct CtrlKbdLedTask<'a> { - inner: Arc>, - _c: Connection, - manager: ManagerProxy<'a>, -} - -impl<'a> CtrlKbdLedTask<'a> { - pub fn new(inner: Arc>) -> Self { - let connection = Connection::new_system().unwrap(); - - let manager = ManagerProxy::new(&connection).unwrap(); - - let c1 = inner.clone(); - // Run this action when the system wakes up from sleep - manager - .connect_prepare_for_sleep(move |sleep| { - if !sleep { - let c1 = c1.clone(); - spawn(move || { - // wait a fraction for things to wake up properly - //std::thread::sleep(Duration::from_millis(100)); - loop { - if let Ok(ref mut lock) = c1.try_lock() { - lock.set_brightness(lock.config.brightness).ok(); - break; - } - } - }); - } - Ok(()) - }) - .map_err(|err| { - warn!("CtrlAnimeTask: new() {}", err); - err - }) - .ok(); - - Self { - inner, - _c: connection, - manager, - } - } - - fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> { - let mut file = OpenOptions::new() - .read(true) - .open(&lock.bright_node) - .map_err(|err| match err.kind() { - std::io::ErrorKind::NotFound => { - RogError::MissingLedBrightNode((&lock.bright_node).into(), err) - } - _ => RogError::Path((&lock.bright_node).into(), err), - })?; - let mut buf = [0u8; 1]; - file.read_exact(&mut buf) - .map_err(|err| RogError::Read("buffer".into(), err))?; - if let Some(num) = char::from(buf[0]).to_digit(10) { - if lock.config.brightness != num.into() { - lock.config.read(); - lock.config.brightness = num.into(); - lock.config.write(); - } - return Ok(()); - } - Err(RogError::ParseLed) - } -} - -impl<'a> CtrlTask for CtrlKbdLedTask<'a> { - fn do_task(&self) -> Result<(), RogError> { - self.manager.next_signal()?; - if let Ok(ref mut lock) = self.inner.try_lock() { - return Self::update_config(lock); - } - Ok(()) - } -} - -pub struct CtrlKbdLedReloader(pub Arc>); - -impl crate::Reloadable for CtrlKbdLedReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut ctrl) = self.0.try_lock() { - let current = ctrl.config.current_mode; - if let Some(mode) = ctrl.config.builtins.get(¤t).cloned() { - ctrl.do_command(mode).ok(); - } - - ctrl.set_states_enabled(ctrl.config.awake_enabled, ctrl.config.sleep_anim_enabled) - .map_err(|err| warn!("{}", err)) - .ok(); - } - Ok(()) - } -} - -pub struct CtrlKbdLedZbus(pub Arc>); - -impl CtrlKbdLedZbus { - pub fn new(inner: Arc>) -> Self { - Self(inner) - } -} - -impl CtrlKbdLed { - #[inline] - pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result { - // TODO: return error if *all* nodes are None - let mut led_node = None; - for prod in ASUS_KEYBOARD_DEVICES.iter() { - match Self::find_led_node(prod) { - Ok(node) => { - led_node = Some(node); - break; - } - Err(err) => warn!("led_node: {}", err), - } - } - - let bright_node = Self::get_kbd_bright_path(); - - if led_node.is_none() && bright_node.is_none() { - return Err(RogError::MissingFunction( - "All keyboard features missing, you may require a v5.11 series kernel or newer" - .into(), - )); - } - - if bright_node.is_none() { - return Err(RogError::MissingFunction( - "No brightness control, you may require a v5.11 series kernel or newer".into(), - )); - } - - let ctrl = CtrlKbdLed { - led_node, - bright_node: bright_node.unwrap(), // If was none then we already returned above - supported_modes, - flip_effect_write: false, - config, - }; - Ok(ctrl) - } - - fn get_kbd_bright_path() -> Option { - if Path::new(KBD_BRIGHT_PATH).exists() { - return Some(KBD_BRIGHT_PATH.to_string()); - } - None - } - - pub(super) fn get_brightness(&self) -> Result { - let mut file = OpenOptions::new() - .read(true) - .open(&self.bright_node) - .map_err(|err| match err.kind() { - std::io::ErrorKind::NotFound => { - RogError::MissingLedBrightNode((&self.bright_node).into(), err) - } - _ => RogError::Path((&self.bright_node).into(), err), - })?; - let mut buf = [0u8; 1]; - file.read_exact(&mut buf) - .map_err(|err| RogError::Read("buffer".into(), err))?; - Ok(buf[0]) - } - - pub(super) fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> { - let path = Path::new(&self.bright_node); - let mut file = - OpenOptions::new() - .write(true) - .open(&path) - .map_err(|err| match err.kind() { - std::io::ErrorKind::NotFound => { - RogError::MissingLedBrightNode((&self.bright_node).into(), err) - } - _ => RogError::Path((&self.bright_node).into(), err), - })?; - file.write_all(&[brightness.as_char_code()]) - .map_err(|err| RogError::Read("buffer".into(), err))?; - Ok(()) - } - - /// Set if awake/on LED active, and/or sleep animation active - pub(super) fn set_states_enabled(&self, awake: bool, sleep: bool) -> Result<(), RogError> { - let bytes = if awake && sleep { - LED_AWAKE_ON_SLEEP_ON - } else if awake && !sleep { - LED_AWAKE_ON_SLEEP_OFF - } else if !awake && sleep { - LED_AWAKE_OFF_SLEEP_ON - } else if !awake && !sleep { - LED_AWAKE_OFF_SLEEP_OFF - } else { - LED_AWAKE_ON_SLEEP_ON - }; - self.write_bytes(&bytes)?; - self.write_bytes(&LED_SET)?; - // Changes won't persist unless apply is set - self.write_bytes(&LED_APPLY)?; - Ok(()) - } - - fn find_led_node(id_product: &str) -> Result { - let mut enumerator = udev::Enumerator::new().map_err(|err| { - warn!("{}", err); - RogError::Udev("enumerator failed".into(), err) - })?; - enumerator.match_subsystem("hidraw").map_err(|err| { - warn!("{}", err); - RogError::Udev("match_subsystem failed".into(), err) - })?; - - for device in enumerator.scan_devices().map_err(|err| { - warn!("{}", err); - RogError::Udev("scan_devices failed".into(), err) - })? { - if let Some(parent) = device - .parent_with_subsystem_devtype("usb", "usb_device") - .map_err(|err| { - warn!("{}", err); - RogError::Udev("parent_with_subsystem_devtype failed".into(), err) - })? - { - if parent - .attribute_value("idProduct") - .ok_or_else(|| RogError::NotFound("LED idProduct".into()))? - == id_product - { - if let Some(dev_node) = device.devnode() { - info!("Using device at: {:?} for LED control", dev_node); - return Ok(dev_node.to_string_lossy().to_string()); - } - } - } - } - Err(RogError::MissingFunction( - "ASUS LED device node not found".into(), - )) - } - - pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> { - self.set_and_save(mode) - } - - /// Should only be used if the bytes you are writing are verified correct - #[inline] - fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> { - if let Some(led_node) = &self.led_node { - if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) { - // println!("write: {:02x?}", &message); - return file - .write_all(message) - .map_err(|err| RogError::Write("write_bytes".into(), err)); - } - } - Err(RogError::NotSupported) - } - - /// Write an effect block - #[inline] - fn _write_effect(&mut self, effect: &[Vec]) -> Result<(), RogError> { - if self.flip_effect_write { - for row in effect.iter().rev() { - self.write_bytes(row)?; - } - } else { - for row in effect.iter() { - self.write_bytes(row)?; - } - } - self.flip_effect_write = !self.flip_effect_write; - Ok(()) - } - - /// Used to set a builtin mode and save the settings for it - /// - /// This needs to be universal so that settings applied by dbus stick - #[inline] - fn set_and_save(&mut self, mode: AuraEffect) -> Result<(), RogError> { - self.config.read(); - self.write_mode(&mode)?; - self.config.current_mode = *mode.mode(); - self.config.set_builtin(mode); - self.config.write(); - Ok(()) - } - - #[inline] - pub(super) fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> { - let current = self.config.current_mode; - if let Some(idx) = self - .supported_modes - .standard - .iter() - .position(|v| *v == current) - { - let mut idx = idx; - // goes past end of array - if reverse { - if idx == 0 { - idx = self.supported_modes.standard.len() - 1; - } else { - idx -= 1; - } - } else { - idx += 1; - if idx == self.supported_modes.standard.len() { - idx = 0; - } - } - let next = self.supported_modes.standard[idx]; - - self.config.read(); - if let Some(data) = self.config.builtins.get(&next) { - self.write_mode(data)?; - self.config.current_mode = next; - } - self.config.write(); - } - - Ok(()) - } - - #[inline] - fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> { - if !self.supported_modes.standard.contains(mode.mode()) { - return Err(RogError::NotSupported); - } - let bytes: [u8; LED_MSG_LEN] = mode.into(); - self.write_bytes(&bytes)?; - self.write_bytes(&LED_SET)?; - // Changes won't persist unless apply is set - self.write_bytes(&LED_APPLY)?; - Ok(()) - } -} diff --git a/daemon/src/ctrl_leds/mod.rs b/daemon/src/ctrl_leds/mod.rs deleted file mode 100644 index 65359c9f..00000000 --- a/daemon/src/ctrl_leds/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod controller; -pub mod zbus; diff --git a/daemon/src/ctrl_leds/zbus.rs b/daemon/src/ctrl_leds/zbus.rs deleted file mode 100644 index d96fa095..00000000 --- a/daemon/src/ctrl_leds/zbus.rs +++ /dev/null @@ -1,165 +0,0 @@ -use log::{error, warn}; -use rog_aura::{AuraEffect, LedBrightness, LedPowerStates}; -use zbus::dbus_interface; -use zvariant::ObjectPath; - -use super::controller::CtrlKbdLedZbus; - -impl crate::ZbusAdd for CtrlKbdLedZbus { - fn add_to_server(self, server: &mut zbus::ObjectServer) { - server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self) - .map_err(|err| { - error!("DbusKbdLed: add_to_server {}", err); - }) - .ok(); - } -} - -/// The main interface for changing, reading, or notfying signals -/// -/// LED commands are split between Brightness, Modes, Per-Key -#[dbus_interface(name = "org.asuslinux.Daemon")] -impl CtrlKbdLedZbus { - /// Set the keyboard brightness level (0-3) - fn set_brightness(&mut self, brightness: LedBrightness) { - if let Ok(ctrl) = self.0.try_lock() { - ctrl.set_brightness(brightness) - .map_err(|err| warn!("{}", err)) - .ok(); - } - } - - /// Set the keyboard LED to enabled while the device is awake - fn set_awake_enabled(&mut self, enabled: bool) { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.set_states_enabled(enabled, ctrl.config.sleep_anim_enabled) - .map_err(|err| warn!("{}", err)) - .ok(); - ctrl.config.awake_enabled = enabled; - ctrl.config.write(); - - let states = LedPowerStates { - enabled: ctrl.config.awake_enabled, - sleep_anim_enabled: ctrl.config.sleep_anim_enabled, - }; - self.notify_power_states(&states) - .unwrap_or_else(|err| warn!("{}", err)); - } - } - - /// Set the keyboard LED suspend animation to enabled while the device is suspended - fn set_sleep_enabled(&mut self, enabled: bool) { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.set_states_enabled(ctrl.config.awake_enabled, enabled) - .map_err(|err| warn!("{}", err)) - .ok(); - ctrl.config.sleep_anim_enabled = enabled; - ctrl.config.write(); - let states = LedPowerStates { - enabled: ctrl.config.awake_enabled, - sleep_anim_enabled: ctrl.config.sleep_anim_enabled, - }; - self.notify_power_states(&states) - .unwrap_or_else(|err| warn!("{}", err)); - } - } - - fn set_led_mode(&mut self, effect: AuraEffect) { - if let Ok(mut ctrl) = self.0.try_lock() { - match ctrl.do_command(effect) { - Ok(_) => { - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - self.notify_led(mode.clone()) - .unwrap_or_else(|err| warn!("{}", err)); - } - } - Err(err) => { - warn!("{}", err); - } - } - } - } - - fn next_led_mode(&self) { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.toggle_mode(false) - .unwrap_or_else(|err| warn!("{}", err)); - - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - self.notify_led(mode.clone()) - .unwrap_or_else(|err| warn!("{}", err)); - } - } - } - - fn prev_led_mode(&self) { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.toggle_mode(true) - .unwrap_or_else(|err| warn!("{}", err)); - - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - self.notify_led(mode.clone()) - .unwrap_or_else(|err| warn!("{}", err)); - } - } - } - - #[dbus_interface(property)] - fn awake_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.awake_enabled; - } - true - } - - #[dbus_interface(property)] - fn sleep_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.sleep_anim_enabled; - } - true - } - - /// Return the current mode data - #[dbus_interface(property)] - fn led_mode(&self) -> String { - if let Ok(ctrl) = self.0.try_lock() { - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - if let Ok(json) = serde_json::to_string(&mode) { - return json; - } - } - } - warn!("SetKeyBacklight could not deserialise"); - "SetKeyBacklight could not deserialise".to_string() - } - - /// Return a list of available modes - #[dbus_interface(property)] - fn led_modes(&self) -> String { - if let Ok(ctrl) = self.0.try_lock() { - if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) { - return json; - } - } - warn!("SetKeyBacklight could not deserialise"); - "SetKeyBacklight could not serialise".to_string() - } - - /// Return the current LED brightness - #[dbus_interface(property)] - fn led_brightness(&self) -> i8 { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1); - } - warn!("SetKeyBacklight could not serialise"); - -1 - } - - #[dbus_interface(signal)] - fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; - - #[dbus_interface(signal)] - fn notify_power_states(&self, data: &LedPowerStates) -> zbus::Result<()>; -} diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index e6cd3791..81f06945 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,116 +1,114 @@ use crate::error::RogError; -use crate::{config::Config, GetSupported}; +use crate::GetSupported; use log::{info, warn}; -use rog_profiles::profiles::Profile; -use rog_types::supported::FanCpuSupportedFunctions; +use rog_profiles::error::ProfileError; +use rog_profiles::{FanCurves, Profile}; +use rog_types::supported::PlatformProfileFunctions; use std::sync::Arc; use std::sync::Mutex; -pub struct CtrlFanAndCpu { - pub config: Arc>, +use super::config::ProfileConfig; + +pub struct CtrlPlatformTask { + config: Arc>, } -impl GetSupported for CtrlFanAndCpu { - type A = FanCpuSupportedFunctions; +impl CtrlPlatformTask { + pub fn new(config: Arc>) -> 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>, +} + +impl GetSupported for CtrlPlatformProfile { + type A = PlatformProfileFunctions; fn get_supported() -> Self::A { - FanCpuSupportedFunctions { - stock_fan_modes: Profile::get_fan_path().is_ok(), - min_max_freq: Profile::get_intel_supported(), - fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(), + if !Profile::is_platform_profile_supported() { + warn!(r#" +platform_profile kernel interface not found, your laptop does not support this, or the iterface is missing. +To enable profile support you require a kernel with the following patch applied: +https://lkml.org/lkml/2021/8/18/1022 +"#); + } + if !FanCurves::is_fan_curves_supported() { + info!(r#" +fan curves kernel interface not found, your laptop does not support this, or the iterface is missing. +To enable fan-curve support you require a kernel with the following patch applied: +https://lkml.org/lkml/2021/8/20/232 +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(), } } } -impl crate::Reloadable for CtrlFanAndCpu { - /// Fetcht he active profile and use that to set all related components up +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(mut cfg) = self.config.clone().try_lock() { - let active = cfg.active_profile.clone(); - if let Some(existing) = cfg.power_profiles.get_mut(&active) { - existing.set_system_all()?; + if let Ok(cfg) = self.config.clone().try_lock() { + if let Some(curves) = &cfg.fan_curves { + curves.update_platform(); } } Ok(()) } } -impl CtrlFanAndCpu { - pub fn new(config: Arc>) -> Result { - Profile::get_fan_path()?; - info!("Device has fan control available"); - Ok(CtrlFanAndCpu { config }) +impl CtrlPlatformProfile { + pub fn new(config: Arc>) -> Result { + if Profile::is_platform_profile_supported() { + info!("Device has profile control available"); + return Ok(CtrlPlatformProfile { config }); + } + Err(ProfileError::NotSupported.into()) } - /// Toggle to next profile in list - pub(super) fn do_next_profile(&mut self) -> Result<(), RogError> { + pub fn save_config(&self) { + if let Ok(lock) = self.config.lock() { + lock.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(); - let mut toggle_index = config - .toggle_profiles - .binary_search(&config.active_profile) - .unwrap_or(0) - + 1; - if toggle_index >= config.toggle_profiles.len() { - toggle_index = 0; + 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; + } } - let profile = config.toggle_profiles[toggle_index].clone(); - - if let Some(existing) = config.power_profiles.get(&profile) { - existing.set_system_all()?; - config.active_profile = existing.name.clone(); - config.write(); - info!("Profile was changed to: {}", &profile); - } else { - warn!( - "toggle_profile {} does not exist in power_profiles", - &profile - ); - return Err(RogError::MissingProfile(profile.to_string())); - } - } - Ok(()) - } - - pub(super) fn set_active(&mut self, profile: &str) -> 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(); - if let Some(existing) = config.power_profiles.get(profile) { - existing.set_system_all()?; - config.active_profile = existing.name.clone(); - config.write(); - info!("Profile was changed to: {}", profile); - } else { - warn!( - "toggle_profile {} does not exist in power_profiles", - profile - ); - return Err(RogError::MissingProfile(profile.to_string())); - } - } - Ok(()) - } - - /// Create a new profile if the requested name doesn't exist, or modify existing - pub(super) fn new_or_modify(&mut self, profile: &Profile) -> Result<(), RogError> { - if let Ok(mut config) = self.config.clone().try_lock() { - config.read(); - - if let Some(existing) = config.power_profiles.get_mut(&profile.name) { - *existing = profile.clone(); - existing.set_system_all()?; - } else { - config - .power_profiles - .insert(profile.name.clone(), profile.clone()); - profile.set_system_all()?; - } - - config.active_profile = profile.name.clone(); config.write(); } Ok(()) diff --git a/daemon/src/ctrl_profiles/mod.rs b/daemon/src/ctrl_profiles/mod.rs index 7df7470d..85a4d229 100644 --- a/daemon/src/ctrl_profiles/mod.rs +++ b/daemon/src/ctrl_profiles/mod.rs @@ -1,3 +1,3 @@ -pub mod zbus; - +pub mod config; pub mod controller; +pub mod zbus; diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 84c7da2b..4f26d79a 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -1,58 +1,54 @@ use log::warn; -use rog_profiles::profiles::Profile; +use rog_profiles::FanCurve; +use rog_profiles::Profile; use std::sync::Arc; use std::sync::Mutex; use zbus::{dbus_interface, fdo::Error}; use zvariant::ObjectPath; -use super::controller::CtrlFanAndCpu; +use super::controller::CtrlPlatformProfile; -pub struct FanAndCpuZbus { - inner: Arc>, +static UNSUPPORTED_MSG: &str = + "Fan curves are not supported on this laptop or you require a patched kernel"; + +pub struct ProfileZbus { + inner: Arc>, } -impl FanAndCpuZbus { - pub fn new(inner: Arc>) -> Self { +impl ProfileZbus { + pub fn new(inner: Arc>) -> Self { Self { inner } } } #[dbus_interface(name = "org.asuslinux.Daemon")] -impl FanAndCpuZbus { - /// Create new profile and make active - fn set_profile(&self, profile: String) { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.set_active(&profile) - .unwrap_or_else(|err| warn!("{}", err)); +impl ProfileZbus { + /// Fetch profile names + fn profiles(&mut self) -> zbus::fdo::Result> { + if let Ok(profiles) = Profile::get_profile_names() { + return Ok(profiles); } - self.do_notification(); + Err(Error::Failed( + "Failed to get all profile details".to_string(), + )) } - /// New or modify profile details and make active, will create if it does not exist - fn new_or_modify(&self, profile: Profile) { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.new_or_modify(&profile) - .unwrap_or_else(|err| warn!("{}", err)); - } - self.do_notification(); - } - - /// Fetch the active profile name + /// Toggle to next platform_profile. Names provided by `Profiles` fn next_profile(&mut self) { if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.do_next_profile() + ctrl.set_next_profile() .unwrap_or_else(|err| warn!("{}", err)); } self.do_notification(); } /// Fetch the active profile name - fn active_name(&mut self) -> zbus::fdo::Result { + fn active_profile(&mut self) -> zbus::fdo::Result { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - return Ok(cfg.active_profile.clone()); + return Ok(cfg.active); } } Err(Error::Failed( @@ -60,94 +56,96 @@ impl FanAndCpuZbus { )) } - // TODO: Profile can't implement Type because of Curve - /// Fetch the active profile details - fn active_data(&mut self) -> zbus::fdo::Result { + /// 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); + cfg.active = profile; + } + ctrl.save_config(); + } + self.do_notification(); + } + + /// Get a list of profiles that have fan-curves enabled. + fn enabled_fan_profiles(&mut self) -> 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(profile) = cfg.power_profiles.get(&cfg.active_profile) { - return Ok(profile.clone()); + if let Some(curves) = &cfg.fan_curves { + return Ok(curves.get_enabled_curve_names().to_vec()); } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } } Err(Error::Failed( - "Failed to get active profile details".to_string(), + "Failed to get enabled fan curve names".to_string(), )) } - /// Fetch all profile data - fn profiles(&mut self) -> zbus::fdo::Result> { + /// Get the fan-curve data for the currently active Profile + fn active_fan_curve_data(&mut self) -> zbus::fdo::Result { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - return Ok(cfg.power_profiles.values().cloned().collect()); + if let Some(curves) = &cfg.fan_curves { + return Ok((*curves.get_active_fan_curves()).clone()); + } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } } - Err(Error::Failed( - "Failed to get all profile details".to_string(), - )) + Err(Error::Failed("Failed to get fan curve data".to_string())) } - fn profile_names(&self) -> zbus::fdo::Result> { + /// Get fan-curve data for each Profile as an array of objects + fn fan_curves(&self) -> zbus::fdo::Result> { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - let profile_names = cfg.power_profiles.keys().cloned().collect::>(); - return Ok(profile_names); + if let Some(curves) = &cfg.fan_curves { + return Ok(curves.get_all_fan_curves()); + } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } } - - Err(Error::Failed("Failed to get all profile names".to_string())) + Err(Error::Failed("Failed to get all fan curves".to_string())) } - fn remove(&self, profile: &str) -> zbus::fdo::Result<()> { + /// 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 !cfg.power_profiles.contains_key(profile) { - return Err(Error::Failed("Invalid profile specified".to_string())); + if let Some(curves) = &mut cfg.fan_curves { + curves.set_fan_curve(curve); } - - if cfg.power_profiles.keys().len() == 1 { - return Err(Error::Failed("Cannot delete the last profile".to_string())); - } - - if cfg.active_profile == *profile { - return Err(Error::Failed( - "Cannot delete the active profile".to_string(), - )); - } - - cfg.power_profiles.remove(profile); - cfg.write(); - - return Ok(()); + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } + ctrl.save_config(); } - Err(Error::Failed("Failed to lock configuration".to_string())) + Err(Error::Failed("Failed to set fan curves".to_string())) } #[dbus_interface(signal)] fn notify_profile(&self, profile: &Profile) -> zbus::Result<()> {} } -impl FanAndCpuZbus { +impl ProfileZbus { fn do_notification(&self) { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(cfg) = ctrl.config.clone().try_lock() { - if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) { - self.notify_profile(profile) - .unwrap_or_else(|err| warn!("{}", err)); - } + self.notify_profile(&cfg.active) + .unwrap_or_else(|err| warn!("{}", err)); } } } } -impl crate::ZbusAdd for FanAndCpuZbus { +impl crate::ZbusAdd for ProfileZbus { fn add_to_server(self, server: &mut zbus::ObjectServer) { server .at( diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 60fedf07..8f0f30de 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -5,20 +5,20 @@ use zvariant::ObjectPath; use zvariant_derive::Type; use crate::{ - ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::controller::CtrlKbdLed, - ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios, GetSupported, + ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_charge::CtrlCharge, + ctrl_profiles::controller::CtrlPlatformProfile, ctrl_rog_bios::CtrlRogBios, GetSupported, }; use rog_types::supported::{ - AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions, - LedSupportedFunctions, RogBiosSupportedFunctions, + AnimeSupportedFunctions, ChargeSupportedFunctions, LedSupportedFunctions, + PlatformProfileFunctions, RogBiosSupportedFunctions, }; #[derive(Serialize, Deserialize, Type)] pub struct SupportedFunctions { pub anime_ctrl: AnimeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions, - pub fan_cpu_ctrl: FanCpuSupportedFunctions, + pub platform_profile: PlatformProfileFunctions, pub keyboard_led: LedSupportedFunctions, pub rog_bios_ctrl: RogBiosSupportedFunctions, } @@ -53,7 +53,7 @@ impl GetSupported for SupportedFunctions { anime_ctrl: CtrlAnime::get_supported(), keyboard_led: CtrlKbdLed::get_supported(), charge_ctrl: CtrlCharge::get_supported(), - fan_cpu_ctrl: CtrlFanAndCpu::get_supported(), + platform_profile: CtrlPlatformProfile::get_supported(), rog_bios_ctrl: CtrlRogBios::get_supported(), } } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 4bd8c604..d04d285f 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -1,33 +1,38 @@ -use daemon::ctrl_leds::controller::{ +use daemon::ctrl_anime::config::AnimeConfig; +use daemon::ctrl_anime::zbus::CtrlAnimeZbus; +use daemon::ctrl_aura::config::AuraConfig; +use daemon::ctrl_aura::controller::{ CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus, }; +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, }; -use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge}; use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics}; use daemon::{ - ctrl_profiles::{controller::CtrlFanAndCpu, zbus::FanAndCpuZbus}, + ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus}, laptops::LaptopLedData, }; +use ::zbus::{fdo, Connection, ObjectServer}; use daemon::{CtrlTask, Reloadable, ZbusAdd}; use log::LevelFilter; use log::{error, info, warn}; use rog_dbus::DBUS_NAME; use rog_types::gfx_vendors::GfxVendors; +use std::env; use std::error::Error; use std::io::Write; use std::sync::Arc; use std::sync::Mutex; -use std::env; use daemon::ctrl_rog_bios::CtrlRogBios; -use std::convert::Into; -use zbus::fdo; -use zbus::Connection; use zvariant::ObjectPath; +static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf"; + pub fn main() -> Result<(), Box> { let mut logger = env_logger::Builder::new(); logger @@ -43,7 +48,9 @@ pub fn main() -> Result<(), Box> { if !is_service { println!("asusd schould be only run from the right systemd service"); - println!("do not run in your terminal, if you need an logs please use journalctl -b -u asusd"); + println!( + "do not run in your terminal, if you need an logs please use journalctl -b -u asusd" + ); println!("asusd will now exit"); return Ok(()); } @@ -71,7 +78,7 @@ fn start_daemon() -> Result<(), Box> { let connection = Connection::new_system()?; fdo::DBusProxy::new(&connection)? .request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?; - let mut object_server = zbus::ObjectServer::new(&connection); + let mut object_server = ObjectServer::new(&connection); let config = Config::load(); let enable_gfx_switching = config.gfx_managed; @@ -105,12 +112,16 @@ fn start_daemon() -> Result<(), Box> { } } - match CtrlFanAndCpu::new(config.clone()) { + let profile_config = Arc::new(Mutex::new(ProfileConfig::load(PROFILE_CONFIG_PATH.into()))); + match CtrlPlatformProfile::new(profile_config.clone()) { Ok(mut ctrl) => { ctrl.reload() .unwrap_or_else(|err| warn!("Profile control: {}", err)); + let tmp = Arc::new(Mutex::new(ctrl)); - FanAndCpuZbus::new(tmp).add_to_server(&mut object_server); + ProfileZbus::new(tmp).add_to_server(&mut object_server); + + tasks.push(Box::new(CtrlPlatformTask::new(profile_config))); } Err(err) => { error!("Profile control: {}", err); diff --git a/daemon/src/error.rs b/daemon/src/error.rs index fa61f61e..c3052c8c 100644 --- a/daemon/src/error.rs +++ b/daemon/src/error.rs @@ -1,4 +1,3 @@ -use rog_fan_curve::CurveError; use rog_profiles::error::ProfileError; use rog_types::error::GraphicsError; use std::convert::From; @@ -17,7 +16,6 @@ pub enum RogError { Write(String, std::io::Error), NotSupported, NotFound(String), - FanCurve(CurveError), DoTask(String), MissingFunction(String), MissingLedBrightNode(String, std::io::Error), @@ -44,7 +42,6 @@ impl fmt::Display for RogError { RogError::Write(path, error) => write!(f, "Write {}: {}", path, error), RogError::NotSupported => write!(f, "Not supported"), RogError::NotFound(deets) => write!(f, "Not found: {}", deets), - RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err), RogError::DoTask(deets) => write!(f, "Task error: {}", deets), RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), @@ -62,12 +59,6 @@ impl fmt::Display for RogError { impl std::error::Error for RogError {} -impl From for RogError { - fn from(err: CurveError) -> Self { - RogError::FanCurve(err) - } -} - impl From for RogError { fn from(err: GraphicsError) -> Self { match err { diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index c331569a..f87a5cf4 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -1,17 +1,15 @@ #![deny(unused_must_use)] /// Configuration loading, saving pub mod config; -pub mod config_anime; -pub mod config_aura; pub(crate) mod config_old; /// Control of AniMe matrix display pub mod ctrl_anime; +/// Keyboard LED brightness control, RGB, and LED display modes +pub mod ctrl_aura; /// Control of battery charge level pub mod ctrl_charge; /// GPU switching and power pub mod ctrl_gfx; -/// Keyboard LED brightness control, RGB, and LED display modes -pub mod ctrl_leds; /// Control CPU min/max freq and turbo, fan mode, fan curves /// /// Intel machines can control: diff --git a/rog-dbus/Cargo.toml b/rog-dbus/Cargo.toml index 46e080ac..4fe86180 100644 --- a/rog-dbus/Cargo.toml +++ b/rog-dbus/Cargo.toml @@ -16,4 +16,4 @@ rog_profiles = { path = "../rog-profiles" } rog_types = { path = "../rog-types" } zbus = "^1.9" zbus_macros = "^1.9" -zvariant = "^2.5" +zvariant = "^2.8" diff --git a/rog-dbus/src/lib.rs b/rog-dbus/src/lib.rs index ae692cfb..d7709969 100644 --- a/rog-dbus/src/lib.rs +++ b/rog-dbus/src/lib.rs @@ -12,7 +12,7 @@ pub mod zbus_supported; use rog_anime::AnimePowerStates; use rog_aura::{AuraEffect, LedPowerStates}; -use rog_profiles::profiles::Profile; +use rog_profiles::Profile; use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors}; use std::sync::mpsc::{channel, Receiver}; use zbus::{Connection, Result, SignalReceiver}; diff --git a/rog-dbus/src/zbus_profile.rs b/rog-dbus/src/zbus_profile.rs index 38d8c7e2..7e5247ac 100644 --- a/rog-dbus/src/zbus_profile.rs +++ b/rog-dbus/src/zbus_profile.rs @@ -21,7 +21,7 @@ use std::sync::mpsc::Sender; -use rog_profiles::profiles::Profile; +use rog_profiles::{FanCurve, Profile}; use zbus::{dbus_proxy, Connection, Result}; #[dbus_proxy( @@ -29,26 +29,29 @@ use zbus::{dbus_proxy, Connection, Result}; default_path = "/org/asuslinux/Profile" )] trait Daemon { + /// Profiles method + fn profiles(&self) -> zbus::Result>; + /// NextProfile method fn next_profile(&self) -> zbus::Result<()>; /// Profile, get the active profile - fn active_name(&self) -> zbus::Result; + fn active_profile(&self) -> zbus::Result; + + /// 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>; /// Get the active `Profile` data - fn active_data(&self) -> zbus::Result; + fn active_fan_data(&self) -> zbus::Result; - /// Profiles method - fn profiles(&self) -> zbus::Result>; + /// Get all fan curve data + fn fan_curves(&self) -> zbus::Result>; - /// ProfileNames method - fn profile_names(&self) -> zbus::Result>; - - /// Remove method - fn remove(&self, profile: &str) -> zbus::Result<()>; - - /// SetProfile method - fn new_or_modify(&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<()>; /// NotifyProfile signal #[dbus_proxy(signal)] @@ -69,40 +72,15 @@ impl<'a> ProfileProxy<'a> { } #[inline] - pub fn active_name(&self) -> Result { - self.0.active_name() - } - - #[inline] - pub fn active_data(&self) -> Result { - self.0.active_data() - } - - #[inline] - pub fn all_profile_data(&self) -> Result> { + pub fn profiles(&self) -> Result> { self.0.profiles() } #[inline] - pub fn next_fan(&self) -> Result<()> { + pub fn next_profile(&self) -> Result<()> { self.0.next_profile() } - #[inline] - pub fn profile_names(&self) -> Result> { - self.0.profile_names() - } - - #[inline] - pub fn remove(&self, profile: &str) -> Result<()> { - self.0.remove(profile) - } - - #[inline] - pub fn new_or_modify(&self, profile: &Profile) -> Result<()> { - self.0.new_or_modify(profile) - } - #[inline] pub fn connect_notify_profile(&self, send: Sender) -> zbus::fdo::Result<()> { self.0.connect_notify_profile(move |data| { diff --git a/rog-profiles/Cargo.toml b/rog-profiles/Cargo.toml index bc434fce..5da2153b 100644 --- a/rog-profiles/Cargo.toml +++ b/rog-profiles/Cargo.toml @@ -9,10 +9,8 @@ default = ["dbus"] dbus = ["zvariant", "zvariant_derive"] [dependencies] -rog_fan_curve = { git = "https://github.com/Yarn/rog_fan_curve.git" } serde = "^1.0" serde_derive = "^1.0" -intel-pstate = "^0.2" zvariant = { version = "^2.6", optional = true } zvariant_derive = { version = "^2.6", optional = true } \ No newline at end of file diff --git a/rog-profiles/src/error.rs b/rog-profiles/src/error.rs index c5dc7c12..f057e040 100644 --- a/rog-profiles/src/error.rs +++ b/rog-profiles/src/error.rs @@ -1,18 +1,12 @@ use std::fmt; -use intel_pstate::PStateError; -use rog_fan_curve::CurveError; - #[derive(Debug)] pub enum ProfileError { - ParseFanLevel, Path(String, std::io::Error), Read(String, std::io::Error), Write(String, std::io::Error), NotSupported, NotFound(String), - IntelPstate(PStateError), - FanCurve(CurveError), Io(std::io::Error), //Zbus(zbus::Error), } @@ -21,14 +15,11 @@ impl fmt::Display for ProfileError { // This trait requires `fmt` with this exact signature. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - ProfileError::ParseFanLevel => write!(f, "Parse profile error"), ProfileError::Path(path, error) => write!(f, "Path {}: {}", path, error), ProfileError::Read(path, error) => write!(f, "Read {}: {}", path, error), ProfileError::Write(path, error) => write!(f, "Write {}: {}", path, error), ProfileError::NotSupported => write!(f, "Not supported"), ProfileError::NotFound(deets) => write!(f, "Not found: {}", deets), - ProfileError::IntelPstate(err) => write!(f, "Intel pstate error: {}", err), - ProfileError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err), ProfileError::Io(detail) => write!(f, "std::io error: {}", detail), //Error::Zbus(detail) => write!(f, "Zbus error: {}", detail), } @@ -36,15 +27,3 @@ impl fmt::Display for ProfileError { } impl std::error::Error for ProfileError {} - -impl From for ProfileError { - fn from(err: PStateError) -> Self { - ProfileError::IntelPstate(err) - } -} - -impl From for ProfileError { - fn from(err: CurveError) -> Self { - ProfileError::FanCurve(err) - } -} diff --git a/rog-profiles/src/lib.rs b/rog-profiles/src/lib.rs index 96d68664..eaa12415 100644 --- a/rog-profiles/src/lib.rs +++ b/rog-profiles/src/lib.rs @@ -1,8 +1,284 @@ pub mod error; -pub mod profiles; -static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"; -static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode"; -static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost"; +use std::{ + fs::OpenOptions, + io::{Read, Write}, + path::{Path, PathBuf}, +}; + +use error::ProfileError; +use serde_derive::{Deserialize, Serialize}; + +#[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"); + +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Deserialize, Serialize, Debug, Clone, Copy)] +pub enum Profile { + Balanced, + Performance, + Quiet, +} + +impl Profile { + pub fn is_platform_profile_supported() -> bool { + Path::new(PLATFORM_PROFILES).exists() + } + + pub fn get_active_profile() -> Result { + let mut file = OpenOptions::new() + .read(true) + .open(&PLATFORM_PROFILE) + .unwrap_or_else(|_| panic!("{} not found", &PLATFORM_PROFILE)); + + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + Ok(buf.as_str().into()) + } + + pub fn get_profile_names() -> Result, ProfileError> { + let mut file = OpenOptions::new() + .read(true) + .open(&PLATFORM_PROFILES) + .unwrap_or_else(|_| panic!("{} not found", &PLATFORM_PROFILES)); + + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + Ok(buf.rsplit(' ').map(|p| p.into()).collect()) + } + + pub fn set_profile(profile: Profile) { + let mut file = OpenOptions::new() + .write(true) + .open(PLATFORM_PROFILE) + .unwrap_or_else(|_| panic!("{} not found", PLATFORM_PROFILE)); + + file.write_all(<&str>::from(profile).as_bytes()).unwrap(); + } +} + +impl Default for Profile { + fn default() -> Self { + Self::Balanced + } +} + +impl From for &str { + fn from(profile: Profile) -> &'static str { + match profile { + Profile::Balanced => "balanced", + Profile::Performance => "performance", + Profile::Quiet => "quiet", + } + } +} + +impl From<&str> for Profile { + fn from(profile: &str) -> Profile { + match profile.to_ascii_lowercase().trim() { + "balanced" => Profile::Balanced, + "performance" => Profile::Performance, + "quiet" => Profile::Quiet, + _ => Profile::Balanced, + } + } +} + +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Deserialize, Serialize, Debug, Clone, Copy)] +pub enum FanCurvePU { + CPU, + GPU, +} + +impl From for &str { + fn from(pu: FanCurvePU) -> &'static str { + match pu { + FanCurvePU::CPU => "cpu", + FanCurvePU::GPU => "gpu", + } + } +} + +impl Default for FanCurvePU { + fn default() -> Self { + Self::CPU + } +} + +#[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 { + active_curves: Vec, + balanced: FanCurve, + performance: FanCurve, + quiet: FanCurve, +} + +impl Default for FanCurves { + fn default() -> Self { + let mut curves = Self { + active_curves: Default::default(), + balanced: Default::default(), + performance: Default::default(), + quiet: Default::default(), + }; + 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() + } + + 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] { + &self.active_curves + } + + pub fn get_all_fan_curves(&self) -> Vec { + vec![ + self.balanced.clone(), + self.performance.clone(), + self.quiet.clone(), + ] + } + + pub fn get_active_fan_curves(&self) -> &FanCurve { + match Profile::get_active_profile().unwrap() { + Profile::Balanced => &self.balanced, + Profile::Performance => &self.performance, + Profile::Quiet => &self.quiet, + } + } + + pub fn get_fan_curves_for(&self, name: Profile) -> &FanCurve { + match name { + Profile::Balanced => &self.balanced, + Profile::Performance => &self.performance, + Profile::Quiet => &self.quiet, + } + } + + 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 { + match name { + Profile::Balanced => match pu { + FanCurvePU::CPU => &self.balanced.cpu, + FanCurvePU::GPU => &self.balanced.gpu, + }, + Profile::Performance => match pu { + FanCurvePU::CPU => &self.balanced.cpu, + FanCurvePU::GPU => &self.balanced.gpu, + }, + Profile::Quiet => match pu { + FanCurvePU::CPU => &self.balanced.cpu, + FanCurvePU::GPU => &self.balanced.gpu, + }, + } + } + + 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(); + } +} diff --git a/rog-profiles/src/profiles.rs b/rog-profiles/src/profiles.rs deleted file mode 100644 index 53754dc8..00000000 --- a/rog-profiles/src/profiles.rs +++ /dev/null @@ -1,185 +0,0 @@ -use rog_fan_curve::{Curve, Fan}; -use serde_derive::{Deserialize, Serialize}; -use std::io::Write; -use std::{fs::OpenOptions, path::Path, str::FromStr}; -#[cfg(feature = "dbus")] -use zvariant_derive::Type; - -use crate::{error::ProfileError, AMD_BOOST_PATH, FAN_TYPE_1_PATH, FAN_TYPE_2_PATH}; - -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Profile { - pub name: String, - pub min_percentage: u8, - pub max_percentage: u8, - pub turbo: bool, - pub fan_preset: FanLevel, - pub fan_curve: String, -} - -impl Default for Profile { - fn default() -> Self { - Profile { - name: "new".into(), - min_percentage: 0, - max_percentage: 100, - turbo: false, - fan_preset: FanLevel::Normal, - fan_curve: "".to_string(), - } - } -} - -impl Profile { - pub fn new( - name: String, - min_percentage: u8, - max_percentage: u8, - turbo: bool, - fan_preset: FanLevel, - fan_curve: String, - ) -> Self { - Profile { - name, - min_percentage, - max_percentage, - turbo, - fan_preset, - fan_curve, - } - } - - pub fn get_intel_supported() -> bool { - intel_pstate::PState::new().is_ok() - } - - pub fn get_fan_path() -> Result<&'static str, ProfileError> { - if Path::new(FAN_TYPE_1_PATH).exists() { - Ok(FAN_TYPE_1_PATH) - } else if Path::new(FAN_TYPE_2_PATH).exists() { - Ok(FAN_TYPE_2_PATH) - } else { - Err(ProfileError::NotSupported) - } - } - - pub fn set_system_pstate(&self) -> Result<(), ProfileError> { - // Set CPU pstate - if let Ok(pstate) = intel_pstate::PState::new() { - pstate.set_min_perf_pct(self.min_percentage)?; - pstate.set_max_perf_pct(self.max_percentage)?; - pstate.set_no_turbo(!self.turbo)?; - } else { - // must be AMD CPU - let mut file = OpenOptions::new() - .write(true) - .open(AMD_BOOST_PATH) - .map_err(|err| ProfileError::Path(AMD_BOOST_PATH.into(), err))?; - - let boost = if self.turbo { "1" } else { "0" }; // opposite of Intel - file.write_all(boost.as_bytes()) - .map_err(|err| ProfileError::Write(AMD_BOOST_PATH.into(), err))?; - } - Ok(()) - } - - pub fn set_system_fan_mode(&self) -> Result<(), ProfileError> { - let path = Profile::get_fan_path()?; - let mut fan_ctrl = OpenOptions::new() - .write(true) - .open(path) - .map_err(|err| ProfileError::Path(path.into(), err))?; - fan_ctrl - .write_all(format!("{}\n", ::from(self.fan_preset)).as_bytes()) - .map_err(|err| ProfileError::Write(path.into(), err))?; - Ok(()) - } - - pub fn set_system_fan_curve(&self) -> Result<(), ProfileError> { - if !self.fan_curve.is_empty() { - if let Ok(curve) = Profile::parse_fan_curve(&self.fan_curve) { - use rog_fan_curve::Board; - if let Some(board) = Board::from_board_name() { - curve.apply(board, Fan::Cpu)?; - curve.apply(board, Fan::Gpu)?; - } - } - } - - Ok(()) - } - - pub fn set_system_all(&self) -> Result<(), ProfileError> { - self.set_system_pstate()?; - if self.fan_curve.is_empty() { - self.set_system_fan_mode()?; - } else { - self.set_system_fan_curve()?; - } - Ok(()) - } - - fn parse_fan_curve(data: &str) -> Result { - let curve = Curve::from_config_str(data)?; - if let Err(err) = curve.check_safety(Fan::Cpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - if let Err(err) = curve.check_safety(Fan::Gpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - Ok(curve) - } -} - -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] -pub enum FanLevel { - Normal, - Boost, - Silent, -} - -impl FromStr for FanLevel { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "normal" => Ok(FanLevel::Normal), - "boost" => Ok(FanLevel::Boost), - "silent" => Ok(FanLevel::Silent), - _ => Err("Invalid fan level"), - } - } -} - -impl From for FanLevel { - fn from(n: u8) -> Self { - match n { - 0 => FanLevel::Normal, - 1 => FanLevel::Boost, - 2 => FanLevel::Silent, - _ => FanLevel::Normal, - } - } -} - -impl From for u8 { - fn from(n: FanLevel) -> Self { - match n { - FanLevel::Normal => 0, - FanLevel::Boost => 1, - FanLevel::Silent => 2, - } - } -} - -impl From<&FanLevel> for u8 { - fn from(n: &FanLevel) -> Self { - match n { - FanLevel::Normal => 0, - FanLevel::Boost => 1, - FanLevel::Silent => 2, - } - } -} diff --git a/rog-types/src/supported.rs b/rog-types/src/supported.rs index e8e3fef8..a132a814 100644 --- a/rog-types/src/supported.rs +++ b/rog-types/src/supported.rs @@ -7,7 +7,7 @@ use zvariant_derive::Type; pub struct SupportedFunctions { pub anime_ctrl: AnimeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions, - pub fan_cpu_ctrl: FanCpuSupportedFunctions, + pub platform_profile: PlatformProfileFunctions, pub keyboard_led: LedSupportedFunctions, pub rog_bios_ctrl: RogBiosSupportedFunctions, } @@ -21,10 +21,9 @@ pub struct ChargeSupportedFunctions { } #[derive(Serialize, Deserialize, Type, Debug)] -pub struct FanCpuSupportedFunctions { - pub stock_fan_modes: bool, - pub min_max_freq: bool, - pub fan_curve_set: bool, +pub struct PlatformProfileFunctions { + pub platform_profile: bool, + pub fan_curves: bool, } #[derive(Serialize, Deserialize, Type, Debug)] @@ -45,7 +44,7 @@ impl fmt::Display for SupportedFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.anime_ctrl)?; writeln!(f, "{}", self.charge_ctrl)?; - writeln!(f, "{}", self.fan_cpu_ctrl)?; + writeln!(f, "{}", self.platform_profile)?; writeln!(f, "{}", self.keyboard_led)?; writeln!(f, "{}", self.rog_bios_ctrl) } @@ -67,12 +66,11 @@ impl fmt::Display for ChargeSupportedFunctions { ) } } -impl fmt::Display for FanCpuSupportedFunctions { +impl fmt::Display for PlatformProfileFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "Fan:")?; - writeln!(f, "\tStock fan modes: {}", self.stock_fan_modes)?; - writeln!(f, "\tMin/max frequency: {}", self.min_max_freq)?; - writeln!(f, "\tFan curve control: {}", self.fan_curve_set) + writeln!(f, "Platform profiles:")?; + writeln!(f, "\tplatform: {}", self.platform_profile)?; + writeln!(f, "\tfan curves: {}", self.fan_curves) } } impl fmt::Display for LedSupportedFunctions {