diff --git a/CHANGELOG.md b/CHANGELOG.md index ac1b52bd..2d5cb5b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Display PNG images on AniMe with scale, position, angle, and brightness - AniMe display parts split out to individual crate in preparation for publishing on crates.io +- 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. # [3.3.0] - 2021-04-3 ### Changed diff --git a/Cargo.lock b/Cargo.lock index 9a926b9e..afb346f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,6 +226,18 @@ dependencies = [ "zvariant", ] +[[package]] +name = "daemon-user" +version = "1.0.0" +dependencies = [ + "dirs 3.0.1", + "rog_anime", + "rog_dbus", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "derivative" version = "2.2.0" @@ -234,7 +246,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -248,6 +260,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "enumflags2" version = "0.6.4" @@ -266,7 +298,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -292,7 +324,7 @@ dependencies = [ "proc-macro2", "quote 1.0.9", "rustversion", - "syn 1.0.64", + "syn 1.0.68", "synstructure", ] @@ -377,7 +409,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -420,7 +452,7 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -439,6 +471,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70155b56080764b8b758e91e4c63d06da0262c0c939f2cd991cd1382087147df" dependencies = [ + "serde", "spirv-std", ] @@ -459,7 +492,7 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -510,9 +543,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.90" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "libm" @@ -573,7 +606,7 @@ checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76" dependencies = [ "cc", "chrono", - "dirs", + "dirs 1.0.5", "objc-foundation", ] @@ -604,9 +637,9 @@ dependencies = [ [[package]] name = "nb-connect" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" +checksum = "a19900e7eee95eb2b3c2e26d12a874cc80aaf750e31be6fcbe743ead369fa45d" dependencies = [ "libc", "socket2", @@ -752,11 +785,11 @@ dependencies = [ [[package]] name = "polling" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" +checksum = "4fc12d774e799ee9ebae13f4076ca003b40d18a11ac0f3641e6f899618580b7b" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", "log", "wepoll-sys", @@ -781,7 +814,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", "version_check", ] @@ -810,9 +843,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid 0.2.1", ] @@ -956,22 +989,22 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "serde" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -993,7 +1026,7 @@ checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -1010,16 +1043,15 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] name = "socket2" -version = "0.3.19" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" dependencies = [ - "cfg-if 1.0.0", "libc", "winapi", ] @@ -1042,7 +1074,7 @@ checksum = "f4972082b5236fd57a46cc47fbc315ad78b5ad07b33e51077c688a2fe28d6f2d" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -1074,9 +1106,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote 1.0.9", @@ -1100,7 +1132,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", "unicode-xid 0.2.1", ] @@ -1124,11 +1156,12 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -1152,9 +1185,9 @@ dependencies = [ [[package]] name = "udev" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307c2b8c8a320a38365def5bb3ee92d146d405655196230f7a445fe4da6749f6" +checksum = "3193363f52bb34c6708ac2ffedcb5f7e5874f0329ef68e1315f27d8d768eb568" dependencies = [ "libc", "libudev-sys", @@ -1181,9 +1214,9 @@ checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "vec-arena" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" +checksum = "34b2f665b594b07095e3ac3f718e13c2197143416fae4c5706cffb7b1af8d7f1" [[package]] name = "version_check" @@ -1209,6 +1242,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "weezl" version = "0.1.4" @@ -1327,7 +1366,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] [[package]] @@ -1351,5 +1390,5 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote 1.0.9", - "syn 1.0.64", + "syn 1.0.68", ] diff --git a/Cargo.toml b/Cargo.toml index 3c6d9912..1daec777 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["asusctl", "asus-notify", "daemon", "rog-types", "rog-dbus", "rog-anime"] +members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-types", "rog-dbus", "rog-anime"] [profile.release] lto = true diff --git a/Makefile b/Makefile index d84544ec..310242a4 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ zshcpl = $(datarootdir)/zsh/site-functions BIN_C := asusctl BIN_D := asusd +BIN_U := asusd-user BIN_N := asus-notify LEDCFG := asusd-ledmodes.toml X11CFG := 90-nvidia-screen-G05.conf @@ -42,6 +43,7 @@ distclean: install: $(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)" $(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)" + $(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)" $(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)" $(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)" $(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules" @@ -50,11 +52,13 @@ install: $(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)" $(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service" $(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service" + $(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service" $(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png" $(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" $(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" $(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl" $(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish" + cd data && find "./anime" -type f -exec install -Dm 755 "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \; uninstall: rm -f "$(DESTDIR)$(bindir)/$(BIN_C)" @@ -72,6 +76,7 @@ uninstall: rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" rm -f "$(DESTDIR)$(zshcpl)/_asusctl" rm -f "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish" + rm -rf "$(DESTDIR)$(datarootdir)/asusd" update: cargo update diff --git a/asusctl/examples/animatrix-diag-png.rs b/asusctl/examples/animatrix-diag-png.rs index 5d8d8fa3..bbfa7f7b 100644 --- a/asusctl/examples/animatrix-diag-png.rs +++ b/asusctl/examples/animatrix-diag-png.rs @@ -1,8 +1,6 @@ use std::{env, error::Error, path::Path, process::exit}; -use rog_anime::{ - AniMeDataBuffer, {AniMeDiagonal, Vec2}, -}; +use rog_anime::{AniMeDataBuffer, AniMeDiagonal}; use rog_dbus::AuraDbusClient; fn main() -> Result<(), Box> { @@ -15,7 +13,8 @@ fn main() -> Result<(), Box> { exit(-1); } - let matrix = AniMeDiagonal::from_png(Path::new(&args[1]), args[2].parse::().unwrap())?; + let matrix = + AniMeDiagonal::from_png(Path::new(&args[1]), None, args[2].parse::().unwrap())?; client .proxies() diff --git a/asusctl/examples/animatrix-diag.rs b/asusctl/examples/animatrix-diag.rs index fc61282a..e823ff81 100644 --- a/asusctl/examples/animatrix-diag.rs +++ b/asusctl/examples/animatrix-diag.rs @@ -12,7 +12,7 @@ fn main() { let (client, _) = AuraDbusClient::new().unwrap(); for step in (2..50).rev() { - let mut matrix = AniMeDiagonal::new(); + let mut matrix = AniMeDiagonal::new(None); for c in (0..60).into_iter().step_by(step) { for i in matrix.get_mut().iter_mut() { i[c] = 50; diff --git a/asusctl/examples/animatrix-gif.rs b/asusctl/examples/animatrix-gif.rs index 1cc387a5..3bd1f63e 100644 --- a/asusctl/examples/animatrix-gif.rs +++ b/asusctl/examples/animatrix-gif.rs @@ -1,6 +1,6 @@ use std::{env, path::Path, thread::sleep}; -use rog_anime::AniMeBlock; +use rog_anime::{Action, Sequences}; use rog_dbus::AuraDbusClient; fn main() { @@ -14,16 +14,21 @@ fn main() { let path = Path::new(&args[1]); let brightness = args[2].parse::().unwrap(); - let gif = AniMeBlock::asus_gif(path, brightness).unwrap(); + let mut seq = Sequences::new(); + seq.add_asus_gif(path, None, brightness).unwrap(); loop { - for frame in gif.get_animation().unwrap().frames() { - client - .proxies() - .anime() - .write(frame.frame().clone()) - .unwrap(); - sleep(frame.delay()); + for action in seq.iter() { + if let Action::Animation(frames) = action { + for frame in frames.frames() { + client + .proxies() + .anime() + .write(frame.frame().clone()) + .unwrap(); + sleep(frame.delay()); + } + } } } } diff --git a/asusctl/examples/animatrix-grid.rs b/asusctl/examples/animatrix-grid.rs index 8678f1cd..8769fc06 100644 --- a/asusctl/examples/animatrix-grid.rs +++ b/asusctl/examples/animatrix-grid.rs @@ -8,7 +8,7 @@ use rog_dbus::AuraDbusClient; fn main() { let (client, _) = AuraDbusClient::new().unwrap(); - let mut matrix = AniMeGrid::new(); + let mut matrix = AniMeGrid::new(None); let tmp = matrix.get_mut(); let mut i = 0; diff --git a/asusctl/examples/animatrix-png-gif.rs b/asusctl/examples/animatrix-png-gif.rs index 5d1a8ef9..b2af2eaa 100644 --- a/asusctl/examples/animatrix-png-gif.rs +++ b/asusctl/examples/animatrix-png-gif.rs @@ -1,20 +1,28 @@ -use std::{env, path::Path, thread::sleep}; +use std::{ + env, + path::Path, + thread::sleep, + time::{Duration, Instant}, +}; use glam::Vec2; -use rog_anime::AniMeBlock; +use rog_anime::{Action, Sequences}; use rog_dbus::AuraDbusClient; fn main() { let (client, _) = AuraDbusClient::new().unwrap(); let args: Vec = env::args().into_iter().collect(); - if args.len() != 7 { - println!("Usage: "); - println!("e.g, asusctl/examples/file.gif 0.9 0.4 0.0 0.0 0.8"); + if args.len() < 7 { + println!( + "Usage: " + ); + println!("e.g, asusctl/examples/file.gif 0.9 0.4 0.0 0.0 0.8 0"); return; } - let gif = AniMeBlock::image_gif( + let mut seq = Sequences::new(); + seq.add_image_gif( Path::new(&args[1]), args[2].parse::().unwrap(), args[3].parse::().unwrap(), @@ -22,18 +30,62 @@ fn main() { args[4].parse::().unwrap(), args[5].parse::().unwrap(), ), + if let Ok(time) = args[7].parse::() { + if time != 0 { + Some(Duration::from_secs(time)) + } else { + None + } + } else { + None + }, args[6].parse::().unwrap(), ) .unwrap(); + if args.len() == 9 { + seq.add_image_gif( + Path::new(&args[8]), + args[2].parse::().unwrap(), + args[3].parse::().unwrap(), + Vec2::new( + args[4].parse::().unwrap(), + args[5].parse::().unwrap(), + ), + if let Ok(time) = args[7].parse::() { + if time != 0 { + Some(Duration::from_secs(time)) + } else { + None + } + } else { + None + }, + args[6].parse::().unwrap(), + ) + .unwrap(); + } + loop { - for frame in gif.get_animation().unwrap().frames() { - client - .proxies() - .anime() - .write(frame.frame().clone()) - .unwrap(); - sleep(frame.delay()); + for action in seq.iter() { + if let Action::Animation(frames) = action { + let start = Instant::now(); + 'outer: loop { + for frame in frames.frames() { + client + .proxies() + .anime() + .write(frame.frame().clone()) + .unwrap(); + if let Some(time) = frames.duration() { + if Instant::now().duration_since(start) > time { + break 'outer; + } + } + sleep(frame.delay()); + } + } + } } } } diff --git a/asusctl/examples/controller.png b/asusctl/examples/controller.png deleted file mode 100644 index 36e29a15..00000000 Binary files a/asusctl/examples/controller.png and /dev/null differ diff --git a/asusctl/examples/diag_sq.png b/asusctl/examples/diag_sq.png deleted file mode 100644 index 36e29a15..00000000 Binary files a/asusctl/examples/diag_sq.png and /dev/null differ diff --git a/asusctl/examples/levelup.png b/asusctl/examples/levelup.png deleted file mode 100644 index b7a8d333..00000000 Binary files a/asusctl/examples/levelup.png and /dev/null differ diff --git a/asusctl/examples/sunset.gif b/asusctl/examples/sunset.gif deleted file mode 100644 index f114859c..00000000 Binary files a/asusctl/examples/sunset.gif and /dev/null differ diff --git a/daemon-user/Cargo.toml b/daemon-user/Cargo.toml new file mode 100644 index 00000000..85426905 --- /dev/null +++ b/daemon-user/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "daemon-user" +version = "1.0.0" +authors = ["Luke D Jones "] +edition = "2018" +description = "Usermode daemon for user settings, anime, per-key lighting" + +[lib] +name = "rog_user" +path = "src/lib.rs" + +[[bin]] +name = "asusd-user" +path = "src/main.rs" + +[dependencies] +# serialisation +serde = "^1.0" +serde_json = "^1.0" +serde_derive = "^1.0" + +rog_anime = { path = "../rog-anime" } +rog_dbus = { path = "../rog-dbus" } + +dirs = "3.0.1" \ No newline at end of file diff --git a/daemon-user/src/error.rs b/daemon-user/src/error.rs new file mode 100644 index 00000000..86496894 --- /dev/null +++ b/daemon-user/src/error.rs @@ -0,0 +1,37 @@ +use std::fmt; + +use rog_anime::error::AnimeError; + +#[derive(Debug)] +pub enum Error { + Io(std::io::Error), + ConfigLoadFail, + XdgVars, + Anime(AnimeError), +} + +impl fmt::Display for Error { + // This trait requires `fmt` with this exact signature. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Io(err) => write!(f, "Failed to open: {}", err), + Error::ConfigLoadFail => write!(f, "Failed to load user config"), + Error::XdgVars => write!(f, "XDG environment vars appear unset"), + Error::Anime(err) => write!(f, "Anime error: {}", err), + } + } +} + +impl std::error::Error for Error {} + +impl From for Error { + fn from(err: std::io::Error) -> Self { + Error::Io(err) + } +} + +impl From for Error { + fn from(err: AnimeError) -> Self { + Error::Anime(err) + } +} diff --git a/daemon-user/src/lib.rs b/daemon-user/src/lib.rs new file mode 100644 index 00000000..3a8034bb --- /dev/null +++ b/daemon-user/src/lib.rs @@ -0,0 +1,3 @@ +pub mod user_config; + +pub mod error; diff --git a/daemon-user/src/main.rs b/daemon-user/src/main.rs new file mode 100644 index 00000000..db224b72 --- /dev/null +++ b/daemon-user/src/main.rs @@ -0,0 +1,60 @@ +use rog_anime::Action; +use rog_dbus::AuraDbusClient; +use rog_user::user_config::*; + +use std::{ + thread::sleep, + time::{Duration, Instant}, +}; + +fn main() -> Result<(), Box> { + 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) => 'animation: loop { + for frame in frames.frames() { + client.proxies().anime().write(frame.frame().clone())?; + if let Some(time) = frames.duration() { + if Instant::now().duration_since(start) > time { + break 'animation; + } + } + sleep(frame.delay()); + } + if frames.duration().is_none() { + 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 => {} + } + } + } +} diff --git a/daemon-user/src/user_config.rs b/daemon-user/src/user_config.rs new file mode 100644 index 00000000..f346b055 --- /dev/null +++ b/daemon-user/src/user_config.rs @@ -0,0 +1,151 @@ +use std::{ + fs::{create_dir, OpenOptions}, + io::{Read, Write}, + path::PathBuf, + time::Duration, +}; + +use rog_anime::{Sequences, Vec2}; +use serde_derive::{Deserialize, Serialize}; + +use crate::error::Error; + +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct UserConfig { + anime: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum AnimeAction { + /// Full gif sequence. Immutable. + AsusAnimation { + file: PathBuf, + duration: Option, + brightness: f32, + }, + /// Basic image, can have properties changed + ImageAnimation { + file: PathBuf, + scale: f32, + angle: f32, + translation: Vec2, + duration: Option, + brightness: f32, + }, + Image { + file: PathBuf, + scale: f32, + angle: f32, + translation: Vec2, + brightness: f32, + }, + /// A pause to be used between sequences + Pause(Duration), +} + +impl UserConfig { + pub fn new() -> Self { + Self { + anime: vec![ + AnimeAction::AsusAnimation { + file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(), + brightness: 0.5, + duration: None, + }, + AnimeAction::ImageAnimation { + file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(), + scale: 0.9, + angle: 0.65, + translation: Vec2::default(), + brightness: 0.5, + duration: Some(Duration::from_secs(5)), + }, + AnimeAction::Image { + file: "/usr/share/asusd/anime/custom/rust.png".into(), + scale: 1.0, + angle: 0.0, + translation: Vec2::default(), + brightness: 0.6, + }, + AnimeAction::Pause(Duration::from_secs(6)), + AnimeAction::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: 0.5, + duration: None, + }, + ], + } + } + + pub fn load_config(&mut 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() + .read(true) + .write(true) + .create(true) + .open(&path)?; + + let mut buf = String::new(); + + if let Ok(read_len) = file.read_to_string(&mut buf) { + if read_len == 0 { + let json = serde_json::to_string_pretty(&self).unwrap(); + file.write_all(json.as_bytes())?; + } else if let Ok(data) = serde_json::from_str::(&buf) { + self.anime = data.anime; + return Ok(()); + } + } + Ok(()) + //Err(Error::ConfigLoadFail) + } + + pub fn create_anime(&self) -> Result { + let mut seq = Sequences::new(); + + for anime in self.anime.iter() { + match anime { + AnimeAction::AsusAnimation { + file, + duration, + brightness, + } => seq.add_asus_gif(&file, *duration, *brightness)?, + AnimeAction::ImageAnimation { + file, + scale, + angle, + translation, + 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)?, + } + } + + Ok(seq) + } +} diff --git a/daemon/src/ctrl_anime.rs b/daemon/src/ctrl_anime.rs index 8ee2fdc5..b84ac5ab 100644 --- a/daemon/src/ctrl_anime.rs +++ b/daemon/src/ctrl_anime.rs @@ -16,10 +16,10 @@ const ON_OFF: u8 = 0x04; use log::{error, info, warn}; use rog_anime::{AniMeDataBuffer, AniMePacketType}; use rusb::{Device, DeviceHandle}; -use zvariant::ObjectPath; use std::error::Error; use std::time::Duration; use zbus::dbus_interface; +use zvariant::ObjectPath; use crate::GetSupported; @@ -52,7 +52,10 @@ pub trait Dbus { impl crate::ZbusAdd for CtrlAnimeDisplay { fn add_to_server(self, server: &mut zbus::ObjectServer) { server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"), self) + .at( + &ObjectPath::from_str_unchecked("/org/asuslinux/Anime"), + self, + ) .map_err(|err| { warn!("CtrlAnimeDisplay: add_to_server {}", err); err diff --git a/daemon/src/ctrl_charge.rs b/daemon/src/ctrl_charge.rs index e5509634..e583f584 100644 --- a/daemon/src/ctrl_charge.rs +++ b/daemon/src/ctrl_charge.rs @@ -2,13 +2,13 @@ use crate::{config::Config, error::RogError, GetSupported}; //use crate::dbus::DbusEvents; use log::{info, warn}; use serde_derive::{Deserialize, Serialize}; -use zvariant::ObjectPath; use std::fs::OpenOptions; use std::io::Write; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use zbus::dbus_interface; +use zvariant::ObjectPath; static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold"; @@ -64,7 +64,10 @@ impl CtrlCharge { impl crate::ZbusAdd for CtrlCharge { fn add_to_server(self, server: &mut zbus::ObjectServer) { server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"), self) + .at( + &ObjectPath::from_str_unchecked("/org/asuslinux/Charge"), + self, + ) .map_err(|err| { warn!("CtrlCharge: add_to_server {}", err); err diff --git a/daemon/src/ctrl_fan_cpu.rs b/daemon/src/ctrl_fan_cpu.rs index 601d1614..f01d67ed 100644 --- a/daemon/src/ctrl_fan_cpu.rs +++ b/daemon/src/ctrl_fan_cpu.rs @@ -3,13 +3,13 @@ use crate::{config::Config, GetSupported}; use log::{info, warn}; use rog_types::profile::{FanLevel, Profile, ProfileEvent}; use serde_derive::{Deserialize, Serialize}; -use zvariant::ObjectPath; use std::fs::OpenOptions; use std::io::Write; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use zbus::{dbus_interface, fdo::Error}; +use zvariant::ObjectPath; 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"; @@ -181,7 +181,10 @@ impl DbusFanAndCpu { impl crate::ZbusAdd for DbusFanAndCpu { fn add_to_server(self, server: &mut zbus::ObjectServer) { server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"), self) + .at( + &ObjectPath::from_str_unchecked("/org/asuslinux/Profile"), + self, + ) .map_err(|err| { warn!("DbusFanAndCpu: add_to_server {}", err); err diff --git a/daemon/src/ctrl_gfx/gfx.rs b/daemon/src/ctrl_gfx/gfx.rs index e9c8a3e9..866e1ba5 100644 --- a/daemon/src/ctrl_gfx/gfx.rs +++ b/daemon/src/ctrl_gfx/gfx.rs @@ -7,7 +7,6 @@ use logind_zbus::{ ManagerProxy, SessionProxy, }; use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; -use zvariant::ObjectPath; use std::{io::Write, ops::Add, path::Path, time::Instant}; use std::{iter::FromIterator, thread::JoinHandle}; use std::{process::Command, thread::sleep, time::Duration}; @@ -16,6 +15,7 @@ use std::{sync::Arc, sync::Mutex}; use sysfs_class::{PciDevice, SysClass}; use system::{GraphicsDevice, PciBus}; use zbus::{dbus_interface, Connection}; +use zvariant::ObjectPath; use crate::*; diff --git a/daemon/src/ctrl_leds.rs b/daemon/src/ctrl_leds.rs index 8643e339..cb5d0502 100644 --- a/daemon/src/ctrl_leds.rs +++ b/daemon/src/ctrl_leds.rs @@ -14,13 +14,13 @@ use rog_types::{ aura_modes::{AuraEffect, AuraModeNum, LedBrightness}, LED_MSG_LEN, }; -use zvariant::ObjectPath; use std::fs::OpenOptions; use std::io::{Read, Write}; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use zbus::dbus_interface; +use zvariant::ObjectPath; use crate::GetSupported; diff --git a/daemon/src/ctrl_rog_bios.rs b/daemon/src/ctrl_rog_bios.rs index c12d6607..fce680fa 100644 --- a/daemon/src/ctrl_rog_bios.rs +++ b/daemon/src/ctrl_rog_bios.rs @@ -1,7 +1,6 @@ use crate::{config::Config, error::RogError, GetSupported}; use log::{error, info, warn}; use serde_derive::{Deserialize, Serialize}; -use zvariant::ObjectPath; use std::fs::OpenOptions; use std::io::BufRead; use std::io::{Read, Write}; @@ -10,6 +9,7 @@ use std::process::Command; use std::sync::Arc; use std::sync::Mutex; use zbus::dbus_interface; +use zvariant::ObjectPath; const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs"; const DRACUT_PATH: &str = "/usr/bin/dracut"; @@ -102,7 +102,10 @@ impl CtrlRogBios { impl crate::ZbusAdd for CtrlRogBios { fn add_to_server(self, server: &mut zbus::ObjectServer) { server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/RogBios"), self) + .at( + &ObjectPath::from_str_unchecked("/org/asuslinux/RogBios"), + self, + ) .map_err(|err| { warn!("CtrlRogBios: add_to_server {}", err); err diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 1c1c8f7d..335827a1 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -31,7 +31,10 @@ impl SupportedFunctions { impl crate::ZbusAdd for SupportedFunctions { fn add_to_server(self, server: &mut zbus::ObjectServer) { server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Supported"), self) + .at( + &ObjectPath::from_str_unchecked("/org/asuslinux/Supported"), + self, + ) .map_err(|err| { warn!("SupportedFunctions: add_to_server {}", err); err diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 64cd601f..7bd8b29c 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -175,10 +175,13 @@ fn start_daemon() -> Result<(), Box> { }); object_server - .with(&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"), |obj: &CtrlCharge| { - let x = obj.limit(); - obj.notify_charge(x as u8) - }) + .with( + &ObjectPath::from_str_unchecked("/org/asuslinux/Charge"), + |obj: &CtrlCharge| { + let x = obj.limit(); + obj.notify_charge(x as u8) + }, + ) .map_err(|err| { warn!("object_server notify_charge error: {}", err); }) diff --git a/data/anime/Festive/Cupid.gif b/data/anime/asus/festive/Cupid.gif similarity index 100% rename from data/anime/Festive/Cupid.gif rename to data/anime/asus/festive/Cupid.gif diff --git a/data/anime/Festive/Firework.gif b/data/anime/asus/festive/Firework.gif similarity index 100% rename from data/anime/Festive/Firework.gif rename to data/anime/asus/festive/Firework.gif diff --git a/data/anime/Festive/Halloween.gif b/data/anime/asus/festive/Halloween.gif similarity index 100% rename from data/anime/Festive/Halloween.gif rename to data/anime/asus/festive/Halloween.gif diff --git a/data/anime/Festive/Happy Holiday.gif b/data/anime/asus/festive/Happy Holiday.gif similarity index 100% rename from data/anime/Festive/Happy Holiday.gif rename to data/anime/asus/festive/Happy Holiday.gif diff --git a/data/anime/Festive/Happy new year.gif b/data/anime/asus/festive/Happy new year.gif similarity index 100% rename from data/anime/Festive/Happy new year.gif rename to data/anime/asus/festive/Happy new year.gif diff --git a/data/anime/Festive/Lantern.gif b/data/anime/asus/festive/Lantern.gif similarity index 100% rename from data/anime/Festive/Lantern.gif rename to data/anime/asus/festive/Lantern.gif diff --git a/data/anime/Festive/Valentine's Day.gif b/data/anime/asus/festive/Valentine's Day.gif similarity index 100% rename from data/anime/Festive/Valentine's Day.gif rename to data/anime/asus/festive/Valentine's Day.gif diff --git a/data/anime/Festive/Year of the Ox.gif b/data/anime/asus/festive/Year of the Ox.gif similarity index 100% rename from data/anime/Festive/Year of the Ox.gif rename to data/anime/asus/festive/Year of the Ox.gif diff --git a/data/anime/Gaming/Bird.gif b/data/anime/asus/gaming/Bird.gif similarity index 100% rename from data/anime/Gaming/Bird.gif rename to data/anime/asus/gaming/Bird.gif diff --git a/data/anime/Gaming/Controller.gif b/data/anime/asus/gaming/Controller.gif similarity index 100% rename from data/anime/Gaming/Controller.gif rename to data/anime/asus/gaming/Controller.gif diff --git a/data/anime/Gaming/FPS.gif b/data/anime/asus/gaming/FPS.gif similarity index 100% rename from data/anime/Gaming/FPS.gif rename to data/anime/asus/gaming/FPS.gif diff --git a/data/anime/Gaming/Fight.gif b/data/anime/asus/gaming/Fight.gif similarity index 100% rename from data/anime/Gaming/Fight.gif rename to data/anime/asus/gaming/Fight.gif diff --git a/data/anime/Gaming/Keyboard.gif b/data/anime/asus/gaming/Keyboard.gif similarity index 100% rename from data/anime/Gaming/Keyboard.gif rename to data/anime/asus/gaming/Keyboard.gif diff --git a/data/anime/Gaming/MOBA.gif b/data/anime/asus/gaming/MOBA.gif similarity index 100% rename from data/anime/Gaming/MOBA.gif rename to data/anime/asus/gaming/MOBA.gif diff --git a/data/anime/Gaming/UFO.gif b/data/anime/asus/gaming/UFO.gif similarity index 100% rename from data/anime/Gaming/UFO.gif rename to data/anime/asus/gaming/UFO.gif diff --git a/data/anime/Music/DJ.gif b/data/anime/asus/music/DJ.gif similarity index 100% rename from data/anime/Music/DJ.gif rename to data/anime/asus/music/DJ.gif diff --git a/data/anime/Music/Music-player.gif b/data/anime/asus/music/Music-player.gif similarity index 100% rename from data/anime/Music/Music-player.gif rename to data/anime/asus/music/Music-player.gif diff --git a/data/anime/ROG Gallery/For-those-who-dare.gif b/data/anime/asus/rog/For-those-who-dare.gif similarity index 100% rename from data/anime/ROG Gallery/For-those-who-dare.gif rename to data/anime/asus/rog/For-those-who-dare.gif diff --git a/data/anime/ROG Gallery/For-those-who-dare_2.gif b/data/anime/asus/rog/For-those-who-dare_2.gif similarity index 100% rename from data/anime/ROG Gallery/For-those-who-dare_2.gif rename to data/anime/asus/rog/For-those-who-dare_2.gif diff --git a/data/anime/ROG Gallery/Fragment.gif b/data/anime/asus/rog/Fragment.gif similarity index 100% rename from data/anime/ROG Gallery/Fragment.gif rename to data/anime/asus/rog/Fragment.gif diff --git a/data/anime/ROG Gallery/Infinite-triangle.gif b/data/anime/asus/rog/Infinite-triangle.gif similarity index 100% rename from data/anime/ROG Gallery/Infinite-triangle.gif rename to data/anime/asus/rog/Infinite-triangle.gif diff --git a/data/anime/ROG Gallery/Kaleidoscope1.gif b/data/anime/asus/rog/Kaleidoscope1.gif similarity index 100% rename from data/anime/ROG Gallery/Kaleidoscope1.gif rename to data/anime/asus/rog/Kaleidoscope1.gif diff --git a/data/anime/ROG Gallery/Kaleidoscope2.gif b/data/anime/asus/rog/Kaleidoscope2.gif similarity index 100% rename from data/anime/ROG Gallery/Kaleidoscope2.gif rename to data/anime/asus/rog/Kaleidoscope2.gif diff --git a/data/anime/ROG Gallery/Kaleidoscope2.png b/data/anime/asus/rog/Kaleidoscope2.png similarity index 100% rename from data/anime/ROG Gallery/Kaleidoscope2.png rename to data/anime/asus/rog/Kaleidoscope2.png diff --git a/data/anime/ROG Gallery/Sunset.gif b/data/anime/asus/rog/Sunset.gif similarity index 100% rename from data/anime/ROG Gallery/Sunset.gif rename to data/anime/asus/rog/Sunset.gif diff --git a/data/anime/Trend/Dog.gif b/data/anime/asus/trend/Dog.gif similarity index 100% rename from data/anime/Trend/Dog.gif rename to data/anime/asus/trend/Dog.gif diff --git a/data/anime/Trend/Ski.gif b/data/anime/asus/trend/Ski.gif similarity index 100% rename from data/anime/Trend/Ski.gif rename to data/anime/asus/trend/Ski.gif diff --git a/data/anime/Trend/Wave.gif b/data/anime/asus/trend/Wave.gif similarity index 100% rename from data/anime/Trend/Wave.gif rename to data/anime/asus/trend/Wave.gif diff --git a/data/anime/custom/rust.png b/data/anime/custom/rust.png new file mode 100644 index 00000000..e9a4c2e3 Binary files /dev/null and b/data/anime/custom/rust.png differ diff --git a/data/asusd-user.service b/data/asusd-user.service new file mode 100644 index 00000000..ba845176 --- /dev/null +++ b/data/asusd-user.service @@ -0,0 +1,14 @@ +[Unit] +Description=ASUS User Daemon +StartLimitInterval=200 +StartLimitBurst=2 + +[Service] +ExecStartPre=/usr/bin/sleep 2 +ExecStart=/usr/bin/asusd-user +Restart=on-failure +RestartSec=1 +Type=simple + +[Install] +WantedBy=default.target \ No newline at end of file diff --git a/data/user-example.json b/data/user-example.json new file mode 100644 index 00000000..b80d8e3e --- /dev/null +++ b/data/user-example.json @@ -0,0 +1,45 @@ +{ + "anime": [ + { + "AsusAnimation": { + "file": "/usr/share/asusd/anime/asus/Controller.gif", + "duration": { + "secs": 5, + "nanos": 0 + } + } + }, + { + "ImageAnimation": { + "file": "/usr/share/asusd/anime/sonic.gif", + "scale": 0.9, + "angle": 0.65, + "translation": [ + 0.0, + 0.0 + ], + "duration": { + "secs": 5, + "nanos": 0 + }, + "brightness": 0.5 + } + }, + { + "Image": { + "file_path": "/usr/share/asusd/anime/doom.png", + "scale": 0.7, + "angle": 0.0, + "translation": [ + 0.0, + 0.0 + ], + "duration": { + "secs": 5, + "nanos": 0 + }, + "brightness": 0.6 + } + } + ] + } \ No newline at end of file diff --git a/rog-anime/Cargo.toml b/rog-anime/Cargo.toml index 50fd09ae..2ced82eb 100644 --- a/rog-anime/Cargo.toml +++ b/rog-anime/Cargo.toml @@ -11,15 +11,17 @@ edition = "2018" [dependencies] png_pong = "^0.8.0" -glam = "*" pix = "0.13" gif = "^0.11.2" + serde = "^1.0" serde_derive = "^1.0" zvariant = "^2.5" zvariant_derive = "^2.5" +glam = { version = "*", features = ["serde"] } + [features] default = ["zbus"] zbus = [] \ No newline at end of file diff --git a/rog-anime/src/anime_data.rs b/rog-anime/src/data.rs similarity index 100% rename from rog-anime/src/anime_data.rs rename to rog-anime/src/data.rs diff --git a/rog-anime/src/anime_diagonal.rs b/rog-anime/src/diagonal.rs similarity index 90% rename from rog-anime/src/anime_diagonal.rs rename to rog-anime/src/diagonal.rs index 31b22982..d21c89a3 100644 --- a/rog-anime/src/anime_diagonal.rs +++ b/rog-anime/src/diagonal.rs @@ -1,25 +1,26 @@ -use std::path::Path; +use std::{path::Path, time::Duration}; use crate::{ - anime_data::{AniMeDataBuffer, ANIME_DATA_LEN}, + data::{AniMeDataBuffer, ANIME_DATA_LEN}, error::AnimeError, }; const WIDTH: usize = 74; const HEIGHT: usize = 36; +/// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images) #[derive(Debug, Clone)] -pub struct AniMeDiagonal([[u8; WIDTH]; HEIGHT]); +pub struct AniMeDiagonal([[u8; WIDTH]; HEIGHT], Option); impl Default for AniMeDiagonal { fn default() -> Self { - Self::new() + Self::new(None) } } impl AniMeDiagonal { - pub fn new() -> Self { - Self([[0u8; WIDTH]; HEIGHT]) + pub fn new(duration: Option) -> Self { + Self([[0u8; WIDTH]; HEIGHT], duration) } pub fn get_mut(&mut self) -> &mut [[u8; WIDTH]; HEIGHT] { @@ -38,14 +39,18 @@ impl AniMeDiagonal { /// Generate the base image from inputs. The result can be displayed as is or /// updated via scale, position, or angle then displayed again after `update()`. - pub fn from_png(path: &Path, bright: f32) -> Result { + pub fn from_png( + path: &Path, + duration: Option, + bright: f32, + ) -> Result { use pix::el::Pixel; let data = std::fs::read(path)?; let data = std::io::Cursor::new(data); let decoder = png_pong::Decoder::new(data)?.into_steps(); let png_pong::Step { raster, delay: _ } = decoder.last().ok_or(AnimeError::NoFrames)??; - let mut matrix = AniMeDiagonal::new(); + let mut matrix = AniMeDiagonal::new(duration); let width; match raster { diff --git a/rog-anime/src/anime_gif.rs b/rog-anime/src/gif.rs similarity index 84% rename from rog-anime/src/anime_gif.rs rename to rog-anime/src/gif.rs index e5e7e07e..59b837a7 100644 --- a/rog-anime/src/anime_gif.rs +++ b/rog-anime/src/gif.rs @@ -22,13 +22,19 @@ impl AniMeFrame { } } +/// 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)] -pub struct AniMeGif(Vec); +pub struct AniMeGif(Vec, Option); impl AniMeGif { /// Create an animation using the 74x36 ASUS gif format - pub fn create_diagonal_gif(file_name: &Path, brightness: f32) -> Result { - let mut matrix = AniMeDiagonal::new(); + pub fn create_diagonal_gif( + file_name: &Path, + duration: Option, + brightness: f32, + ) -> Result { + let mut matrix = AniMeDiagonal::new(None); let mut decoder = gif::DecodeOptions::new(); // Configure the decoder such that it will expand the image to RGBA. @@ -59,7 +65,7 @@ impl AniMeGif { delay: Duration::from_millis(wait as u64), }); } - Ok(Self(frames)) + Ok(Self(frames, duration)) } /// Create an animation using a gif of any size. This method must precompute the @@ -69,6 +75,7 @@ impl AniMeGif { scale: f32, angle: f32, translation: Vec2, + duration: Option, brightness: f32, ) -> Result { let mut frames = Vec::new(); @@ -98,8 +105,14 @@ impl AniMeGif { if matches!(frame.dispose, gif::DisposalMethod::Background) { let pixels: Vec = vec![Pixel::default(); (width as u32 * height as u32) as usize]; - image = - AniMeImage::new(Vec2::new(scale,scale), angle, translation, brightness, pixels, width as u32); + image = AniMeImage::new( + Vec2::new(scale, scale), + angle, + translation, + brightness, + pixels, + width as u32, + ); } for (y, row) in frame.buffer.chunks(frame.width as usize * 4).enumerate() { for (x, px) in row.chunks(4).enumerate() { @@ -122,10 +135,14 @@ impl AniMeGif { delay: Duration::from_millis(wait as u64), }); } - Ok(Self(frames)) + Ok(Self(frames, duration)) } pub fn frames(&self) -> &[AniMeFrame] { &self.0 } + + pub fn duration(&self) -> Option { + self.1 + } } diff --git a/rog-anime/src/anime_grid.rs b/rog-anime/src/grid.rs similarity index 95% rename from rog-anime/src/anime_grid.rs rename to rog-anime/src/grid.rs index 253f6406..36bc6198 100644 --- a/rog-anime/src/anime_grid.rs +++ b/rog-anime/src/grid.rs @@ -1,5 +1,7 @@ -use crate::anime_data::{AniMeDataBuffer, ANIME_DATA_LEN}; -use crate::anime_image::LED_IMAGE_POSITIONS; +use std::time::Duration; + +use crate::data::{AniMeDataBuffer, ANIME_DATA_LEN}; +use crate::image::LED_IMAGE_POSITIONS; const WIDTH: usize = 33; const HEIGHT: usize = 55; @@ -10,17 +12,17 @@ const HEIGHT: usize = 55; /// Width = 33 /// height = 55 #[derive(Debug, Clone)] -pub struct AniMeGrid([[u8; WIDTH]; HEIGHT]); +pub struct AniMeGrid([[u8; WIDTH]; HEIGHT], Option); impl Default for AniMeGrid { fn default() -> Self { - Self::new() + Self::new(None) } } impl AniMeGrid { - pub fn new() -> Self { - AniMeGrid([[0u8; WIDTH]; HEIGHT]) + pub fn new(duration: Option) -> Self { + AniMeGrid([[0u8; WIDTH]; HEIGHT], duration) } pub fn set(&mut self, x: usize, y: usize, b: u8) { @@ -97,11 +99,11 @@ impl From for AniMeDataBuffer { #[cfg(test)] mod tests { - use crate::anime_grid::*; + use crate::grid::*; #[test] fn check_data_alignment() { - let mut matrix = AniMeGrid::new(); + let mut matrix = AniMeGrid::new(None); { let tmp = matrix.get_mut(); for row in tmp.iter_mut() { diff --git a/rog-anime/src/anime_image.rs b/rog-anime/src/image.rs similarity index 99% rename from rog-anime/src/anime_image.rs rename to rog-anime/src/image.rs index d9901348..595edf37 100644 --- a/rog-anime/src/anime_image.rs +++ b/rog-anime/src/image.rs @@ -4,7 +4,7 @@ pub use glam::Vec2; use glam::{Mat3, Vec3}; use crate::{ - anime_data::{AniMeDataBuffer, ANIME_DATA_LEN}, + data::{AniMeDataBuffer, ANIME_DATA_LEN}, error::AnimeError, }; @@ -252,7 +252,7 @@ impl AniMeImage { width = ras.width(); ras.pixels() .iter() - .map(|px| crate::anime_image::Pixel { + .map(|px| crate::image::Pixel { color: ::from(px.one()) as u32, alpha: ::from(px.alpha()), }) @@ -261,7 +261,14 @@ impl AniMeImage { _ => return Err(AnimeError::Format), }; - let mut matrix = AniMeImage::new(Vec2::new(scale, scale), angle, translation, bright, pixels, width); + let mut matrix = AniMeImage::new( + Vec2::new(scale, scale), + angle, + translation, + bright, + pixels, + width, + ); matrix.update(); Ok(matrix) @@ -1539,7 +1546,7 @@ pub const LED_IMAGE_POSITIONS: [Option; LED_PIXEL_LEN] = [ #[cfg(test)] mod tests { - use crate::anime_image::*; + use crate::image::*; #[test] fn led_positions() { diff --git a/rog-anime/src/lib.rs b/rog-anime/src/lib.rs index f44a51b0..9bba7e0c 100644 --- a/rog-anime/src/lib.rs +++ b/rog-anime/src/lib.rs @@ -1,89 +1,25 @@ -use serde_derive::{Deserialize, Serialize}; /// The main data conversion for transfering in shortform over dbus or other, /// or writing directly to the USB device -mod anime_data; -use std::{path::Path, time::Duration}; +mod data; -pub use anime_data::*; +pub use data::*; /// Useful for specialised effects that required a grid of data -mod anime_grid; -pub use anime_grid::*; +mod grid; +pub use grid::*; /// Transform a PNG image for displaying on AniMe matrix display -mod anime_image; -pub use anime_image::*; +mod image; +pub use image::*; -mod anime_diagonal; -pub use anime_diagonal::*; +mod diagonal; +pub use diagonal::*; -mod anime_gif; -pub use anime_gif::*; -use error::AnimeError; +mod gif; +pub use crate::gif::*; + +mod sequencer; +pub use sequencer::*; /// Base errors that are possible pub mod error; - -// TODO: make schema to rebuild the full sequence without requiring saving the actual -// packet data - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub enum AniMeBlock { - /// Full gif sequence. Immutable. - Animation(AniMeGif), - /// Basic image, can have properties changed - Image(Box), - /// A pause to be used between sequences - Pause(Duration), -} - -impl AniMeBlock { - pub fn asus_gif(file: &Path, brightness: f32) -> Result { - let frames = AniMeGif::create_diagonal_gif(file, brightness)?; - Ok(Self::Animation(frames)) - } - - pub fn png( - file: &Path, - scale: f32, - angle: f32, - translation: Vec2, - brightness: f32, - ) -> Result { - let image = AniMeImage::from_png(file, scale, angle, translation, brightness)?; - let data = ::from(&image); - Ok(Self::Image(Box::new(data))) - } - - pub fn image_gif( - file: &Path, - scale: f32, - angle: f32, - translation: Vec2, - brightness: f32, - ) -> Result { - let frames = AniMeGif::create_png_gif(file, scale, angle, translation, brightness)?; - Ok(Self::Animation(frames)) - } - - pub fn get_animation(&self) -> Option<&AniMeGif> { - match self { - AniMeBlock::Animation(anim) => Some(anim), - _ => None, - } - } - - pub fn get_image(&self) -> Option<&AniMeDataBuffer> { - match self { - AniMeBlock::Image(image) => Some(image), - _ => None, - } - } - - pub fn get_pause(&self) -> Option { - match self { - AniMeBlock::Pause(pause) => Some(*pause), - _ => None, - } - } -} diff --git a/rog-anime/src/sequencer.rs b/rog-anime/src/sequencer.rs new file mode 100644 index 00000000..0db9fcde --- /dev/null +++ b/rog-anime/src/sequencer.rs @@ -0,0 +1,108 @@ +use std::{path::Path, time::Duration}; + +use glam::Vec2; +use serde_derive::{Deserialize, Serialize}; + +use crate::{error::AnimeError, AniMeDataBuffer, AniMeGif, AniMeImage}; + +/// +#[derive(Debug, Deserialize, Serialize)] +pub enum Action { + /// Full gif sequence. Immutable. + Animation(AniMeGif), + /// Basic image, can have properties changed and image updated via those properties + Image(Box), + /// A pause to be used between sequences + Pause(Duration), + /// Placeholder + AudioEq, + /// Placeholder + SystemInfo, + /// Placeholder + TimeDate, + /// Placeholder + Matrix, +} + +/// An optimised precomputed set of actions +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct Sequences(Vec); + +impl Sequences { + pub fn new() -> Self { + Self(Vec::new()) + } + + pub fn add_asus_gif( + &mut self, + file: &Path, + duration: Option, + brightness: f32, + ) -> Result<(), AnimeError> { + let frames = AniMeGif::create_diagonal_gif(file, duration, brightness)?; + self.0.push(Action::Animation(frames)); + Ok(()) + } + + pub fn add_png( + &mut self, + file: &Path, + scale: f32, + angle: f32, + translation: Vec2, + brightness: f32, + ) -> Result<(), AnimeError> { + let image = AniMeImage::from_png(file, scale, angle, translation, brightness)?; + let data = ::from(&image); + self.0.push(Action::Image(Box::new(data))); + Ok(()) + } + + pub fn add_image_gif( + &mut self, + file: &Path, + scale: f32, + angle: f32, + translation: Vec2, + duration: Option, + brightness: f32, + ) -> Result<(), AnimeError> { + let frames = + AniMeGif::create_png_gif(file, scale, angle, translation, duration, brightness)?; + self.0.push(Action::Animation(frames)); + Ok(()) + } + + pub fn add_pause(&mut self, duration: Duration) -> Result<(), AnimeError> { + self.0.push(Action::Pause(duration)); + Ok(()) + } + + pub fn iter(&self) -> ActionIterator { + ActionIterator { + actions: &self, + next_idx: 0, + } + } +} + +pub struct ActionIterator<'a> { + actions: &'a Sequences, + next_idx: usize, +} + +impl<'a> Iterator for ActionIterator<'a> { + type Item = &'a Action; + + fn next(&mut self) -> Option<&'a Action> { + if self.next_idx == self.actions.0.len() { + self.next_idx = 0; + return None; + } + + let current = self.next_idx; + self.next_idx += 1; + + Some(&self.actions.0[current]) + } +}