mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Merge branch 'fluke/anime-cli' into 'main'
anime: add zbus methods See merge request asus-linux/asus-nb-ctrl!49
This commit is contained in:
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Revert zbus to 1.9.1
|
||||
- Use enum to show power states, and catch missing pci path for nvidia.
|
||||
- Partial user-daemon for anime/per-key done, asusd-user. Includes asusd-user systemd unit.
|
||||
- user-daemon provides dbus emthods to insert anime actions, remove from index, set leds on/off
|
||||
|
||||
# [3.3.0] - 2021-04-3
|
||||
### Changed
|
||||
|
||||
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -233,9 +233,13 @@ dependencies = [
|
||||
"dirs 3.0.1",
|
||||
"rog_anime",
|
||||
"rog_dbus",
|
||||
"rog_types",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"zbus",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -909,6 +913,7 @@ dependencies = [
|
||||
"png_pong",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"zbus",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
|
||||
@@ -2,6 +2,7 @@ use notify_rust::{Hint, Notification, NotificationHandle};
|
||||
use rog_dbus::{DbusProxies, Signals};
|
||||
use rog_types::profile::Profile;
|
||||
use std::error::Error;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -18,9 +19,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut last_chrg_notif: Option<NotificationHandle> = None;
|
||||
|
||||
let recv = proxies.setup_recv(conn);
|
||||
let mut err_count = 0;
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
recv.next_signal().unwrap();
|
||||
sleep(Duration::from_millis(100));
|
||||
if let Err(err) = recv.next_signal() {
|
||||
if err_count < 3 {
|
||||
err_count += 1;
|
||||
println!("{}", err);
|
||||
}
|
||||
if err_count == 3 {
|
||||
err_count += 1;
|
||||
println!("Max error count reached. Spooling silently.");
|
||||
}
|
||||
sleep(Duration::from_millis(2000));
|
||||
continue;
|
||||
}
|
||||
err_count = 0;
|
||||
|
||||
if let Ok(mut lock) = signals.gfx_vendor.lock() {
|
||||
if let Some(vendor) = lock.take() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{env, path::Path, thread::sleep};
|
||||
|
||||
use rog_anime::{Action, Sequences};
|
||||
use rog_anime::{ActionData, AnimeAction, Sequences};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
fn main() {
|
||||
@@ -15,11 +15,19 @@ fn main() {
|
||||
let path = Path::new(&args[1]);
|
||||
let brightness = args[2].parse::<f32>().unwrap();
|
||||
let mut seq = Sequences::new();
|
||||
seq.add_asus_gif(path, rog_anime::AnimTime::Infinite, brightness).unwrap();
|
||||
seq.insert(
|
||||
0,
|
||||
&AnimeAction::AsusAnimation {
|
||||
file: path.into(),
|
||||
time: rog_anime::AnimTime::Infinite,
|
||||
brightness,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
for action in seq.iter() {
|
||||
if let Action::Animation(frames) = action {
|
||||
if let ActionData::Animation(frames) = action {
|
||||
for frame in frames.frames() {
|
||||
client
|
||||
.proxies()
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
use std::{
|
||||
env,
|
||||
path::Path,
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use glam::Vec2;
|
||||
use rog_anime::{Action, AnimTime, Sequences};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let args: Vec<String> = env::args().into_iter().collect();
|
||||
if args.len() < 7 {
|
||||
println!(
|
||||
"Usage: <filepath> <scale> <angle> <x pos> <y pos> <brightness> <duration> <filepath>"
|
||||
);
|
||||
println!("e.g, asusctl/examples/file.gif 0.9 0.4 0.0 0.0 0.8 0");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut seq = Sequences::new();
|
||||
seq.add_image_gif(
|
||||
Path::new(&args[1]),
|
||||
args[2].parse::<f32>().unwrap(),
|
||||
args[3].parse::<f32>().unwrap(),
|
||||
Vec2::new(
|
||||
args[4].parse::<f32>().unwrap(),
|
||||
args[5].parse::<f32>().unwrap(),
|
||||
),
|
||||
if let Ok(time) = args[7].parse::<u64>() {
|
||||
if time != 0 {
|
||||
AnimTime::Time(Duration::from_secs(time))
|
||||
} else {
|
||||
AnimTime::Infinite
|
||||
}
|
||||
} else {
|
||||
AnimTime::Infinite
|
||||
},
|
||||
args[6].parse::<f32>().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if args.len() == 9 {
|
||||
seq.add_image_gif(
|
||||
Path::new(&args[8]),
|
||||
args[2].parse::<f32>().unwrap(),
|
||||
args[3].parse::<f32>().unwrap(),
|
||||
Vec2::new(
|
||||
args[4].parse::<f32>().unwrap(),
|
||||
args[5].parse::<f32>().unwrap(),
|
||||
),
|
||||
if let Ok(time) = args[7].parse::<u64>() {
|
||||
if time != 0 {
|
||||
AnimTime::Time(Duration::from_secs(time))
|
||||
} else {
|
||||
AnimTime::Infinite
|
||||
}
|
||||
} else {
|
||||
AnimTime::Infinite
|
||||
},
|
||||
args[6].parse::<f32>().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
loop {
|
||||
for action in seq.iter() {
|
||||
if let Action::Animation(frames) = action {
|
||||
let mut count = 0;
|
||||
let start = Instant::now();
|
||||
'outer: loop {
|
||||
for frame in frames.frames() {
|
||||
client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(frame.frame().clone())
|
||||
.unwrap();
|
||||
if let AnimTime::Time(time) = frames.duration() {
|
||||
if Instant::now().duration_since(start) > time {
|
||||
break 'outer;
|
||||
}
|
||||
} else if let AnimTime::Cycles(times) = frames.duration() {
|
||||
if count == times {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
sleep(frame.delay());
|
||||
}
|
||||
count +=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,6 @@ mod aura_cli;
|
||||
|
||||
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
|
||||
use anime_cli::{AniMeActions, AniMeCommand};
|
||||
use daemon::{
|
||||
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
|
||||
ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions,
|
||||
};
|
||||
use gumdrop::{Opt, Options};
|
||||
use rog_anime::{AniMeDataBuffer, AniMeImage, Vec2, ANIME_DATA_LEN};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
@@ -14,6 +10,10 @@ use rog_types::{
|
||||
aura_modes::{self, AuraEffect, AuraModeNum},
|
||||
gfx_vendors::GfxVendors,
|
||||
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
||||
supported::{
|
||||
FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions,
|
||||
SupportedFunctions,
|
||||
},
|
||||
};
|
||||
use std::{env::args, path::Path};
|
||||
use yansi_term::Colour::Green;
|
||||
|
||||
@@ -11,7 +11,7 @@ path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "asusd-user"
|
||||
path = "src/main.rs"
|
||||
path = "src/daemon.rs"
|
||||
|
||||
[dependencies]
|
||||
# serialisation
|
||||
@@ -21,5 +21,10 @@ serde_derive = "^1.0"
|
||||
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_types = { path = "../rog-types" }
|
||||
|
||||
dirs = "3.0.1"
|
||||
dirs = "3.0.1"
|
||||
|
||||
zbus = "^1.9.1"
|
||||
zvariant = "^2.6"
|
||||
zvariant_derive = "^2.6"
|
||||
342
daemon-user/src/ctrl_anime.rs
Normal file
342
daemon-user/src/ctrl_anime.rs
Normal file
@@ -0,0 +1,342 @@
|
||||
use rog_anime::{ActionData, AnimTime, AnimeAction, Sequences, Vec2};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
//use crate::dbus::DbusEvents;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Mutex,
|
||||
},
|
||||
};
|
||||
use std::{sync::Arc, thread::sleep, time::Instant};
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
use zvariant_derive::Type;
|
||||
|
||||
use crate::{error::Error, user_config::UserConfig};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
|
||||
pub enum TimeType {
|
||||
Timer,
|
||||
Count,
|
||||
Infinite,
|
||||
}
|
||||
|
||||
/// The inner object exists to allow the zbus proxy to share it with a runner thread
|
||||
/// and a zbus server behind `Arc<Mutex<T>>`
|
||||
pub struct CtrlAnimeInner<'a> {
|
||||
sequences: Sequences,
|
||||
client: AuraDbusClient<'a>,
|
||||
do_early_return: &'a AtomicBool,
|
||||
}
|
||||
|
||||
impl<'a> CtrlAnimeInner<'static> {
|
||||
pub fn new(
|
||||
sequences: Sequences,
|
||||
client: AuraDbusClient<'static>,
|
||||
do_early_return: &'static AtomicBool,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
sequences,
|
||||
client,
|
||||
do_early_return,
|
||||
})
|
||||
}
|
||||
/// To be called on each main loop iteration to pump out commands to the anime
|
||||
pub fn run(&self) -> Result<(), Error> {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for action in self.sequences.iter() {
|
||||
match action {
|
||||
ActionData::Animation(frames) => {
|
||||
let mut count = 0;
|
||||
let start = Instant::now();
|
||||
'animation: loop {
|
||||
for frame in frames.frames() {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
self.client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(frame.frame().clone())
|
||||
.unwrap();
|
||||
if let AnimTime::Time(time) = frames.duration() {
|
||||
if Instant::now().duration_since(start) > time {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
sleep(frame.delay());
|
||||
}
|
||||
if let AnimTime::Cycles(times) = frames.duration() {
|
||||
count += 1;
|
||||
if count >= times {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ActionData::Image(image) => {
|
||||
self.client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(image.as_ref().clone())
|
||||
.unwrap();
|
||||
}
|
||||
ActionData::Pause(duration) => {
|
||||
let start = Instant::now();
|
||||
'pause: loop {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
if Instant::now().duration_since(start) > *duration {
|
||||
break 'pause;
|
||||
}
|
||||
sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
ActionData::AudioEq => {}
|
||||
ActionData::SystemInfo => {}
|
||||
ActionData::TimeDate => {}
|
||||
ActionData::Matrix => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnime<'a> {
|
||||
config: Arc<Mutex<UserConfig>>,
|
||||
client: AuraDbusClient<'a>,
|
||||
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
|
||||
/// Must be the same Atomic as in CtrlAnimeInner
|
||||
inner_early_return: &'a AtomicBool,
|
||||
}
|
||||
|
||||
impl<'a> CtrlAnime<'static> {
|
||||
pub fn new(
|
||||
config: Arc<Mutex<UserConfig>>,
|
||||
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
|
||||
client: AuraDbusClient<'static>,
|
||||
inner_early_return: &'static AtomicBool,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(CtrlAnime {
|
||||
config,
|
||||
inner,
|
||||
client,
|
||||
inner_early_return,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
println!("CtrlAnime: add_to_server {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The pattern for a zbus method is:
|
||||
// - Get config lock if required
|
||||
// - Set inner_early_return to stop the inner run loop temporarily
|
||||
// - Do actions
|
||||
// - Write config if required
|
||||
// - Unset inner_early_return
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlAnime<'static> {
|
||||
pub fn insert_asus_gif(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
time: TimeType,
|
||||
count: u32,
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let time: AnimTime = match time {
|
||||
TimeType::Timer => AnimTime::Time(Duration::from_millis(count as u64)),
|
||||
TimeType::Count => AnimTime::Cycles(count),
|
||||
TimeType::Infinite => AnimTime::Infinite,
|
||||
};
|
||||
let file = Path::new(&file);
|
||||
let action = AnimeAction::AsusAnimation {
|
||||
file: file.into(),
|
||||
brightness,
|
||||
time,
|
||||
};
|
||||
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json = serde_json::to_string_pretty(&*config).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn insert_image_gif(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
xy: (f32, f32),
|
||||
time: TimeType,
|
||||
count: u32,
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let time: AnimTime = match time {
|
||||
TimeType::Timer => AnimTime::Time(Duration::from_millis(count as u64)),
|
||||
TimeType::Count => AnimTime::Cycles(count),
|
||||
TimeType::Infinite => AnimTime::Infinite,
|
||||
};
|
||||
let file = Path::new(&file);
|
||||
let translation = Vec2::new(xy.0, xy.1);
|
||||
let action = AnimeAction::ImageAnimation {
|
||||
file: file.into(),
|
||||
scale,
|
||||
angle,
|
||||
translation,
|
||||
brightness,
|
||||
time,
|
||||
};
|
||||
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn insert_image(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
xy: (f32, f32),
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let file = Path::new(&file);
|
||||
let action = AnimeAction::Image {
|
||||
file: file.into(),
|
||||
scale,
|
||||
angle,
|
||||
translation: Vec2::new(xy.0, xy.1),
|
||||
brightness,
|
||||
};
|
||||
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn insert_pause(&mut self, index: u32, millis: u64) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let action = AnimeAction::Pause(Duration::from_millis(millis));
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn remove_item(&mut self, index: u32) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.remove_item(index as usize);
|
||||
}
|
||||
if (index as usize) < config.anime.len() {
|
||||
config.anime.remove(index as usize);
|
||||
}
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
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().toggle_on(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().toggle_on(on)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
67
daemon-user/src/daemon.rs
Normal file
67
daemon-user/src/daemon.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::supported::SupportedFunctions;
|
||||
use rog_user::{
|
||||
ctrl_anime::{CtrlAnime, CtrlAnimeInner},
|
||||
user_config::*,
|
||||
DBUS_NAME,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
use zbus::{fdo, Connection};
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// The anime loop needs an atomic to make it exit early if required
|
||||
static ANIME_INNER_EARLY_RETURN: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
let supported = client.proxies().supported().get_supported_functions()?;
|
||||
let supported = serde_json::from_str::<SupportedFunctions>(&&supported).unwrap();
|
||||
|
||||
let mut config = UserConfig::new();
|
||||
config.load_config()?;
|
||||
let anime = config.create_anime()?;
|
||||
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
|
||||
// Create server
|
||||
let connection = Connection::new_session()?;
|
||||
fdo::DBusProxy::new(&connection)?
|
||||
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
||||
let mut server = zbus::ObjectServer::new(&connection);
|
||||
|
||||
// Set up the anime data and run loop/thread
|
||||
if supported.anime_ctrl.0 {
|
||||
// Inner behind mutex required for thread safety
|
||||
let inner = Arc::new(Mutex::new(CtrlAnimeInner::new(
|
||||
anime,
|
||||
client,
|
||||
&ANIME_INNER_EARLY_RETURN,
|
||||
)?));
|
||||
// Need new client object for dbus control part
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
let anime_control =
|
||||
CtrlAnime::new(config, inner.clone(), client, &ANIME_INNER_EARLY_RETURN)?;
|
||||
anime_control.add_to_server(&mut server);
|
||||
// Thread using inner
|
||||
let _anime_thread = thread::Builder::new()
|
||||
.name("Anime User".into())
|
||||
.spawn(move || loop {
|
||||
if let Ok(inner) = inner.try_lock() {
|
||||
inner.run().unwrap();
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
if supported.keyboard_led.per_key_led_mode {}
|
||||
|
||||
loop {
|
||||
if let Err(err) = server.try_handle_next() {
|
||||
println!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use rog_anime::error::AnimeError;
|
||||
pub enum Error {
|
||||
Io(std::io::Error),
|
||||
ConfigLoadFail,
|
||||
ConfigLockFail,
|
||||
XdgVars,
|
||||
Anime(AnimeError),
|
||||
}
|
||||
@@ -16,6 +17,7 @@ impl fmt::Display for Error {
|
||||
match self {
|
||||
Error::Io(err) => write!(f, "Failed to open: {}", err),
|
||||
Error::ConfigLoadFail => write!(f, "Failed to load user config"),
|
||||
Error::ConfigLockFail => write!(f, "Failed to lock user config"),
|
||||
Error::XdgVars => write!(f, "XDG environment vars appear unset"),
|
||||
Error::Anime(err) => write!(f, "Anime error: {}", err),
|
||||
}
|
||||
@@ -35,3 +37,9 @@ impl From<AnimeError> for Error {
|
||||
Error::Anime(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for zbus::fdo::Error {
|
||||
fn from(err: Error) -> Self {
|
||||
zbus::fdo::Error::Failed(format!("Anime zbus error: {}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
pub mod user_config;
|
||||
|
||||
pub mod error;
|
||||
|
||||
pub mod ctrl_anime;
|
||||
|
||||
pub mod zbus_anime;
|
||||
|
||||
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
||||
@@ -1,66 +0,0 @@
|
||||
use rog_anime::{Action, AnimTime};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_user::user_config::*;
|
||||
|
||||
use std::{
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let mut config = UserConfig::new();
|
||||
config.load_config()?;
|
||||
let anime = config.create_anime()?;
|
||||
|
||||
// TODO:
|
||||
// - find user config dir with xdg
|
||||
// - load user config
|
||||
// - start anime
|
||||
// A way to reload when the config changes
|
||||
|
||||
loop {
|
||||
for action in anime.iter() {
|
||||
let start = Instant::now();
|
||||
|
||||
match action {
|
||||
Action::Animation(frames) => {
|
||||
let mut count = 0;
|
||||
'animation: loop {
|
||||
for frame in frames.frames() {
|
||||
client.proxies().anime().write(frame.frame().clone())?;
|
||||
if let AnimTime::Time(time) = frames.duration() {
|
||||
if Instant::now().duration_since(start) > time {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
sleep(frame.delay());
|
||||
}
|
||||
if let AnimTime::Cycles(times) = frames.duration() {
|
||||
count += 1;
|
||||
if count >= times {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::Image(image) => {
|
||||
client.proxies().anime().write(image.as_ref().clone())?;
|
||||
}
|
||||
Action::Pause(duration) => 'pause: loop {
|
||||
if Instant::now().duration_since(start) > *duration {
|
||||
break 'pause;
|
||||
}
|
||||
sleep(Duration::from_millis(10));
|
||||
},
|
||||
Action::AudioEq => {}
|
||||
Action::SystemInfo => {}
|
||||
Action::TimeDate => {}
|
||||
Action::Matrix => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,17 @@
|
||||
use std::{
|
||||
fs::{create_dir, OpenOptions},
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rog_anime::{AnimTime, Sequences, Vec2};
|
||||
use rog_anime::{AnimTime, AnimeAction, Sequences, Vec2};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
pub struct UserConfig {
|
||||
anime: Vec<AnimeAction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum AnimeAction {
|
||||
/// Full gif sequence. Immutable.
|
||||
AsusAnimation {
|
||||
file: PathBuf,
|
||||
time: AnimTime,
|
||||
brightness: f32,
|
||||
},
|
||||
/// Basic image, can have properties changed
|
||||
ImageAnimation {
|
||||
file: PathBuf,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
translation: Vec2,
|
||||
time: AnimTime,
|
||||
brightness: f32,
|
||||
},
|
||||
Image {
|
||||
file: PathBuf,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
translation: Vec2,
|
||||
brightness: f32,
|
||||
},
|
||||
/// A pause to be used between sequences
|
||||
Pause(Duration),
|
||||
pub anime: Vec<AnimeAction>,
|
||||
}
|
||||
|
||||
impl UserConfig {
|
||||
@@ -114,38 +85,35 @@ impl UserConfig {
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
//Err(Error::ConfigLoadFail)
|
||||
}
|
||||
|
||||
pub fn write(&self) -> Result<(), Error> {
|
||||
let mut path = if let Some(dir) = dirs::config_dir() {
|
||||
dir
|
||||
} else {
|
||||
return Err(Error::XdgVars);
|
||||
};
|
||||
|
||||
path.push("rog");
|
||||
if !path.exists() {
|
||||
create_dir(path.clone())?;
|
||||
}
|
||||
|
||||
path.push("rog-user.cfg");
|
||||
|
||||
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(&path)?;
|
||||
|
||||
let json = serde_json::to_string_pretty(&self).unwrap();
|
||||
dbg!(&json);
|
||||
file.write_all(json.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_anime(&self) -> Result<Sequences, Error> {
|
||||
let mut seq = Sequences::new();
|
||||
|
||||
for anime in self.anime.iter() {
|
||||
match anime {
|
||||
AnimeAction::AsusAnimation {
|
||||
file,
|
||||
time: duration,
|
||||
brightness,
|
||||
} => seq.add_asus_gif(&file, *duration, *brightness)?,
|
||||
AnimeAction::ImageAnimation {
|
||||
file,
|
||||
scale,
|
||||
angle,
|
||||
translation,
|
||||
time: duration,
|
||||
brightness,
|
||||
} => {
|
||||
seq.add_image_gif(&file, *scale, *angle, *translation, *duration, *brightness)?
|
||||
}
|
||||
AnimeAction::Image {
|
||||
file,
|
||||
scale,
|
||||
angle,
|
||||
translation,
|
||||
brightness,
|
||||
} => seq.add_png(&file, *scale, *angle, *translation, *brightness)?,
|
||||
AnimeAction::Pause(duration) => seq.add_pause(*duration)?,
|
||||
}
|
||||
for (idx, action) in self.anime.iter().enumerate() {
|
||||
seq.insert(idx, action)?;
|
||||
}
|
||||
|
||||
Ok(seq)
|
||||
|
||||
68
daemon-user/src/zbus_anime.rs
Normal file
68
daemon-user/src/zbus_anime.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||
//! Source: `Interface '/org/asuslinux/Anime' from service 'org.asuslinux.Daemon' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(interface = "org.asuslinux.Daemon")]
|
||||
trait Daemon {
|
||||
/// InsertAsusGif method
|
||||
fn insert_asus_gif(
|
||||
&self,
|
||||
index: u32,
|
||||
file: &str,
|
||||
time: u32,
|
||||
count: u32,
|
||||
brightness: f64,
|
||||
) -> zbus::Result<String>;
|
||||
|
||||
/// InsertImage method
|
||||
fn insert_image(
|
||||
&self,
|
||||
index: u32,
|
||||
file: &str,
|
||||
scale: f64,
|
||||
angle: f64,
|
||||
xy: &(f64, f64),
|
||||
brightness: f64,
|
||||
) -> zbus::Result<String>;
|
||||
|
||||
/// InsertImageGif method
|
||||
fn insert_image_gif(
|
||||
&self,
|
||||
index: u32,
|
||||
file: &str,
|
||||
scale: f64,
|
||||
angle: f64,
|
||||
xy: &(f64, f64),
|
||||
time: u32,
|
||||
count: u32,
|
||||
brightness: f64,
|
||||
) -> zbus::Result<String>;
|
||||
|
||||
/// InsertPause method
|
||||
fn insert_pause(&self, index: u32, millis: u64) -> zbus::Result<String>;
|
||||
|
||||
/// RemoveItem method
|
||||
fn remove_item(&self, index: u32) -> zbus::Result<String>;
|
||||
|
||||
/// SetState method
|
||||
fn set_state(&self, on: bool) -> zbus::Result<()>;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ const ON_OFF: u8 = 0x04;
|
||||
|
||||
use log::{error, info, warn};
|
||||
use rog_anime::{AniMeDataBuffer, AniMePacketType};
|
||||
use rog_types::supported::AnimeSupportedFunctions;
|
||||
use rusb::{Device, DeviceHandle};
|
||||
use std::error::Error;
|
||||
use std::time::Duration;
|
||||
@@ -23,10 +24,6 @@ use zvariant::ObjectPath;
|
||||
|
||||
use crate::GetSupported;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AnimeSupportedFunctions(pub bool);
|
||||
|
||||
impl GetSupported for CtrlAnimeDisplay {
|
||||
type A = AnimeSupportedFunctions;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
//use crate::dbus::DbusEvents;
|
||||
use log::{info, warn};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use rog_types::supported::ChargeSupportedFunctions;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
@@ -12,11 +12,6 @@ use zvariant::ObjectPath;
|
||||
|
||||
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ChargeSupportedFunctions {
|
||||
pub charge_level_set: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlCharge {
|
||||
type A = ChargeSupportedFunctions;
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::error::RogError;
|
||||
use crate::{config::Config, GetSupported};
|
||||
use log::{info, warn};
|
||||
use rog_types::profile::{FanLevel, Profile, ProfileEvent};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use rog_types::{profile::{FanLevel, Profile, ProfileEvent}, supported::FanCpuSupportedFunctions};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
@@ -20,13 +19,6 @@ pub struct CtrlFanAndCpu {
|
||||
config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FanCpuSupportedFunctions {
|
||||
pub stock_fan_modes: bool,
|
||||
pub min_max_freq: bool,
|
||||
pub fan_curve_set: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlFanAndCpu {
|
||||
type A = FanCpuSupportedFunctions;
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@ use crate::{
|
||||
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
||||
};
|
||||
use log::{error, info, warn};
|
||||
use rog_types::{
|
||||
aura_modes::{AuraEffect, AuraModeNum, LedBrightness},
|
||||
LED_MSG_LEN,
|
||||
};
|
||||
use rog_types::{LED_MSG_LEN, aura_modes::{AuraEffect, AuraModeNum, LedBrightness}, supported::LedSupportedFunctions};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
@@ -24,15 +21,6 @@ use zvariant::ObjectPath;
|
||||
|
||||
use crate::GetSupported;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LedSupportedFunctions {
|
||||
pub brightness_set: bool,
|
||||
pub stock_led_modes: Option<Vec<AuraModeNum>>,
|
||||
pub multizone_led_mode: bool,
|
||||
pub per_key_led_mode: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlKbdBacklight {
|
||||
type A = LedSupportedFunctions;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
use log::{error, info, warn};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use rog_types::supported::RogBiosSupportedFunctions;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::BufRead;
|
||||
use std::io::{Read, Write};
|
||||
@@ -23,12 +23,6 @@ pub struct CtrlRogBios {
|
||||
_config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RogBiosSupportedFunctions {
|
||||
pub post_sound_toggle: bool,
|
||||
pub dedicated_gfx_toggle: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlRogBios {
|
||||
type A = RogBiosSupportedFunctions;
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::{
|
||||
ctrl_anime::{AnimeSupportedFunctions, CtrlAnimeDisplay},
|
||||
ctrl_charge::{ChargeSupportedFunctions, CtrlCharge},
|
||||
ctrl_fan_cpu::{CtrlFanAndCpu, FanCpuSupportedFunctions},
|
||||
ctrl_leds::{CtrlKbdBacklight, LedSupportedFunctions},
|
||||
ctrl_rog_bios::{CtrlRogBios, RogBiosSupportedFunctions},
|
||||
GetSupported,
|
||||
ctrl_anime::CtrlAnimeDisplay, ctrl_charge::CtrlCharge, ctrl_fan_cpu::CtrlFanAndCpu,
|
||||
ctrl_leds::CtrlKbdBacklight, ctrl_rog_bios::CtrlRogBios, GetSupported,
|
||||
};
|
||||
|
||||
use rog_types::supported::{
|
||||
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
|
||||
LedSupportedFunctions, RogBiosSupportedFunctions,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
||||
@@ -17,11 +17,12 @@ gif = "^0.11.2"
|
||||
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
zbus = "^1.9.1"
|
||||
zvariant = "^2.5"
|
||||
zvariant_derive = "^2.5"
|
||||
|
||||
glam = { version = "*", features = ["serde"] }
|
||||
|
||||
[features]
|
||||
default = ["zbus"]
|
||||
zbus = []
|
||||
default = ["z"]
|
||||
z = []
|
||||
@@ -1,5 +1,5 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[cfg(feature = "zbus")]
|
||||
#[cfg(feature = "z")]
|
||||
use zvariant_derive::Type;
|
||||
|
||||
/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and `USB_PREFIX2`
|
||||
@@ -16,7 +16,7 @@ const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
|
||||
|
||||
/// The minimal serializable data that can be transferred over wire types.
|
||||
/// Other data structures in `rog_anime` will convert to this.
|
||||
#[cfg_attr(feature = "zbus", derive(Type))]
|
||||
#[cfg_attr(feature = "z", derive(Type))]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AniMeDataBuffer(Vec<u8>);
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ use png_pong::decode::Error as PngError;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(feature = "z")]
|
||||
use zbus::fdo;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AnimeError {
|
||||
NoFrames,
|
||||
@@ -12,6 +15,8 @@ pub enum AnimeError {
|
||||
Format,
|
||||
/// The input was incorrect size, expected size is `IncorrectSize(width, height)`
|
||||
IncorrectSize(u32, u32),
|
||||
#[cfg(feature = "z")]
|
||||
Zbus(fdo::Error)
|
||||
}
|
||||
|
||||
impl fmt::Display for AnimeError {
|
||||
@@ -28,6 +33,8 @@ impl fmt::Display for AnimeError {
|
||||
"The input image size is incorrect, expected {}x{}",
|
||||
width, height
|
||||
),
|
||||
#[cfg(feature = "z")]
|
||||
AnimeError::Zbus(e) => write!(f, "ZBUS error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,3 +58,10 @@ impl From<DecodingError> for AnimeError {
|
||||
AnimeError::Gif(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "z")]
|
||||
impl From<AnimeError> for fdo::Error {
|
||||
fn from(err: AnimeError) -> Self {
|
||||
fdo::Error::Failed(format!("{}", err))
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ impl AniMeFrame {
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
pub enum AnimTime {
|
||||
/// Time in milliseconds for animation to run
|
||||
Time(Duration),
|
||||
Cycles(u32),
|
||||
Infinite,
|
||||
@@ -35,7 +36,6 @@ impl Default for AnimTime {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A gif animation. This is a collection of frames from the gif, and a duration
|
||||
/// that the animation should be shown for.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
|
||||
@@ -1,13 +1,44 @@
|
||||
use std::{path::Path, time::Duration};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use glam::Vec2;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::{AniMeDataBuffer, AniMeGif, AniMeImage, AnimTime, error::AnimeError};
|
||||
use crate::{error::AnimeError, AniMeDataBuffer, AniMeGif, AniMeImage, AnimTime};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum AnimeAction {
|
||||
/// Full gif sequence. Immutable.
|
||||
AsusAnimation {
|
||||
file: PathBuf,
|
||||
time: AnimTime,
|
||||
brightness: f32,
|
||||
},
|
||||
/// Basic image, can have properties changed
|
||||
ImageAnimation {
|
||||
file: PathBuf,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
translation: Vec2,
|
||||
time: AnimTime,
|
||||
brightness: f32,
|
||||
},
|
||||
Image {
|
||||
file: PathBuf,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
translation: Vec2,
|
||||
brightness: f32,
|
||||
},
|
||||
/// A pause to be used between sequences
|
||||
Pause(Duration),
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum Action {
|
||||
pub enum ActionData {
|
||||
/// Full gif sequence. Immutable.
|
||||
Animation(AniMeGif),
|
||||
/// Basic image, can have properties changed and image updated via those properties
|
||||
@@ -26,40 +57,92 @@ pub enum Action {
|
||||
|
||||
/// An optimised precomputed set of actions
|
||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||
pub struct Sequences(Vec<Action>);
|
||||
pub struct Sequences(Vec<ActionData>);
|
||||
|
||||
impl Sequences {
|
||||
pub fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
pub fn add_asus_gif(
|
||||
pub fn insert(&mut self, index: usize, action: &AnimeAction) -> Result<(), AnimeError> {
|
||||
match action {
|
||||
AnimeAction::AsusAnimation {
|
||||
file,
|
||||
time: duration,
|
||||
brightness,
|
||||
} => self.insert_asus_gif(index, &file, *duration, *brightness)?,
|
||||
AnimeAction::ImageAnimation {
|
||||
file,
|
||||
scale,
|
||||
angle,
|
||||
translation,
|
||||
time: duration,
|
||||
brightness,
|
||||
} => self.insert_image_gif(
|
||||
index,
|
||||
&file,
|
||||
*scale,
|
||||
*angle,
|
||||
*translation,
|
||||
*duration,
|
||||
*brightness,
|
||||
)?,
|
||||
AnimeAction::Image {
|
||||
file,
|
||||
scale,
|
||||
angle,
|
||||
translation,
|
||||
brightness,
|
||||
} => self.insert_png(index, &file, *scale, *angle, *translation, *brightness)?,
|
||||
AnimeAction::Pause(duration) => self.insert_pause(index, *duration),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_item(&mut self, index: usize) -> Option<ActionData> {
|
||||
if index < self.0.len() {
|
||||
return Some(self.0.remove(index));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn insert_asus_gif(
|
||||
&mut self,
|
||||
mut index: usize,
|
||||
file: &Path,
|
||||
duration: AnimTime,
|
||||
brightness: f32,
|
||||
) -> Result<(), AnimeError> {
|
||||
if index > self.0.len() {
|
||||
index = self.0.len() - 1;
|
||||
}
|
||||
let frames = AniMeGif::create_diagonal_gif(file, duration, brightness)?;
|
||||
self.0.push(Action::Animation(frames));
|
||||
self.0.insert(index, ActionData::Animation(frames));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_png(
|
||||
fn insert_png(
|
||||
&mut self,
|
||||
mut index: usize,
|
||||
file: &Path,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
translation: Vec2,
|
||||
brightness: f32,
|
||||
) -> Result<(), AnimeError> {
|
||||
if index > self.0.len() {
|
||||
index = self.0.len() - 1;
|
||||
}
|
||||
let image = AniMeImage::from_png(file, scale, angle, translation, brightness)?;
|
||||
let data = <AniMeDataBuffer>::from(&image);
|
||||
self.0.push(Action::Image(Box::new(data)));
|
||||
self.0.insert(index, ActionData::Image(Box::new(data)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_image_gif(
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn insert_image_gif(
|
||||
&mut self,
|
||||
mut index: usize,
|
||||
file: &Path,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
@@ -67,15 +150,20 @@ impl Sequences {
|
||||
duration: AnimTime,
|
||||
brightness: f32,
|
||||
) -> Result<(), AnimeError> {
|
||||
if index > self.0.len() {
|
||||
index = self.0.len() - 1;
|
||||
}
|
||||
let frames =
|
||||
AniMeGif::create_png_gif(file, scale, angle, translation, duration, brightness)?;
|
||||
self.0.push(Action::Animation(frames));
|
||||
self.0.insert(index, ActionData::Animation(frames));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_pause(&mut self, duration: Duration) -> Result<(), AnimeError> {
|
||||
self.0.push(Action::Pause(duration));
|
||||
Ok(())
|
||||
fn insert_pause(&mut self, mut index: usize, duration: Duration) {
|
||||
if index > self.0.len() {
|
||||
index = self.0.len() - 1;
|
||||
}
|
||||
self.0.insert(index, ActionData::Pause(duration));
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> ActionIterator {
|
||||
@@ -92,9 +180,9 @@ pub struct ActionIterator<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ActionIterator<'a> {
|
||||
type Item = &'a Action;
|
||||
type Item = &'a ActionData;
|
||||
|
||||
fn next(&mut self) -> Option<&'a Action> {
|
||||
fn next(&mut self) -> Option<&'a ActionData> {
|
||||
if self.next_idx == self.actions.0.len() {
|
||||
self.next_idx = 0;
|
||||
return None;
|
||||
|
||||
@@ -14,5 +14,5 @@ gumdrop = "^0.8"
|
||||
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
zvariant = "^2.5"
|
||||
zvariant_derive = "^2.5"
|
||||
zvariant = "^2.6"
|
||||
zvariant_derive = "^2.6"
|
||||
@@ -16,6 +16,8 @@ pub mod aura_perkey;
|
||||
|
||||
pub mod gfx_vendors;
|
||||
|
||||
pub mod supported;
|
||||
|
||||
pub mod error;
|
||||
|
||||
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
41
rog-types/src/supported.rs
Normal file
41
rog-types/src/supported.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::aura_modes::AuraModeNum;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SupportedFunctions {
|
||||
pub anime_ctrl: AnimeSupportedFunctions,
|
||||
pub charge_ctrl: ChargeSupportedFunctions,
|
||||
pub fan_cpu_ctrl: FanCpuSupportedFunctions,
|
||||
pub keyboard_led: LedSupportedFunctions,
|
||||
pub rog_bios_ctrl: RogBiosSupportedFunctions,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AnimeSupportedFunctions(pub bool);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ChargeSupportedFunctions {
|
||||
pub charge_level_set: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FanCpuSupportedFunctions {
|
||||
pub stock_fan_modes: bool,
|
||||
pub min_max_freq: bool,
|
||||
pub fan_curve_set: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LedSupportedFunctions {
|
||||
pub brightness_set: bool,
|
||||
pub stock_led_modes: Option<Vec<AuraModeNum>>,
|
||||
pub multizone_led_mode: bool,
|
||||
pub per_key_led_mode: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RogBiosSupportedFunctions {
|
||||
pub post_sound_toggle: bool,
|
||||
pub dedicated_gfx_toggle: bool,
|
||||
}
|
||||
Reference in New Issue
Block a user