From 1366422d96afe58229168bd88aa90622846ca1d2 Mon Sep 17 00:00:00 2001 From: "Jochen@Jinbe" Date: Fri, 22 Mar 2024 22:05:27 +0100 Subject: [PATCH] Play around and add rog-slash --- Cargo.lock | 14 +- Cargo.toml | 1 + Makefile | 9 +- asusctl/examples/slash-steady.rs | 38 ++ asusd/src/lib.rs | 2 +- .../dbus-xml/org-asuslinux-19b6-4-4-4.xml | 105 ++++++ .../dbus-xml/org-asuslinux-platform-4.xml | 284 ++++++++++++-- rog-aura/data/aura_support.ron | 8 + rog-aura/src/builtin_modes.rs | 2 +- rog-dbus/src/zbus_aura.rs | 2 +- rog-slash/Cargo.toml | 29 ++ rog-slash/src/lib.rs | 3 + rog-slash/src/usb.rs | 345 ++++++++++++++++++ squashfs-root/.DirIcon | 1 + 14 files changed, 794 insertions(+), 49 deletions(-) create mode 100644 asusctl/examples/slash-steady.rs create mode 100644 bindings/dbus-xml/org-asuslinux-19b6-4-4-4.xml create mode 100644 rog-slash/Cargo.toml create mode 100644 rog-slash/src/lib.rs create mode 100644 rog-slash/src/usb.rs create mode 100644 squashfs-root/.DirIcon 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 @@ +ToolBox_trayIcon_colour_32-01 \ No newline at end of file