Add additional anime cli commands for image types

This commit is contained in:
Luke D. Jones
2021-10-28 23:43:50 +13:00
parent a925cbaed5
commit 678505811d
8 changed files with 194 additions and 104 deletions

View File

@@ -101,4 +101,3 @@ fn do_led_notif(ledmode: &AuraEffect) -> Result<NotificationHandle, notify_rust:
fn do_charge_notif(limit: &u8) -> Result<NotificationHandle, notify_rust::error::Error> { fn do_charge_notif(limit: &u8) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!("Battery charge limit changed to {}", limit)) base_notification!(&format!("Battery charge limit changed to {}", limit))
} }

View File

@@ -1,54 +1,4 @@
use gumdrop::Options; 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<Self, Self::Err> {
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<AnimeStatusValue> 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)] #[derive(Options)]
pub struct AnimeCommand { pub struct AnimeCommand {
@@ -56,21 +6,30 @@ pub struct AnimeCommand {
pub help: bool, pub help: bool,
#[options( #[options(
meta = "", 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<AnimeStatusValue>, pub enable: Option<bool>,
#[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")] #[options(
pub boot: Option<AnimeStatusValue>, meta = "",
help = "enable/disable system animations (boot/sleep/shutdown)"
)]
pub boot_enable: Option<bool>,
#[options(meta = "", help = "set global AniMe brightness value")]
pub brightness: Option<f32>,
#[options(command)] #[options(command)]
pub command: Option<AnimeActions>, pub command: Option<AnimeActions>,
} }
#[derive(Options)] #[derive(Options)]
pub enum AnimeActions { pub enum AnimeActions {
#[options(help = "change all leds brightness")] #[options(help = "display a PNG image")]
Leds(AnimeLeds),
#[options(help = "display an image png")]
Image(AnimeImage), 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)] #[derive(Options)]
@@ -90,3 +49,53 @@ pub struct AnimeImage {
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")] #[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
pub bright: f32, 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,
}

View File

