diff --git a/Cargo.lock b/Cargo.lock
index ff4a4df8..bdebc464 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3907,7 +3907,7 @@ dependencies = [
"i-slint-compiler",
"spin_on",
"thiserror",
- "toml_edit 0.22.8",
+ "toml_edit 0.22.9",
]
[[package]]
@@ -3932,9 +3932,9 @@ dependencies = [
[[package]]
name = "smallvec"
-version = "1.13.1"
+version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "smithay-client-toolkit"
@@ -4112,7 +4112,7 @@ dependencies = [
[[package]]
name = "supergfxctl"
version = "5.2.2"
-source = "git+https://gitlab.com/asus-linux/supergfxctl.git#f3465681ac147821bbd2d50aff2bced2d92d529e"
+source = "git+https://gitlab.com/asus-linux/supergfxctl.git#68c12374d2cc20e5503b7694168afa2bf52af705"
dependencies = [
"log",
"logind-zbus",
@@ -4377,7 +4377,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.22.8",
+ "toml_edit 0.22.9",
]
[[package]]
@@ -4413,9 +4413,9 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.22.8"
+version = "0.22.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c12219811e0c1ba077867254e5ad62ee2c9c190b0d957110750ac0cda1ae96cd"
+checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
dependencies = [
"indexmap",
"serde",
diff --git a/Cargo.toml b/Cargo.toml
index c25d3efc..e72dafa6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,7 @@ tokio = { version = "^1.23.0", default-features = false, features = [
"sync",
"time",
"rt",
+ "rt-multi-thread"
] }
concat-idents = "^1.1"
dirs = "^4.0"
diff --git a/Makefile b/Makefile
index 8acce3b6..f5f7a967 100644
--- a/Makefile
+++ b/Makefile
@@ -124,10 +124,11 @@ bindings:
typeshare ./rog-platform/src/ --lang=typescript --output-file=bindings/ts/platform.ts
introspect:
- gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Platform -x > bindings/dbus-xml/org-asuslinux-platform-4.xml
- gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Aura -x > bindings/dbus-xml/org-asuslinux-aura-4.xml
- gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Anime -x > bindings/dbus-xml/org-asuslinux-anime-4.xml
- gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/FanCurves -x > bindings/dbus-xml/org-asuslinux-fan-curves-4.xml
+# gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Platform -x > bindings/dbus-xml/org-asuslinux-platform-4.xml
+# gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Aura -x > bindings/dbus-xml/org-asuslinux-aura-4.xml
+# gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Anime -x > bindings/dbus-xml/org-asuslinux-anime-4.xml
+ gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux -x > bindings/dbus-xml/org-asuslinux-platform-4.xml
+ gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/19b6_4_4 -x > bindings/dbus-xml/org-asuslinux-19b6-4-4-4.xml
xmlstarlet ed -L -O -d '//interface[@name="org.freedesktop.DBus.Introspectable"]' bindings/dbus-xml/org-asuslinux-*
xmlstarlet ed -L -O -d '//interface[@name="org.freedesktop.DBus.Properties"]' bindings/dbus-xml/org-asuslinux-*
xmlstarlet ed -L -O -d '//interface[@name="org.freedesktop.DBus.Peer"]' bindings/dbus-xml/org-asuslinux-*
diff --git a/asusctl/examples/slash-steady.rs b/asusctl/examples/slash-steady.rs
new file mode 100644
index 00000000..874689d8
--- /dev/null
+++ b/asusctl/examples/slash-steady.rs
@@ -0,0 +1,38 @@
+use std::thread::sleep;
+use std::time::Duration;
+
+use rog_anime::usb::get_anime_type;
+use rog_anime::{AnimeDiagonal, AnimeType};
+use rog_dbus::RogDbusClientBlocking;
+
+// In usable data:
+// Top row start at 1, ends at 32
+
+// 74w x 36h diagonal used by the windows app
+
+fn main() {
+ let (client, _) = RogDbusClientBlocking::new().unwrap();
+
+ for step in (2..50).rev() {
+ let mut matrix = AnimeDiagonal::new(AnimeType::GA401, None);
+ for c in (0..60).step_by(step) {
+ for i in matrix.get_mut().iter_mut() {
+ i[c] = 50;
+ }
+ }
+
+ for c in (0..35).step_by(step) {
+ for i in &mut matrix.get_mut()[c] {
+ *i = 50;
+ }
+ }
+
+ let anime_type = get_anime_type().unwrap();
+ client
+ .proxies()
+ .anime()
+ .write(matrix.into_data_buffer(anime_type).unwrap())
+ .unwrap();
+ sleep(Duration::from_millis(300));
+ }
+}
diff --git a/asusd/src/lib.rs b/asusd/src/lib.rs
index db784d39..aaeff5fc 100644
--- a/asusd/src/lib.rs
+++ b/asusd/src/lib.rs
@@ -50,7 +50,7 @@ pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
/// task_watch_item!(panel_od platform);
/// task_watch_item!(gpu_mux_mode platform);
/// }
-/// ```
+/// ```\
/// // TODO: this is kind of useless if it can't trigger some action
#[macro_export]
macro_rules! task_watch_item {
diff --git a/bindings/dbus-xml/org-asuslinux-19b6-4-4-4.xml b/bindings/dbus-xml/org-asuslinux-19b6-4-4-4.xml
new file mode 100644
index 00000000..a04d6fab
--- /dev/null
+++ b/bindings/dbus-xml/org-asuslinux-19b6-4-4-4.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bindings/dbus-xml/org-asuslinux-platform-4.xml b/bindings/dbus-xml/org-asuslinux-platform-4.xml
index a8708bd5..682f0441 100644
--- a/bindings/dbus-xml/org-asuslinux-platform-4.xml
+++ b/bindings/dbus-xml/org-asuslinux-platform-4.xml
@@ -2,7 +2,100 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -18,6 +111,11 @@
-->
+
+
@@ -42,10 +140,6 @@
internal config also.
-->
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rog-aura/data/aura_support.ron b/rog-aura/data/aura_support.ron
index 39f39241..a2775043 100644
--- a/rog-aura/data/aura_support.ron
+++ b/rog-aura/data/aura_support.ron
@@ -727,4 +727,12 @@
advanced_type: None,
power_zones: [Keyboard],
),
+ (
+ board_name: "GA403UI",
+ layout_name: "ga401q",
+ basic_modes: [Static, Breathe, Pulse],
+ basic_zones: [],
+ advanced_type: None,
+ power_zones: [Keyboard],
+ ),
])
diff --git a/rog-aura/src/builtin_modes.rs b/rog-aura/src/builtin_modes.rs
index d955c74c..f5c729a9 100644
--- a/rog-aura/src/builtin_modes.rs
+++ b/rog-aura/src/builtin_modes.rs
@@ -486,7 +486,7 @@ impl Default for AuraEffect {
Self {
mode: AuraModeNum::Static,
zone: AuraZone::None,
- colour1: Colour { r: 166, g: 0, b: 0 },
+ colour1: Colour { r: 166, g: 166, b: 166 },
colour2: Colour { r: 0, g: 0, b: 0 },
speed: Speed::Med,
direction: Direction::Right,
diff --git a/rog-dbus/src/zbus_aura.rs b/rog-dbus/src/zbus_aura.rs
index f1e5e221..040bb9b5 100644
--- a/rog-dbus/src/zbus_aura.rs
+++ b/rog-dbus/src/zbus_aura.rs
@@ -34,7 +34,7 @@ const BLOCKING_TIME: u64 = 33; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 F
#[proxy(
interface = "org.asuslinux.Aura",
default_service = "org.asuslinux.Daemon",
- default_path = "/org/asuslinux/Aura"
+ default_path = "/org/asuslinux/19b6_4_4"
)]
trait Aura {
/// AllModeData method
diff --git a/rog-slash/Cargo.toml b/rog-slash/Cargo.toml
new file mode 100644
index 00000000..4f5864a2
--- /dev/null
+++ b/rog-slash/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "rog_slash"
+license = "MPL-2.0"
+version.workspace = true
+readme = "README.md"
+authors = ["Luke "]
+repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
+homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
+documentation = "https://docs.rs/rog-anime"
+description = "ASUS Slash display"
+keywords = ["ROG", "ASUS", "AniMe", "Slash"]
+edition = "2024"
+exclude = ["data"]
+
+[dependencies]
+log.workspace = true
+serde.workspace = true
+serde_derive.workspace = true
+zbus.workspace = true
+concat-idents.workspace = true
+udev.workspace = true
+inotify.workspace = true
+typeshare.workspace = true
+
+rusb.workspace = true
+
+[dev-dependencies]
+cargo-husky.workspace = true
+rog_aura = { path = "../rog-aura" }
\ No newline at end of file
diff --git a/rog-slash/src/lib.rs b/rog-slash/src/lib.rs
new file mode 100644
index 00000000..ffb4a0c5
--- /dev/null
+++ b/rog-slash/src/lib.rs
@@ -0,0 +1,3 @@
+
+/// Provides const methods to create the USB HID control packets
+pub mod usb;
\ No newline at end of file
diff --git a/rog-slash/src/usb.rs b/rog-slash/src/usb.rs
new file mode 100644
index 00000000..d0dcc9ca
--- /dev/null
+++ b/rog-slash/src/usb.rs
@@ -0,0 +1,345 @@
+//! Utils for writing to the `AniMe` USB device
+//!
+//! Use of the device requires a few steps:
+//! 1. Initialise the device by writing the two packets from
+//! `get_init_packets()` 2. Write data from `AnimePacketType`
+//! 3. Write the packet from `get_flush_packet()`, which tells the device to
+//! display the data from step 2
+//!
+//! Step 1 need to applied only on fresh system boot.
+
+use std::str::FromStr;
+
+use dmi_id::DMIID;
+use serde_derive::{Deserialize, Serialize};
+use typeshare::typeshare;
+#[cfg(feature = "dbus")]
+use zbus::zvariant::{OwnedValue, Type, Value};
+
+use crate::error::AnimeError;
+use crate::AnimeType;
+
+const PACKET_SIZE: usize = 640;
+const DEV_PAGE: u8 = 0x5e;
+pub const VENDOR_ID: u16 = 0x0b05;
+pub const PROD_ID: u16 = 0x193b;
+
+#[cfg_attr(
+feature = "dbus",
+derive(Type, Value, OwnedValue),
+zvariant(signature = "u")
+)]
+#[typeshare]
+#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
+/// Base LED brightness of the display
+pub enum Brightness {
+ Off = 0,
+ Low = 1,
+ #[default]
+ Med = 2,
+ High = 3,
+}
+
+impl FromStr for Brightness {
+ type Err = AnimeError;
+
+ fn from_str(s: &str) -> Result {
+ Ok(match s {
+ "Off" | "off" => Brightness::Off,
+ "Low" | "low" => Brightness::Low,
+ "Med" | "med" => Brightness::Med,
+ "High" | "high" => Brightness::High,
+ _ => Brightness::Med,
+ })
+ }
+}
+
+impl From for Brightness {
+ fn from(v: u8) -> Brightness {
+ match v {
+ 0 => Brightness::Off,
+ 1 => Brightness::Low,
+ 3 => Brightness::High,
+ _ => Brightness::Med,
+ }
+ }
+}
+
+impl From for Brightness {
+ fn from(v: i32) -> Brightness {
+ (v as u8).into()
+ }
+}
+
+impl From for i32 {
+ fn from(v: Brightness) -> i32 {
+ v as i32
+ }
+}
+
+#[cfg_attr(
+feature = "dbus",
+derive(Type, Value, OwnedValue),
+zvariant(signature = "s")
+)]
+#[typeshare]
+#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
+pub enum AnimBooting {
+ #[default]
+ GlitchConstruction = 0,
+ StaticEmergence = 1,
+}
+
+impl FromStr for AnimBooting {
+ type Err = AnimeError;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ "GlitchConstruction" => Ok(Self::GlitchConstruction),
+ "StaticEmergence" => Ok(Self::StaticEmergence),
+ _ => Err(AnimeError::ParseError(s.to_owned())),
+ }
+ }
+}
+
+impl From for AnimBooting {
+ fn from(value: i32) -> Self {
+ match value {
+ 0 => Self::GlitchConstruction,
+ 1 => Self::StaticEmergence,
+ _ => Self::default(),
+ }
+ }
+}
+
+impl From for i32 {
+ fn from(value: AnimBooting) -> Self {
+ value as i32
+ }
+}
+
+#[cfg_attr(
+feature = "dbus",
+derive(Type, Value, OwnedValue),
+zvariant(signature = "s")
+)]
+#[typeshare]
+#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
+pub enum AnimAwake {
+ #[default]
+ BinaryBannerScroll = 0,
+ RogLogoGlitch = 1,
+}
+
+impl FromStr for AnimAwake {
+ type Err = AnimeError;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ "BinaryBannerScroll" => Ok(Self::BinaryBannerScroll),
+ "RogLogoGlitch" => Ok(Self::RogLogoGlitch),
+ _ => Err(AnimeError::ParseError(s.to_owned())),
+ }
+ }
+}
+
+impl From for AnimAwake {
+ fn from(value: i32) -> Self {
+ match value {
+ 0 => Self::BinaryBannerScroll,
+ 1 => Self::RogLogoGlitch,
+ _ => Self::default(),
+ }
+ }
+}
+
+impl From for i32 {
+ fn from(value: AnimAwake) -> Self {
+ value as i32
+ }
+}
+
+#[cfg_attr(
+feature = "dbus",
+derive(Type, Value, OwnedValue),
+zvariant(signature = "s")
+)]
+#[typeshare]
+#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
+pub enum AnimSleeping {
+ #[default]
+ BannerSwipe = 0,
+ Starfield = 1,
+}
+
+impl FromStr for AnimSleeping {
+ type Err = AnimeError;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ "BannerSwipe" => Ok(Self::BannerSwipe),
+ "Starfield" => Ok(Self::Starfield),
+ _ => Err(AnimeError::ParseError(s.to_owned())),
+ }
+ }
+}
+
+impl From for AnimSleeping {
+ fn from(value: i32) -> Self {
+ match value {
+ 0 => Self::BannerSwipe,
+ 1 => Self::Starfield,
+ _ => Self::default(),
+ }
+ }
+}
+
+impl From for i32 {
+ fn from(value: AnimSleeping) -> Self {
+ value as i32
+ }
+}
+
+#[cfg_attr(
+feature = "dbus",
+derive(Type, Value, OwnedValue),
+zvariant(signature = "s")
+)]
+#[typeshare]
+#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
+pub enum AnimShutdown {
+ #[default]
+ GlitchOut = 0,
+ SeeYa = 1,
+}
+
+impl FromStr for AnimShutdown {
+ type Err = AnimeError;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ "GlitchOut" => Ok(Self::GlitchOut),
+ "SeeYa" => Ok(Self::SeeYa),
+ _ => Err(AnimeError::ParseError(s.to_owned())),
+ }
+ }
+}
+
+impl From for AnimShutdown {
+ fn from(value: i32) -> Self {
+ match value {
+ 0 => Self::GlitchOut,
+ 1 => Self::SeeYa,
+ _ => Self::default(),
+ }
+ }
+}
+
+impl From for i32 {
+ fn from(value: AnimShutdown) -> Self {
+ value as i32
+ }
+}
+
+/// `get_anime_type` is very broad, matching on part of the laptop board name
+/// only. For this reason `find_node()` must be used also to verify if the USB
+/// device is available.
+///
+/// The currently known USB device is `19b6`.
+#[inline]
+pub fn get_anime_type() -> Result {
+ let dmi = DMIID::new().map_err(|_| AnimeError::NoDevice)?; // TODO: better error
+ let board_name = dmi.board_name;
+
+ if board_name.contains("GA401I") || board_name.contains("GA401Q") {
+ return Ok(AnimeType::GA401);
+ } else if board_name.contains("GA402R") {
+ return Ok(AnimeType::GA402);
+ } else if board_name.contains("GU604V") {
+ return Ok(AnimeType::GU604);
+ }
+ log::warn!("AniMe Matrix device found but not yet supported, will default to a GA402 layout");
+ Ok(AnimeType::Unknown)
+}
+
+/// Get the two device initialization packets. These are required for device
+/// start after the laptop boots.
+#[inline]
+pub const fn pkts_for_init() -> [[u8; PACKET_SIZE]; 2] {
+ let mut packets = [[0; PACKET_SIZE]; 2];
+ packets[0][0] = DEV_PAGE; // This is the USB page we're using throughout
+ let mut count = 0;
+ // TODO: memcpy or slice copy
+ let bytes = "ASUS Tech.Inc.".as_bytes();
+ while count < bytes.len() {
+ packets[0][count + 1] = bytes[count];
+ count += 1;
+ }
+ //
+ packets[1][0] = DEV_PAGE;
+ packets[1][1] = 0xc2;
+ packets
+}
+
+/// Should be written to the device after writing the two main data packets that
+/// make up the display data packet
+#[inline]
+pub const fn pkt_flush() -> [u8; PACKET_SIZE] {
+ let mut pkt = [0; PACKET_SIZE];
+ pkt[0] = DEV_PAGE;
+ pkt[1] = 0xc0;
+ pkt[2] = 0x03;
+ pkt
+}
+
+/// Packet for setting the brightness (0-3). Requires
+/// `pkt_for_apply()` to be written after.
+#[inline]
+pub const fn pkt_set_brightness(brightness: Brightness) -> [u8; PACKET_SIZE] {
+ let mut pkt = [0; PACKET_SIZE];
+ pkt[0] = DEV_PAGE;
+ pkt[1] = 0xc0;
+ pkt[2] = 0x04;
+ pkt[3] = brightness as u8;
+ pkt
+}
+
+/// Enable the display?
+#[inline]
+pub const fn pkt_set_enable_display(status: bool) -> [u8; PACKET_SIZE] {
+ let mut pkt = [0; PACKET_SIZE];
+ pkt[0] = DEV_PAGE;
+ pkt[1] = 0xc3;
+ pkt[2] = 0x01;
+ pkt[3] = if status { 0x00 } else { 0x80 };
+ pkt
+}
+
+/// Enable builtin animations?
+#[inline]
+pub const fn pkt_set_enable_powersave_anim(status: bool) -> [u8; PACKET_SIZE] {
+ let mut pkt = [0; PACKET_SIZE];
+ pkt[0] = DEV_PAGE;
+ pkt[1] = 0xc4;
+ pkt[2] = 0x01;
+ pkt[3] = if status { 0x00 } else { 0x80 };
+ pkt
+}
+
+/// Set which animations are shown for each stage
+#[inline]
+pub const fn pkt_set_builtin_animations(
+ boot: AnimBooting,
+ awake: AnimAwake,
+ sleep: AnimSleeping,
+ shutdown: AnimShutdown,
+) -> [u8; PACKET_SIZE] {
+ let mut pkt = [0; PACKET_SIZE];
+ pkt[0] = DEV_PAGE;
+ pkt[1] = 0xc5;
+ pkt[2] = (awake as u8)
+ | ((sleep as u8) << 0x01)
+ | ((shutdown as u8) << 0x02)
+ | ((boot as u8) << 0x03);
+ pkt
+}
diff --git a/squashfs-root/.DirIcon b/squashfs-root/.DirIcon
new file mode 100644
index 00000000..94e6adba
--- /dev/null
+++ b/squashfs-root/.DirIcon
@@ -0,0 +1 @@
+
\ No newline at end of file