diff --git a/Cargo.lock b/Cargo.lock index 5c2e71e6..38ee33ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ [[package]] name = "asusctl" -version = "4.0.5" +version = "4.0.6" dependencies = [ "daemon", "gif", @@ -901,7 +901,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rog_anime" -version = "1.1.0" +version = "1.3.0" dependencies = [ "gif", "glam", diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index e397ae39..a9ef55c1 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -101,4 +101,3 @@ fn do_led_notif(ledmode: &AuraEffect) -> Result Result { base_notification!(&format!("Battery charge limit changed to {}", limit)) } - diff --git a/asusctl/Cargo.toml b/asusctl/Cargo.toml index a768c117..43587fa4 100644 --- a/asusctl/Cargo.toml +++ b/asusctl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "asusctl" -version = "4.0.5" +version = "4.0.6" authors = ["Luke D Jones "] edition = "2018" diff --git a/asusctl/src/anime_cli.rs b/asusctl/src/anime_cli.rs index 5a725f20..928d1586 100644 --- a/asusctl/src/anime_cli.rs +++ b/asusctl/src/anime_cli.rs @@ -1,54 +1,4 @@ use gumdrop::Options; -use rog_aura::error::Error; -use std::str::FromStr; - -#[derive(Copy, Clone, Debug)] -pub enum AnimeStatusValue { - On, - Off, -} -impl FromStr for AnimeStatusValue { - type Err = Error; - - fn from_str(s: &str) -> Result { - let s = s.to_lowercase(); - match s.as_str() { - "on" => Ok(AnimeStatusValue::On), - "off" => Ok(AnimeStatusValue::Off), - _ => { - print!("Invalid argument, must be one of: on, off"); - Err(Error::ParseAnime) - } - } - } -} -impl From for bool { - fn from(value: AnimeStatusValue) -> Self { - match value { - AnimeStatusValue::On => true, - AnimeStatusValue::Off => false, - } - } -} - -#[derive(Options)] -pub struct AnimeLeds { - #[options(help = "print help message")] - help: bool, - #[options( - no_long, - required, - short = "b", - meta = "", - help = "set all leds brightness value" - )] - led_brightness: u8, -} -impl AnimeLeds { - pub fn led_brightness(&self) -> u8 { - self.led_brightness - } -} #[derive(Options)] pub struct AnimeCommand { @@ -56,21 +6,30 @@ pub struct AnimeCommand { pub help: bool, #[options( meta = "", - help = "turn on/off the panel (accept/reject write requests)" + help = "enable/disable the panel LEDs (does not erase last image)" )] - pub turn: Option, - #[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")] - pub boot: Option, + pub enable: Option, + #[options( + meta = "", + help = "enable/disable system animations (boot/sleep/shutdown)" + )] + pub boot_enable: Option, + #[options(meta = "", help = "set global AniMe brightness value")] + pub brightness: Option, #[options(command)] pub command: Option, } #[derive(Options)] pub enum AnimeActions { - #[options(help = "change all leds brightness")] - Leds(AnimeLeds), - #[options(help = "display an image png")] + #[options(help = "display a PNG image")] Image(AnimeImage), + #[options(help = "display a diagonal/pixel-perfect PNG")] + PixelImage(AnimeImageDiagonal), + #[options(help = "display an animated GIF")] + Gif(AnimeGif), + #[options(help = "display an animated diagonal/pixel-perfect GIF")] + PixelGif(AnimeGifDiagonal), } #[derive(Options)] @@ -90,3 +49,53 @@ pub struct AnimeImage { #[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")] pub bright: f32, } + +#[derive(Options)] +pub struct AnimeImageDiagonal { + #[options(help = "print help message")] + pub help: bool, + #[options(meta = "", help = "full path to the png to display")] + pub path: String, + #[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")] + pub bright: f32, +} + +#[derive(Options)] +pub struct AnimeGif { + #[options(help = "print help message")] + pub help: bool, + #[options(meta = "", help = "full path to the png to display")] + pub path: String, + #[options(meta = "", default = "1.0", help = "scale 1.0 == normal")] + pub scale: f32, + #[options(meta = "", default = "0.0", help = "x position (float)")] + pub x_pos: f32, + #[options(meta = "", default = "0.0", help = "y position (float)")] + pub y_pos: f32, + #[options(meta = "", default = "0.0", help = "the angle in radians")] + pub angle: f32, + #[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")] + pub bright: f32, + #[options( + meta = "", + default = "1", + help = "how many loops to play - 0 is infinite" + )] + pub loops: u32, +} + +#[derive(Options)] +pub struct AnimeGifDiagonal { + #[options(help = "print help message")] + pub help: bool, + #[options(meta = "", help = "full path to the png to display")] + pub path: String, + #[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")] + pub bright: f32, + #[options( + meta = "", + default = "1", + help = "how many loops to play - 0 is infinite" + )] + pub loops: u32, +} diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 9dd73015..e7971685 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -1,14 +1,12 @@ -mod anime_cli; -mod aura_cli; -mod cli_opts; -mod profiles_cli; +use std::process::Command; +use std::thread::sleep; +use std::{env::args, path::Path}; -use crate::aura_cli::{LedBrightness, SetAuraBuiltin}; -use crate::cli_opts::*; -use anime_cli::{AnimeActions, AnimeCommand}; use gumdrop::{Opt, Options}; + +use anime_cli::{AnimeActions, AnimeCommand}; use profiles_cli::{FanCurveCommand, ProfileCommand}; -use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN}; +use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2}; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClient; use rog_profiles::error::ProfileError; @@ -17,8 +15,14 @@ use rog_supported::{ AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions, RogBiosSupportedFunctions, }; -use std::process::Command; -use std::{env::args, path::Path}; + +use crate::aura_cli::{LedBrightness, SetAuraBuiltin}; +use crate::cli_opts::*; + +mod anime_cli; +mod aura_cli; +mod cli_opts; +mod profiles_cli; const CONFIG_ADVICE: &str = "A config file need to be removed so a new one can be generated"; @@ -167,7 +171,7 @@ fn do_parsed( match brightness.level() { None => { let level = dbus.proxies().led().get_led_brightness()?; - println!("Current keyboard led brightness: {}", level.to_string()); + println!("Current keyboard led brightness: {}", level); } Some(level) => dbus .proxies() @@ -206,28 +210,28 @@ fn handle_anime( _supported: &AnimeSupportedFunctions, cmd: &AnimeCommand, ) -> Result<(), Box> { - if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help { + if (cmd.command.is_none() + && cmd.enable.is_none() + && cmd.boot_enable.is_none() + && cmd.brightness.is_none()) + || cmd.help + { println!("Missing arg or command\n\n{}", cmd.self_usage()); if let Some(lst) = cmd.self_command_list() { println!("\n{}", lst); } } - if let Some(anime_turn) = cmd.turn { - dbus.proxies().anime().set_led_power(anime_turn.into())? + if let Some(anime_turn) = cmd.enable { + dbus.proxies().anime().set_on_off(anime_turn)? } - if let Some(anime_boot) = cmd.boot { - dbus.proxies() - .anime() - .set_system_animations(anime_boot.into())? + if let Some(anime_boot) = cmd.boot_enable { + dbus.proxies().anime().set_boot_on_off(anime_boot)? + } + if let Some(bright) = cmd.brightness { + dbus.proxies().anime().set_brightness(bright as f32)? } if let Some(action) = cmd.command.as_ref() { match action { - AnimeActions::Leds(anime_leds) => { - let data = AnimeDataBuffer::from_vec( - [anime_leds.led_brightness(); ANIME_DATA_LEN].to_vec(), - ); - dbus.proxies().anime().write(data)?; - } AnimeActions::Image(image) => { if image.help_requested() || image.path.is_empty() { println!("Missing arg or command\n\n{}", image.self_usage()); @@ -249,6 +253,82 @@ fn handle_anime( .anime() .write(::from(&matrix))?; } + AnimeActions::PixelImage(image) => { + if image.help_requested() || image.path.is_empty() { + println!("Missing arg or command\n\n{}", image.self_usage()); + if let Some(lst) = image.self_command_list() { + println!("\n{}", lst); + } + std::process::exit(1); + } + + let matrix = AnimeDiagonal::from_png(Path::new(&image.path), None, image.bright)?; + + dbus.proxies() + .anime() + .write(::from(&matrix))?; + } + AnimeActions::Gif(gif) => { + if gif.help_requested() || gif.path.is_empty() { + println!("Missing arg or command\n\n{}", gif.self_usage()); + if let Some(lst) = gif.self_command_list() { + println!("\n{}", lst); + } + std::process::exit(1); + } + + let matrix = AnimeGif::from_gif( + Path::new(&gif.path), + gif.scale, + gif.angle, + Vec2::new(gif.x_pos, gif.y_pos), + AnimTime::Count(1), + gif.bright, + )?; + + let mut loops = gif.loops as i32; + loop { + for frame in matrix.frames() { + dbus.proxies().anime().write(frame.frame().clone())?; + sleep(frame.delay()); + } + if loops >= 0 { + loops -= 1; + } + if loops == 0 { + break; + } + } + } + AnimeActions::PixelGif(gif) => { + if gif.help_requested() || gif.path.is_empty() { + println!("Missing arg or command\n\n{}", gif.self_usage()); + if let Some(lst) = gif.self_command_list() { + println!("\n{}", lst); + } + std::process::exit(1); + } + + let matrix = AnimeGif::from_diagonal_gif( + Path::new(&gif.path), + AnimTime::Count(1), + gif.bright, + )?; + + let mut loops = gif.loops as i32; + loop { + for frame in matrix.frames() { + dbus.proxies().anime().write(frame.frame().clone())?; + sleep(frame.delay()); + } + if loops >= 0 { + loops -= 1; + } + if loops == 0 { + break; + } + } + } } } Ok(()) diff --git a/daemon-user/src/ctrl_anime.rs b/daemon-user/src/ctrl_anime.rs index 40c6226b..a096f9a5 100644 --- a/daemon-user/src/ctrl_anime.rs +++ b/daemon-user/src/ctrl_anime.rs @@ -353,13 +353,13 @@ impl CtrlAnime<'static> { pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> { // Operations here need to be in specific order if on { - self.client.proxies().anime().set_led_power(on)?; + self.client.proxies().anime().set_on_off(on)?; // Let the inner loop run self.inner_early_return.store(false, Ordering::SeqCst); } else { // Must make the inner run loop return early self.inner_early_return.store(true, Ordering::SeqCst); - self.client.proxies().anime().set_led_power(on)?; + self.client.proxies().anime().set_on_off(on)?; } Ok(()) } diff --git a/rog-anime/Cargo.toml b/rog-anime/Cargo.toml index 527b5e39..1962f26a 100644 --- a/rog-anime/Cargo.toml +++ b/rog-anime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog_anime" -version = "1.1.0" +version = "1.3.0" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/rog-anime/src/gif.rs b/rog-anime/src/gif.rs index a581de68..ef89ad4b 100644 --- a/rog-anime/src/gif.rs +++ b/rog-anime/src/gif.rs @@ -88,7 +88,7 @@ pub struct AnimeGif(Vec, AnimTime); impl AnimeGif { /// Create an animation using the 74x36 ASUS gif format #[inline] - pub fn create_diagonal_gif( + pub fn from_diagonal_gif( file_name: &Path, duration: AnimTime, brightness: f32, @@ -130,7 +130,7 @@ impl AnimeGif { /// Create an animation using the 74x36 ASUS gif format from a png #[inline] - pub fn create_diagonal_png( + pub fn from_diagonal_png( file_name: &Path, duration: AnimTime, brightness: f32, @@ -159,7 +159,7 @@ impl AnimeGif { /// Create an animation using a gif of any size. This method must precompute the /// result. #[inline] - pub fn create_png_gif( + pub fn from_gif( file_name: &Path, scale: f32, angle: f32, @@ -231,7 +231,7 @@ impl AnimeGif { /// will be 1 second long. If `AnimTime::Cycles` is specified for `duration` then this can /// be considered how many seconds the image will show for. #[inline] - pub fn create_png_static( + pub fn from_png( file_name: &Path, scale: f32, angle: f32, diff --git a/rog-anime/src/sequencer.rs b/rog-anime/src/sequencer.rs index 3a667133..5db29882 100644 --- a/rog-anime/src/sequencer.rs +++ b/rog-anime/src/sequencer.rs @@ -69,7 +69,7 @@ impl ActionData { file, time, brightness, - } => ActionData::Animation(AnimeGif::create_diagonal_gif(file, *time, *brightness)?), + } => ActionData::Animation(AnimeGif::from_diagonal_gif(file, *time, *brightness)?), ActionLoader::AsusImage { file, time, @@ -80,9 +80,7 @@ impl ActionData { let data = ::from(&image); ActionData::Image(Box::new(data)) } - _ => { - ActionData::Animation(AnimeGif::create_diagonal_png(file, *time, *brightness)?) - } + _ => ActionData::Animation(AnimeGif::from_diagonal_png(file, *time, *brightness)?), }, ActionLoader::ImageAnimation { file, @@ -94,7 +92,7 @@ impl ActionData { } => { if let Some(ext) = file.extension() { if ext.to_string_lossy().to_lowercase() == "png" { - return Ok(ActionData::Animation(AnimeGif::create_png_static( + return Ok(ActionData::Animation(AnimeGif::from_png( file, *scale, *angle, @@ -104,7 +102,7 @@ impl ActionData { )?)); } } - ActionData::Animation(AnimeGif::create_png_gif( + ActionData::Animation(AnimeGif::from_gif( file, *scale, *angle, @@ -129,7 +127,7 @@ impl ActionData { let data = ::from(&image); ActionData::Image(Box::new(data)) } - _ => ActionData::Animation(AnimeGif::create_png_static( + _ => ActionData::Animation(AnimeGif::from_png( file, *scale, *angle, diff --git a/rog-dbus/src/zbus_anime.rs b/rog-dbus/src/zbus_anime.rs index 47cebc68..da681ca5 100644 --- a/rog-dbus/src/zbus_anime.rs +++ b/rog-dbus/src/zbus_anime.rs @@ -45,18 +45,23 @@ impl<'a> AnimeProxy<'a> { &self.0 } - /// Set whether the AniMe will show boot, suspend, or off animations - #[inline] - pub fn set_system_animations(&self, on: bool) -> Result<()> { - self.0.set_boot_on_off(on) - } - /// Set whether the AniMe is displaying images/data #[inline] - pub fn set_led_power(&self, on: bool) -> Result<()> { + pub fn set_on_off(&self, on: bool) -> Result<()> { self.0.set_on_off(on) } + /// Set the global AniMe brightness + pub fn set_brightness(&self, bright: f32) -> Result<()> { + self.0.set_brightness(bright) + } + + /// Set whether the AniMe will show boot, suspend, or off animations + #[inline] + pub fn set_boot_on_off(&self, on: bool) -> Result<()> { + self.0.set_boot_on_off(on) + } + /// Writes a data stream of length. Will force system thread to exit until it is restarted #[inline] pub fn write(&self, input: AnimeDataBuffer) -> Result<()> { diff --git a/rog-profiles/src/error.rs b/rog-profiles/src/error.rs index 2ead72b8..be221c0e 100644 --- a/rog-profiles/src/error.rs +++ b/rog-profiles/src/error.rs @@ -37,8 +37,7 @@ impl fmt::Display for ProfileError { ), ProfileError::ParseFanCurvePercentOver100(value) => { write!(f, "Invalid percentage, {} is higher than 100", value) - } - // Error::Zbus(detail) => write!(f, "Zbus error: {}", detail), + } // Error::Zbus(detail) => write!(f, "Zbus error: {}", detail), } } }