@@ -1,14 +1,12 @@
mod anime_cli; use std::process::Command;
mod aura_cli; use std::thread::sleep;
mod cli_opts; use std::{env::args, path::Path};
mod profiles_cli;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use crate::cli_opts::*;
use anime_cli::{AnimeActions, AnimeCommand};
use gumdrop::{Opt, Options}; use gumdrop::{Opt, Options};
use anime_cli::{AnimeActions, AnimeCommand};
use profiles_cli::{FanCurveCommand, ProfileCommand}; 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_aura::{self, AuraEffect};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClient;
use rog_profiles::error::ProfileError; use rog_profiles::error::ProfileError;
@@ -17,8 +15,14 @@ use rog_supported::{
AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions, AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions,
RogBiosSupportedFunctions, 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"; 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() { match brightness.level() {
None => { None => {
let level = dbus.proxies().led().get_led_brightness()?; 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 Some(level) => dbus
.proxies() .proxies()
@@ -206,28 +210,28 @@ fn handle_anime(
_supported: &AnimeSupportedFunctions, _supported: &AnimeSupportedFunctions,
cmd: &AnimeCommand, cmd: &AnimeCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
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()); println!("Missing arg or command\n\n{}", cmd.self_usage());
if let Some(lst) = cmd.self_command_list() { if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst); println!("\n{}", lst);
} }
} }
if let Some(anime_turn) = cmd.turn { if let Some(anime_turn) = cmd.enable {
dbus.proxies().anime().set_led_power(anime_turn.into())? dbus.proxies().anime().set_on_off(anime_turn)?
} }
if let Some(anime_boot) = cmd.boot { if let Some(anime_boot) = cmd.boot_enable {
dbus.proxies() dbus.proxies().anime().set_boot_on_off(anime_boot)?
.anime() }
.set_system_animations(anime_boot.into())? if let Some(bright) = cmd.brightness {
dbus.proxies().anime().set_brightness(bright as f32)?
} }
if let Some(action) = cmd.command.as_ref() { if let Some(action) = cmd.command.as_ref() {
match action { 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) => { AnimeActions::Image(image) => {
if image.help_requested() || image.path.is_empty() { if image.help_requested() || image.path.is_empty() {
println!("Missing arg or command\n\n{}", image.self_usage()); println!("Missing arg or command\n\n{}", image.self_usage());
@@ -249,6 +253,82 @@ fn handle_anime(
.anime() .anime()
.write(<AnimeDataBuffer>::from(&matrix))?; .write(<AnimeDataBuffer>::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(<AnimeDataBuffer>::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(()) Ok(())

View File

@@ -353,13 +353,13 @@ impl CtrlAnime<'static> {
pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> { pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> {
// Operations here need to be in specific order // Operations here need to be in specific order
if on { if on {
self.client.proxies().anime().set_led_power(on)?; self.client.proxies().anime().set_on_off(on)?;
// Let the inner loop run // Let the inner loop run
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
} else { } else {
// Must make the inner run loop return early // Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst); 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(()) Ok(())
} }

View File

@@ -88,7 +88,7 @@ pub struct AnimeGif(Vec<AnimeFrame>, AnimTime);
impl AnimeGif { impl AnimeGif {
/// Create an animation using the 74x36 ASUS gif format /// Create an animation using the 74x36 ASUS gif format
#[inline] #[inline]
pub fn create_diagonal_gif( pub fn from_diagonal_gif(
file_name: &Path, file_name: &Path,
duration: AnimTime, duration: AnimTime,
brightness: f32, brightness: f32,
@@ -130,7 +130,7 @@ impl AnimeGif {
/// Create an animation using the 74x36 ASUS gif format from a png /// Create an animation using the 74x36 ASUS gif format from a png
#[inline] #[inline]
pub fn create_diagonal_png( pub fn from_diagonal_png(
file_name: &Path, file_name: &Path,
duration: AnimTime, duration: AnimTime,
brightness: f32, brightness: f32,
@@ -159,7 +159,7 @@ impl AnimeGif {
/// Create an animation using a gif of any size. This method must precompute the /// Create an animation using a gif of any size. This method must precompute the
/// result. /// result.
#[inline] #[inline]
pub fn create_png_gif( pub fn from_gif(
file_name: &Path, file_name: &Path,
scale: f32, scale: f32,
angle: f32, angle: f32,
@@ -231,7 +231,7 @@ impl AnimeGif {
/// will be 1 second long. If `AnimTime::Cycles` is specified for `duration` then this can /// 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. /// be considered how many seconds the image will show for.
#[inline] #[inline]
pub fn create_png_static( pub fn from_png(
file_name: &Path, file_name: &Path,
scale: f32, scale: f32,
angle: f32, angle: f32,

View File

@@ -69,7 +69,7 @@ impl ActionData {
file, file,
time, time,
brightness, brightness,
} => ActionData::Animation(AnimeGif::create_diagonal_gif(file, *time, *brightness)?), } => ActionData::Animation(AnimeGif::from_diagonal_gif(file, *time, *brightness)?),
ActionLoader::AsusImage { ActionLoader::AsusImage {
file, file,
time, time,
@@ -80,9 +80,7 @@ impl ActionData {
let data = <AnimeDataBuffer>::from(&image); let data = <AnimeDataBuffer>::from(&image);
ActionData::Image(Box::new(data)) ActionData::Image(Box::new(data))
} }
_ => { _ => ActionData::Animation(AnimeGif::from_diagonal_png(file, *time, *brightness)?),
ActionData::Animation(AnimeGif::create_diagonal_png(file, *time, *brightness)?)
}
}, },
ActionLoader::ImageAnimation { ActionLoader::ImageAnimation {
file, file,
@@ -94,7 +92,7 @@ impl ActionData {
} => { } => {
if let Some(ext) = file.extension() { if let Some(ext) = file.extension() {
if ext.to_string_lossy().to_lowercase() == "png" { if ext.to_string_lossy().to_lowercase() == "png" {
return Ok(ActionData::Animation(AnimeGif::create_png_static( return Ok(ActionData::Animation(AnimeGif::from_png(
file, file,
*scale, *scale,
*angle, *angle,
@@ -104,7 +102,7 @@ impl ActionData {
)?)); )?));
} }
} }
ActionData::Animation(AnimeGif::create_png_gif( ActionData::Animation(AnimeGif::from_gif(
file, file,
*scale, *scale,
*angle, *angle,
@@ -129,7 +127,7 @@ impl ActionData {
let data = <AnimeDataBuffer>::from(&image); let data = <AnimeDataBuffer>::from(&image);
ActionData::Image(Box::new(data)) ActionData::Image(Box::new(data))
} }
_ => ActionData::Animation(AnimeGif::create_png_static( _ => ActionData::Animation(AnimeGif::from_png(
file, file,
*scale, *scale,
*angle, *angle,

View File

@@ -45,18 +45,23 @@ impl<'a> AnimeProxy<'a> {
&self.0 &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 /// Set whether the AniMe is displaying images/data
#[inline] #[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) 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 /// Writes a data stream of length. Will force system thread to exit until it is restarted
#[inline] #[inline]
pub fn write(&self, input: AnimeDataBuffer) -> Result<()> { pub fn write(&self, input: AnimeDataBuffer) -> Result<()> {

View File

@@ -37,8 +37,7 @@ impl fmt::Display for ProfileError {
), ),
ProfileError::ParseFanCurvePercentOver100(value) => { ProfileError::ParseFanCurvePercentOver100(value) => {
write!(f, "Invalid percentage, {} is higher than 100", 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),
} }
} }
} }