mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Merge pull request #23 from jschoubben/main
Add support for 2024 G14 Slash lighting (GA403UI)
This commit is contained in:
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -136,6 +136,7 @@ dependencies = [
|
|||||||
"rog_dbus",
|
"rog_dbus",
|
||||||
"rog_platform",
|
"rog_platform",
|
||||||
"rog_profiles",
|
"rog_profiles",
|
||||||
|
"rog_slash",
|
||||||
"tinybmp",
|
"tinybmp",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml 0.5.11",
|
"toml 0.5.11",
|
||||||
@@ -160,6 +161,7 @@ dependencies = [
|
|||||||
"rog_aura",
|
"rog_aura",
|
||||||
"rog_platform",
|
"rog_platform",
|
||||||
"rog_profiles",
|
"rog_profiles",
|
||||||
|
"rog_slash",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"systemd-zbus",
|
"systemd-zbus",
|
||||||
@@ -3560,6 +3562,23 @@ dependencies = [
|
|||||||
"uhid-virt",
|
"uhid-virt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rog_slash"
|
||||||
|
version = "6.0.0-alpha1"
|
||||||
|
dependencies = [
|
||||||
|
"cargo-husky",
|
||||||
|
"dmi_id",
|
||||||
|
"gif 0.12.0",
|
||||||
|
"glam",
|
||||||
|
"log",
|
||||||
|
"pix",
|
||||||
|
"png_pong",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"typeshare",
|
||||||
|
"zbus 4.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ron"
|
name = "ron"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ members = [
|
|||||||
"rog-aura",
|
"rog-aura",
|
||||||
"rog-profiles",
|
"rog-profiles",
|
||||||
"rog-control-center",
|
"rog-control-center",
|
||||||
|
"rog-slash",
|
||||||
"simulators",
|
"simulators",
|
||||||
]
|
]
|
||||||
default-members = [
|
default-members = [
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ version.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rog_anime = { path = "../rog-anime" }
|
rog_anime = { path = "../rog-anime" }
|
||||||
|
rog_slash = { path = "../rog-slash" }
|
||||||
rog_aura = { path = "../rog-aura" }
|
rog_aura = { path = "../rog-aura" }
|
||||||
rog_dbus = { path = "../rog-dbus" }
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
rog_profiles = { path = "../rog-profiles" }
|
rog_profiles = { path = "../rog-profiles" }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use rog_platform::platform::ThrottlePolicy;
|
|||||||
use crate::anime_cli::AnimeCommand;
|
use crate::anime_cli::AnimeCommand;
|
||||||
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
|
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
|
||||||
use crate::fan_curve_cli::FanCurveCommand;
|
use crate::fan_curve_cli::FanCurveCommand;
|
||||||
|
use crate::slash_cli::SlashCommand;
|
||||||
|
|
||||||
#[derive(Default, Options)]
|
#[derive(Default, Options)]
|
||||||
pub struct CliStart {
|
pub struct CliStart {
|
||||||
@@ -41,6 +42,8 @@ pub enum CliCommand {
|
|||||||
Graphics(GraphicsCommand),
|
Graphics(GraphicsCommand),
|
||||||
#[options(name = "anime", help = "Manage AniMe Matrix")]
|
#[options(name = "anime", help = "Manage AniMe Matrix")]
|
||||||
Anime(AnimeCommand),
|
Anime(AnimeCommand),
|
||||||
|
#[options(name = "slash", help = "Manage Slash Ledbar")]
|
||||||
|
Slash(SlashCommand),
|
||||||
#[options(help = "Change bios settings")]
|
#[options(help = "Change bios settings")]
|
||||||
Bios(BiosCommand),
|
Bios(BiosCommand),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,18 @@ use rog_dbus::zbus_fan_curves::FanCurvesProxyBlocking;
|
|||||||
use rog_dbus::zbus_platform::PlatformProxyBlocking;
|
use rog_dbus::zbus_platform::PlatformProxyBlocking;
|
||||||
use rog_platform::platform::{GpuMode, Properties, ThrottlePolicy};
|
use rog_platform::platform::{GpuMode, Properties, ThrottlePolicy};
|
||||||
use rog_profiles::error::ProfileError;
|
use rog_profiles::error::ProfileError;
|
||||||
|
use rog_slash::SlashMode;
|
||||||
use zbus::blocking::Connection;
|
use zbus::blocking::Connection;
|
||||||
|
|
||||||
use crate::aura_cli::{AuraPowerStates, LedBrightness};
|
use crate::aura_cli::{AuraPowerStates, LedBrightness};
|
||||||
use crate::cli_opts::*;
|
use crate::cli_opts::*;
|
||||||
|
use crate::slash_cli::{SlashCommand};
|
||||||
|
|
||||||
mod anime_cli;
|
mod anime_cli;
|
||||||
mod aura_cli;
|
mod aura_cli;
|
||||||
mod cli_opts;
|
mod cli_opts;
|
||||||
mod fan_curve_cli;
|
mod fan_curve_cli;
|
||||||
|
mod slash_cli;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = args().skip(1).collect();
|
let args: Vec<String> = args().skip(1).collect();
|
||||||
@@ -168,6 +171,7 @@ fn do_parsed(
|
|||||||
}
|
}
|
||||||
Some(CliCommand::Graphics(_)) => do_gfx(),
|
Some(CliCommand::Graphics(_)) => do_gfx(),
|
||||||
Some(CliCommand::Anime(cmd)) => handle_anime(&conn, cmd)?,
|
Some(CliCommand::Anime(cmd)) => handle_anime(&conn, cmd)?,
|
||||||
|
Some(CliCommand::Slash(cmd)) => handle_slash(&conn, cmd)?,
|
||||||
Some(CliCommand::Bios(cmd)) => {
|
Some(CliCommand::Bios(cmd)) => {
|
||||||
handle_platform_properties(&conn, supported_properties, cmd)?
|
handle_platform_properties(&conn, supported_properties, cmd)?
|
||||||
}
|
}
|
||||||
@@ -482,6 +486,49 @@ fn verify_brightness(brightness: f32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_slash(
|
||||||
|
dbus: &RogDbusClientBlocking<'_>,
|
||||||
|
cmd: &SlashCommand,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if (
|
||||||
|
cmd.brightness.is_none() &&
|
||||||
|
cmd.interval.is_none() &&
|
||||||
|
cmd.slash_mode.is_none() &&
|
||||||
|
!cmd.list &&
|
||||||
|
!cmd.enable &&
|
||||||
|
!cmd.disable
|
||||||
|
) || cmd.help
|
||||||
|
{
|
||||||
|
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||||
|
if let Some(lst) = cmd.self_command_list() {
|
||||||
|
println!("\n{}", lst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cmd.enable {
|
||||||
|
dbus.proxies().slash().set_enabled(true)?;
|
||||||
|
}
|
||||||
|
if cmd.disable {
|
||||||
|
dbus.proxies().slash().set_enabled(false)?;
|
||||||
|
}
|
||||||
|
if let Some(brightness) = cmd.brightness {
|
||||||
|
dbus.proxies().slash().set_brightness(brightness)?;
|
||||||
|
}
|
||||||
|
if let Some(interval) = cmd.interval {
|
||||||
|
dbus.proxies().slash().set_interval(interval)?;
|
||||||
|
}
|
||||||
|
if let Some(slash_mode) = cmd.slash_mode {
|
||||||
|
dbus.proxies().slash().set_slash_mode(slash_mode)?;
|
||||||
|
}
|
||||||
|
if cmd.list {
|
||||||
|
let res = SlashMode::list();
|
||||||
|
for p in &res {
|
||||||
|
println!("{:?}", p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_led_mode(
|
fn handle_led_mode(
|
||||||
aura: &[AuraProxyBlocking],
|
aura: &[AuraProxyBlocking],
|
||||||
mode: &LedModeCommand,
|
mode: &LedModeCommand,
|
||||||
|
|||||||
20
asusctl/src/slash_cli.rs
Normal file
20
asusctl/src/slash_cli.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
use gumdrop::Options;
|
||||||
|
use rog_slash::SlashMode;
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
pub struct SlashCommand {
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
pub help: bool,
|
||||||
|
#[options(help = "Enable the Slash Ledbar")]
|
||||||
|
pub enable: bool,
|
||||||
|
#[options(help = "Ddisable the Slash Ledbar")]
|
||||||
|
pub disable: bool,
|
||||||
|
#[options(meta = "", help = "Set brightness value <0-255>")]
|
||||||
|
pub brightness: Option<u8>,
|
||||||
|
#[options(meta = "", help = "Set interval value <0-255>")]
|
||||||
|
pub interval: Option<u8>,
|
||||||
|
#[options(help = "Set SlashMode (so 'list' for all options)")]
|
||||||
|
pub slash_mode: Option<SlashMode>,
|
||||||
|
#[options(help = "list available animations")]
|
||||||
|
pub list: bool,
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ path = "src/daemon.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
config-traits = { path = "../config-traits" }
|
config-traits = { path = "../config-traits" }
|
||||||
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
||||||
|
rog_slash = { path = "../rog-slash", features = ["dbus"] }
|
||||||
rog_aura = { path = "../rog-aura", features = ["dbus"] }
|
rog_aura = { path = "../rog-aura", features = ["dbus"] }
|
||||||
rog_platform = { path = "../rog-platform" }
|
rog_platform = { path = "../rog-platform" }
|
||||||
rog_profiles = { path = "../rog-profiles" }
|
rog_profiles = { path = "../rog-profiles" }
|
||||||
|
|||||||
@@ -90,13 +90,13 @@ impl StdConfig for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_dir() -> std::path::PathBuf {
|
|
||||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_name(&self) -> String {
|
fn file_name(&self) -> String {
|
||||||
CONFIG_FILE.to_owned()
|
CONFIG_FILE.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn config_dir() -> std::path::PathBuf {
|
||||||
|
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdConfigLoad3<Config472, Config506, Config507> for Config {}
|
impl StdConfigLoad3<Config472, Config506, Config507> for Config {}
|
||||||
|
|||||||
@@ -150,13 +150,13 @@ impl StdConfig for AnimeConfig {
|
|||||||
Self::create_default()
|
Self::create_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_dir() -> std::path::PathBuf {
|
|
||||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_name(&self) -> String {
|
fn file_name(&self) -> String {
|
||||||
CONFIG_FILE.to_owned()
|
CONFIG_FILE.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn config_dir() -> std::path::PathBuf {
|
||||||
|
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdConfigLoad2<AnimeConfigV460, AnimeConfigV472> for AnimeConfig {}
|
impl StdConfigLoad2<AnimeConfigV460, AnimeConfigV472> for AnimeConfig {}
|
||||||
|
|||||||
@@ -27,16 +27,16 @@ impl StdConfig for AuraConfig {
|
|||||||
panic!("This should not be used");
|
panic!("This should not be used");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_dir() -> std::path::PathBuf {
|
|
||||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_name(&self) -> String {
|
fn file_name(&self) -> String {
|
||||||
if self.config_name.is_empty() {
|
if self.config_name.is_empty() {
|
||||||
panic!("Config file name should not be empty");
|
panic!("Config file name should not be empty");
|
||||||
}
|
}
|
||||||
self.config_name.to_owned()
|
self.config_name.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn config_dir() -> std::path::PathBuf {
|
||||||
|
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdConfigLoad for AuraConfig {}
|
impl StdConfigLoad for AuraConfig {}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use crate::ctrl_aura::trait_impls::{CtrlAuraZbus, AURA_ZBUS_NAME, AURA_ZBUS_PATH
|
|||||||
use crate::ctrl_fancurves::{CtrlFanCurveZbus, FAN_CURVE_ZBUS_NAME, FAN_CURVE_ZBUS_PATH};
|
use crate::ctrl_fancurves::{CtrlFanCurveZbus, FAN_CURVE_ZBUS_NAME, FAN_CURVE_ZBUS_PATH};
|
||||||
use crate::error::RogError;
|
use crate::error::RogError;
|
||||||
use crate::{task_watch_item, task_watch_item_notify, CtrlTask, ReloadAndNotify};
|
use crate::{task_watch_item, task_watch_item_notify, CtrlTask, ReloadAndNotify};
|
||||||
|
use crate::ctrl_slash::trait_impls::{CtrlSlashZbus, SLASH_ZBUS_NAME, SLASH_ZBUS_PATH};
|
||||||
|
|
||||||
const PLATFORM_ZBUS_NAME: &str = "Platform";
|
const PLATFORM_ZBUS_NAME: &str = "Platform";
|
||||||
const PLATFORM_ZBUS_PATH: &str = "/org/asuslinux";
|
const PLATFORM_ZBUS_PATH: &str = "/org/asuslinux";
|
||||||
@@ -351,6 +352,13 @@ impl CtrlPlatform {
|
|||||||
{
|
{
|
||||||
interfaces.push(PLATFORM_ZBUS_NAME.to_owned());
|
interfaces.push(PLATFORM_ZBUS_NAME.to_owned());
|
||||||
}
|
}
|
||||||
|
if server
|
||||||
|
.interface::<_, CtrlSlashZbus>(SLASH_ZBUS_PATH)
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
interfaces.push(SLASH_ZBUS_NAME.to_owned());
|
||||||
|
}
|
||||||
interfaces
|
interfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
asusd/src/ctrl_slash/config.rs
Normal file
51
asusd/src/ctrl_slash/config.rs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use config_traits::{StdConfig, StdConfigLoad};
|
||||||
|
use rog_slash::{DeviceState, SlashMode};
|
||||||
|
|
||||||
|
const CONFIG_FILE: &str = "slash.ron";
|
||||||
|
|
||||||
|
/// Config for base system actions for the anime display
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct SlashConfig {
|
||||||
|
pub slash_enabled: bool,
|
||||||
|
pub slash_brightness: u8,
|
||||||
|
pub slash_interval: u8,
|
||||||
|
pub slash_mode: SlashMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SlashConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
SlashConfig {
|
||||||
|
slash_enabled: true,
|
||||||
|
slash_brightness: 255,
|
||||||
|
slash_interval: 0,
|
||||||
|
slash_mode: SlashMode::Bounce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl StdConfig for SlashConfig {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_name(&self) -> String {
|
||||||
|
CONFIG_FILE.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config_dir() -> std::path::PathBuf {
|
||||||
|
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StdConfigLoad for SlashConfig {}
|
||||||
|
|
||||||
|
impl From<&SlashConfig> for DeviceState {
|
||||||
|
fn from(config: &SlashConfig) -> Self {
|
||||||
|
DeviceState {
|
||||||
|
slash_enabled: config.slash_enabled,
|
||||||
|
slash_brightness: config.slash_brightness,
|
||||||
|
slash_interval: config.slash_interval,
|
||||||
|
slash_mode: config.slash_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
102
asusd/src/ctrl_slash/mod.rs
Normal file
102
asusd/src/ctrl_slash/mod.rs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
pub mod config;
|
||||||
|
pub mod trait_impls;
|
||||||
|
|
||||||
|
use rog_platform::hid_raw::HidRaw;
|
||||||
|
use rog_platform::usb_raw::USBRaw;
|
||||||
|
use rog_slash::{SlashMode, SlashType};
|
||||||
|
use rog_slash::error::SlashError;
|
||||||
|
use rog_slash::usb::{get_slash_type, pkt_set_mode, pkt_set_options, pkts_for_init};
|
||||||
|
use crate::ctrl_slash::config::SlashConfig;
|
||||||
|
use crate::error::RogError;
|
||||||
|
|
||||||
|
enum Node {
|
||||||
|
Usb(USBRaw),
|
||||||
|
Hid(HidRaw),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
|
||||||
|
// TODO: map and pass on errors
|
||||||
|
match self {
|
||||||
|
Node::Usb(u) => {
|
||||||
|
u.write_bytes(message).ok();
|
||||||
|
}
|
||||||
|
Node::Hid(h) => {
|
||||||
|
h.write_bytes(message).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CtrlSlash {
|
||||||
|
// node: HidRaw,
|
||||||
|
node: Node,
|
||||||
|
config: SlashConfig,
|
||||||
|
// slash_type: SlashType,
|
||||||
|
// // set to force thread to exit
|
||||||
|
// thread_exit: Arc<AtomicBool>,
|
||||||
|
// // Set to false when the thread exits
|
||||||
|
// thread_running: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlSlash {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(config: SlashConfig) -> Result<CtrlSlash, RogError> {
|
||||||
|
let usb = USBRaw::new(rog_slash::usb::PROD_ID).ok();
|
||||||
|
let hid = HidRaw::new(rog_slash::usb::PROD_ID_STR).ok();
|
||||||
|
let node = if usb.is_some() {
|
||||||
|
unsafe { Node::Usb(usb.unwrap_unchecked()) }
|
||||||
|
} else if hid.is_some() {
|
||||||
|
unsafe { Node::Hid(hid.unwrap_unchecked()) }
|
||||||
|
} else {
|
||||||
|
return Err(RogError::NotSupported);
|
||||||
|
};
|
||||||
|
|
||||||
|
let slash_type = get_slash_type()?;
|
||||||
|
if slash_type == SlashType::Unknown {
|
||||||
|
return Err(RogError::Slash(SlashError::NoDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctrl = CtrlSlash {
|
||||||
|
node,
|
||||||
|
config,
|
||||||
|
// slash_type,
|
||||||
|
// thread_exit: Arc::new(AtomicBool::new(false)),
|
||||||
|
// thread_running: Arc::new(AtomicBool::new(false)),
|
||||||
|
};
|
||||||
|
ctrl.do_initialization()?;
|
||||||
|
|
||||||
|
Ok(ctrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_initialization(&self) -> Result<(), RogError> {
|
||||||
|
|
||||||
|
let init_packets = pkts_for_init();
|
||||||
|
self.node.write_bytes(&init_packets[0])?;
|
||||||
|
self.node.write_bytes(&init_packets[1])?;
|
||||||
|
|
||||||
|
// Apply config upon initialization
|
||||||
|
let option_packets = pkt_set_options(self.config.slash_enabled, self.config.slash_brightness, self.config.slash_interval);
|
||||||
|
self.node.write_bytes(&option_packets)?;
|
||||||
|
|
||||||
|
let mode_packets = pkt_set_mode(self.config.slash_mode);
|
||||||
|
self.node.write_bytes(&mode_packets[0])?;
|
||||||
|
self.node.write_bytes(&mode_packets[1])?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_options(&self, enabled: bool, brightness: u8, interval: u8) -> Result<(), RogError> {
|
||||||
|
let command_packets = pkt_set_options(enabled, brightness, interval);
|
||||||
|
self.node.write_bytes(&command_packets)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_slash_mode(&self, slash_mode: SlashMode) -> Result<(), RogError> {
|
||||||
|
let command_packets = pkt_set_mode(slash_mode);
|
||||||
|
self.node.write_bytes(&command_packets[0])?;
|
||||||
|
self.node.write_bytes(&command_packets[1])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
145
asusd/src/ctrl_slash/trait_impls.rs
Normal file
145
asusd/src/ctrl_slash/trait_impls.rs
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use log::warn;
|
||||||
|
use zbus::{Connection, interface, SignalContext};
|
||||||
|
use zbus::export::futures_util::lock::Mutex;
|
||||||
|
use config_traits::StdConfig;
|
||||||
|
use rog_slash::{DeviceState, SlashMode};
|
||||||
|
use rog_slash::usb::{pkt_set_mode, pkt_set_options};
|
||||||
|
use crate::ctrl_slash::CtrlSlash;
|
||||||
|
use crate::error::RogError;
|
||||||
|
|
||||||
|
|
||||||
|
pub const SLASH_ZBUS_NAME: &str = "Slash";
|
||||||
|
pub const SLASH_ZBUS_PATH: &str = "/org/asuslinux";
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CtrlSlashZbus(pub Arc<Mutex<CtrlSlash>>);
|
||||||
|
|
||||||
|
/// The struct with the main dbus methods requires this trait
|
||||||
|
impl crate::ZbusRun for CtrlSlashZbus {
|
||||||
|
async fn add_to_server(self, server: &mut Connection) {
|
||||||
|
Self::add_to_server_helper(self, SLASH_ZBUS_PATH, server).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interface(name = "org.asuslinux.Slash")]
|
||||||
|
impl CtrlSlashZbus {
|
||||||
|
|
||||||
|
/// Get enabled or not
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn enabled(&self) -> bool {
|
||||||
|
let lock = self.0.lock().await;
|
||||||
|
lock.config.slash_enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set enabled true or false
|
||||||
|
async fn set_enabled(&self, enabled: bool) {
|
||||||
|
let mut lock = self.0.lock().await;
|
||||||
|
let brightness = if enabled && lock.config.slash_brightness == 0 { 0x88 } else { lock.config.slash_brightness };
|
||||||
|
lock.node
|
||||||
|
.write_bytes(&pkt_set_options(enabled, brightness, lock.config.slash_interval))
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("ctrl_slash::set_options {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
lock.config.slash_enabled = enabled;
|
||||||
|
lock.config.slash_brightness = brightness;
|
||||||
|
lock.config.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get brightness level
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn brightness(&self) -> u8 {
|
||||||
|
let lock = self.0.lock().await;
|
||||||
|
lock.config.slash_brightness
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set brightness level
|
||||||
|
async fn set_brightness(&self, brightness: u8) {
|
||||||
|
let mut lock = self.0.lock().await;
|
||||||
|
let enabled = brightness > 0;
|
||||||
|
lock.node
|
||||||
|
.write_bytes(&pkt_set_options(enabled, brightness, lock.config.slash_interval))
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("ctrl_slash::set_options {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
lock.config.slash_enabled = enabled;
|
||||||
|
lock.config.slash_brightness = brightness;
|
||||||
|
lock.config.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn interval(&self) -> u8 {
|
||||||
|
let lock = self.0.lock().await;
|
||||||
|
lock.config.slash_interval
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interval between slash animations (0-255)
|
||||||
|
async fn set_interval(&self, interval: u8) {
|
||||||
|
let mut lock = self.0.lock().await;
|
||||||
|
lock.node
|
||||||
|
.write_bytes(&pkt_set_options(lock.config.slash_enabled, lock.config.slash_brightness, interval))
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("ctrl_slash::set_options {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
lock.config.slash_interval = interval;
|
||||||
|
lock.config.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn slash_mode(&self) -> u8 {
|
||||||
|
let lock = self.0.lock().await;
|
||||||
|
lock.config.slash_interval
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interval between slash animations (0-255)
|
||||||
|
async fn set_slash_mode(&self, slash_mode: SlashMode) {
|
||||||
|
let mut lock = self.0.lock().await;
|
||||||
|
|
||||||
|
let command_packets = pkt_set_mode(slash_mode);
|
||||||
|
|
||||||
|
lock.node
|
||||||
|
.write_bytes(&command_packets[0])
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("ctrl_slash::set_options {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
lock.node
|
||||||
|
.write_bytes(&command_packets[1])
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("ctrl_slash::set_options {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
lock.config.slash_mode = slash_mode;
|
||||||
|
lock.config.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the device state as stored by asusd
|
||||||
|
// #[zbus(property)]
|
||||||
|
async fn device_state(&self) -> DeviceState {
|
||||||
|
let lock = self.0.lock().await;
|
||||||
|
DeviceState::from(&lock.config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::CtrlTask for CtrlSlashZbus {
|
||||||
|
fn zbus_path() -> &'static str {
|
||||||
|
SLASH_ZBUS_PATH
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlSlashZbus {
|
||||||
|
async fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,9 +12,12 @@ use asusd::ctrl_aura::manager::AuraManager;
|
|||||||
use asusd::ctrl_fancurves::CtrlFanCurveZbus;
|
use asusd::ctrl_fancurves::CtrlFanCurveZbus;
|
||||||
use asusd::ctrl_platform::CtrlPlatform;
|
use asusd::ctrl_platform::CtrlPlatform;
|
||||||
use asusd::{print_board_info, start_tasks, CtrlTask, DBUS_NAME};
|
use asusd::{print_board_info, start_tasks, CtrlTask, DBUS_NAME};
|
||||||
use config_traits::{StdConfig, StdConfigLoad2, StdConfigLoad3};
|
use config_traits::{StdConfig, StdConfigLoad, StdConfigLoad2, StdConfigLoad3};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use zbus::fdo::ObjectManager;
|
use zbus::fdo::ObjectManager;
|
||||||
|
use asusd::ctrl_slash::config::SlashConfig;
|
||||||
|
use asusd::ctrl_slash::CtrlSlash;
|
||||||
|
use asusd::ctrl_slash::trait_impls::CtrlSlashZbus;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -42,6 +45,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
info!(" daemon v{}", asusd::VERSION);
|
info!(" daemon v{}", asusd::VERSION);
|
||||||
info!(" rog-anime v{}", rog_anime::VERSION);
|
info!(" rog-anime v{}", rog_anime::VERSION);
|
||||||
|
info!(" rog-slash v{}", rog_slash::VERSION);
|
||||||
info!(" rog-aura v{}", rog_aura::VERSION);
|
info!(" rog-aura v{}", rog_aura::VERSION);
|
||||||
info!(" rog-profiles v{}", rog_profiles::VERSION);
|
info!(" rog-profiles v{}", rog_profiles::VERSION);
|
||||||
info!("rog-platform v{}", rog_platform::VERSION);
|
info!("rog-platform v{}", rog_platform::VERSION);
|
||||||
@@ -105,6 +109,20 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match CtrlSlash::new(SlashConfig::new().load()) {
|
||||||
|
Ok(ctrl) => {
|
||||||
|
let zbus = CtrlSlashZbus(Arc::new(Mutex::new(ctrl)));
|
||||||
|
// Currently, the Slash has no need for a loop watching power events, however,
|
||||||
|
// it could be cool to have the slash do some power-on/off animation
|
||||||
|
// (It has a built-in power on animation which plays when u plug in the power supply)
|
||||||
|
let sig_ctx = CtrlSlashZbus::signal_context(&connection)?;
|
||||||
|
start_tasks(zbus, &mut connection, sig_ctx).await?;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
info!("AniMe control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let _ = AuraManager::new(connection.clone()).await?;
|
let _ = AuraManager::new(connection.clone()).await?;
|
||||||
|
|
||||||
// Request dbus name after finishing initalizing all functions
|
// Request dbus name after finishing initalizing all functions
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use config_traits::ron;
|
|||||||
use rog_anime::error::AnimeError;
|
use rog_anime::error::AnimeError;
|
||||||
use rog_platform::error::PlatformError;
|
use rog_platform::error::PlatformError;
|
||||||
use rog_profiles::error::ProfileError;
|
use rog_profiles::error::ProfileError;
|
||||||
|
use rog_slash::error::SlashError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RogError {
|
pub enum RogError {
|
||||||
@@ -31,6 +32,7 @@ pub enum RogError {
|
|||||||
NoAuraKeyboard,
|
NoAuraKeyboard,
|
||||||
NoAuraNode,
|
NoAuraNode,
|
||||||
Anime(AnimeError),
|
Anime(AnimeError),
|
||||||
|
Slash(SlashError),
|
||||||
Platform(PlatformError),
|
Platform(PlatformError),
|
||||||
SystemdUnitAction(String),
|
SystemdUnitAction(String),
|
||||||
SystemdUnitWaitTimeout(String),
|
SystemdUnitWaitTimeout(String),
|
||||||
@@ -72,6 +74,7 @@ impl fmt::Display for RogError {
|
|||||||
RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"),
|
RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"),
|
||||||
RogError::NoAuraNode => write!(f, "No Aura keyboard node found"),
|
RogError::NoAuraNode => write!(f, "No Aura keyboard node found"),
|
||||||
RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets),
|
RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets),
|
||||||
|
RogError::Slash(deets) => write!(f, "Slash error: {}", deets),
|
||||||
RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets),
|
RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets),
|
||||||
RogError::SystemdUnitAction(action) => {
|
RogError::SystemdUnitAction(action) => {
|
||||||
write!(f, "systemd unit action {} failed", action)
|
write!(f, "systemd unit action {} failed", action)
|
||||||
@@ -103,6 +106,12 @@ impl From<AnimeError> for RogError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SlashError> for RogError {
|
||||||
|
fn from(err: SlashError) -> Self {
|
||||||
|
RogError::Slash(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<PlatformError> for RogError {
|
impl From<PlatformError> for RogError {
|
||||||
fn from(err: PlatformError) -> Self {
|
fn from(err: PlatformError) -> Self {
|
||||||
RogError::Platform(err)
|
RogError::Platform(err)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
/// Control of anime matrix display
|
/// Control of anime matrix display
|
||||||
pub mod ctrl_anime;
|
pub mod ctrl_anime;
|
||||||
|
/// Control of Slash led bar
|
||||||
|
pub mod ctrl_slash;
|
||||||
/// Keyboard LED brightness control, RGB, and LED display modes
|
/// Keyboard LED brightness control, RGB, and LED display modes
|
||||||
pub mod ctrl_aura;
|
pub mod ctrl_aura;
|
||||||
/// Control platform profiles + fan-curves if available
|
/// Control platform profiles + fan-curves if available
|
||||||
@@ -50,7 +52,7 @@ pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
|||||||
/// task_watch_item!(panel_od platform);
|
/// task_watch_item!(panel_od platform);
|
||||||
/// task_watch_item!(gpu_mux_mode platform);
|
/// task_watch_item!(gpu_mux_mode platform);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```\
|
||||||
/// // TODO: this is kind of useless if it can't trigger some action
|
/// // TODO: this is kind of useless if it can't trigger some action
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! task_watch_item {
|
macro_rules! task_watch_item {
|
||||||
@@ -130,7 +132,7 @@ pub fn print_board_info() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Reloadable {
|
pub trait Reloadable {
|
||||||
fn reload(&mut self) -> impl std::future::Future<Output = Result<(), RogError>> + Send;
|
fn reload(&mut self) -> impl Future<Output = Result<(), RogError>> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ReloadAndNotify {
|
pub trait ReloadAndNotify {
|
||||||
@@ -140,18 +142,18 @@ pub trait ReloadAndNotify {
|
|||||||
&mut self,
|
&mut self,
|
||||||
signal_context: &SignalContext<'static>,
|
signal_context: &SignalContext<'static>,
|
||||||
data: Self::Data,
|
data: Self::Data,
|
||||||
) -> impl std::future::Future<Output = Result<(), RogError>> + Send;
|
) -> impl Future<Output = Result<(), RogError>> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ZbusRun {
|
pub trait ZbusRun {
|
||||||
fn add_to_server(self, server: &mut Connection)
|
fn add_to_server(self, server: &mut Connection)
|
||||||
-> impl std::future::Future<Output = ()> + Send;
|
-> impl Future<Output = ()> + Send;
|
||||||
|
|
||||||
fn add_to_server_helper(
|
fn add_to_server_helper(
|
||||||
iface: impl zbus::Interface,
|
iface: impl zbus::Interface,
|
||||||
path: &str,
|
path: &str,
|
||||||
server: &mut Connection,
|
server: &mut Connection,
|
||||||
) -> impl std::future::Future<Output = ()> + Send {
|
) -> impl Future<Output = ()> + Send {
|
||||||
async move {
|
async move {
|
||||||
server
|
server
|
||||||
.object_server()
|
.object_server()
|
||||||
@@ -180,7 +182,7 @@ pub trait CtrlTask {
|
|||||||
fn create_tasks(
|
fn create_tasks(
|
||||||
&self,
|
&self,
|
||||||
signal: SignalContext<'static>,
|
signal: SignalContext<'static>,
|
||||||
) -> impl std::future::Future<Output = Result<(), RogError>> + Send;
|
) -> impl Future<Output = Result<(), RogError>> + Send;
|
||||||
|
|
||||||
// /// Create a timed repeating task
|
// /// Create a timed repeating task
|
||||||
// async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send +
|
// async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send +
|
||||||
@@ -213,7 +215,7 @@ pub trait CtrlTask {
|
|||||||
mut on_prepare_for_shutdown: F2,
|
mut on_prepare_for_shutdown: F2,
|
||||||
mut on_lid_change: F3,
|
mut on_lid_change: F3,
|
||||||
mut on_external_power_change: F4,
|
mut on_external_power_change: F4,
|
||||||
) -> impl std::future::Future<Output = ()> + Send
|
) -> impl Future<Output = ()> + Send
|
||||||
where
|
where
|
||||||
F1: FnMut(bool) -> Fut1,
|
F1: FnMut(bool) -> Fut1,
|
||||||
F2: FnMut(bool) -> Fut2,
|
F2: FnMut(bool) -> Fut2,
|
||||||
@@ -307,13 +309,13 @@ pub async fn start_tasks<T>(
|
|||||||
where
|
where
|
||||||
T: ZbusRun + Reloadable + CtrlTask + Clone,
|
T: ZbusRun + Reloadable + CtrlTask + Clone,
|
||||||
{
|
{
|
||||||
let task = zbus.clone();
|
let zbus_clone = zbus.clone();
|
||||||
|
|
||||||
zbus.reload()
|
zbus.reload()
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|err| warn!("Controller error: {}", err));
|
.unwrap_or_else(|err| warn!("Controller error: {}", err));
|
||||||
zbus.add_to_server(connection).await;
|
zbus.add_to_server(connection).await;
|
||||||
|
|
||||||
task.create_tasks(signal_ctx).await.ok();
|
zbus_clone.create_tasks(signal_ctx).await.ok();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
|
||||||
<node>
|
<node>
|
||||||
<interface name="org.asuslinux.Daemon">
|
<interface name="org.asuslinux.Daemon">
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -735,4 +735,12 @@
|
|||||||
advanced_type: None,
|
advanced_type: None,
|
||||||
power_zones: [Keyboard],
|
power_zones: [Keyboard],
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
board_name: "GA403UI",
|
||||||
|
layout_name: "ga401q",
|
||||||
|
basic_modes: [Static, Breathe, Pulse],
|
||||||
|
basic_zones: [],
|
||||||
|
advanced_type: None,
|
||||||
|
power_zones: [Keyboard],
|
||||||
|
),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ impl StdConfig for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn file_name(&self) -> String {
|
||||||
|
CFG_FILE_NAME.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
fn config_dir() -> std::path::PathBuf {
|
fn config_dir() -> std::path::PathBuf {
|
||||||
let mut path = dirs::config_dir().unwrap_or_default();
|
let mut path = dirs::config_dir().unwrap_or_default();
|
||||||
|
|
||||||
@@ -62,10 +66,6 @@ impl StdConfig for Config {
|
|||||||
}
|
}
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_name(&self) -> String {
|
|
||||||
CFG_FILE_NAME.to_owned()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdConfigLoad1<Config461> for Config {}
|
impl StdConfigLoad1<Config461> for Config {}
|
||||||
|
|||||||
@@ -41,17 +41,13 @@ async fn main() -> Result<()> {
|
|||||||
let board_name = dmi.board_name;
|
let board_name = dmi.board_name;
|
||||||
let prod_family = dmi.product_family;
|
let prod_family = dmi.product_family;
|
||||||
info!("Running on {board_name}, product: {prod_family}");
|
info!("Running on {board_name}, product: {prod_family}");
|
||||||
let is_rog_ally = prod_family == "RC71L";
|
// let is_rog_ally = prod_family == "RC71L";
|
||||||
|
|
||||||
// tmp-dir must live to the end of program life
|
// tmp-dir must live to the end of program life
|
||||||
let _tmp_dir = match tempfile::Builder::new()
|
let _tmp_dir = tempfile::Builder::new()
|
||||||
.prefix("rog-gui")
|
.prefix("rog-gui")
|
||||||
.rand_bytes(0)
|
.rand_bytes(0)
|
||||||
.tempdir()
|
.tempdir().unwrap_or_else(|_| on_tmp_dir_exists().unwrap());
|
||||||
{
|
|
||||||
Ok(tmp) => tmp,
|
|
||||||
Err(_) => on_tmp_dir_exists().unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let args: Vec<String> = args().skip(1).collect();
|
let args: Vec<String> = args().skip(1).collect();
|
||||||
|
|
||||||
@@ -84,8 +80,7 @@ async fn main() -> Result<()> {
|
|||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
// TODO: show an error window
|
// TODO: show an error window
|
||||||
Vec::default()
|
Vec::default()
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
// Startup
|
// Startup
|
||||||
let mut config = Config::new().load();
|
let mut config = Config::new().load();
|
||||||
@@ -127,7 +122,8 @@ async fn main() -> Result<()> {
|
|||||||
init_tray(supported_properties, states.clone(), config.clone());
|
init_tray(supported_properties, states.clone(), config.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! { pub static UI: std::cell::RefCell<Option<MainWindow>> = Default::default()};
|
thread_local! { pub static UI: std::cell::RefCell<Option<MainWindow>> = Default::default()}
|
||||||
|
;
|
||||||
i_slint_backend_selector::with_platform(|_| Ok(())).unwrap();
|
i_slint_backend_selector::with_platform(|_| Ok(())).unwrap();
|
||||||
|
|
||||||
let mut do_once = !startup_in_background;
|
let mut do_once = !startup_in_background;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
asusd = { path = "../asusd" }
|
asusd = { path = "../asusd" }
|
||||||
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
||||||
|
rog_slash = { path = "../rog-slash", features = ["dbus"] }
|
||||||
rog_aura = { path = "../rog-aura" }
|
rog_aura = { path = "../rog-aura" }
|
||||||
rog_profiles = { path = "../rog-profiles" }
|
rog_profiles = { path = "../rog-profiles" }
|
||||||
rog_platform = { path = "../rog-platform" }
|
rog_platform = { path = "../rog-platform" }
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
pub use asusd::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
pub use asusd::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
||||||
|
|
||||||
pub mod zbus_anime;
|
pub mod zbus_anime;
|
||||||
pub mod zbus_aura;
|
pub mod zbus_aura;
|
||||||
pub mod zbus_fan_curves;
|
pub mod zbus_fan_curves;
|
||||||
pub mod zbus_platform;
|
pub mod zbus_platform;
|
||||||
|
pub mod zbus_slash;
|
||||||
|
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|||||||
34
rog-dbus/src/zbus_slash.rs
Normal file
34
rog-dbus/src/zbus_slash.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use zbus::proxy;
|
||||||
|
use rog_slash::SlashMode;
|
||||||
|
|
||||||
|
#[proxy(
|
||||||
|
interface = "org.asuslinux.Slash",
|
||||||
|
default_service = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux"
|
||||||
|
)]
|
||||||
|
trait Slash {
|
||||||
|
/// EnableDisplay property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn enabled(&self) -> zbus::Result<bool>;
|
||||||
|
// #[zbus(property)]
|
||||||
|
fn set_enabled(&self, value: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Brightness property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn brightness(&self) -> zbus::Result<u8>;
|
||||||
|
// #[zbus(property)]
|
||||||
|
fn set_brightness(&self, value: u8) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Interval property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn interval(&self) -> zbus::Result<u8>;
|
||||||
|
// #[zbus(property)]
|
||||||
|
fn set_interval(&self, value: u8) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Slash modes property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn slash_mode(&self) -> zbus::Result<SlashMode>;
|
||||||
|
// #[zbus(property)]
|
||||||
|
fn set_slash_mode(&self, value: SlashMode) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
}
|
||||||
40
rog-slash/Cargo.toml
Normal file
40
rog-slash/Cargo.toml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[package]
|
||||||
|
name = "rog_slash"
|
||||||
|
license = "MPL-2.0"
|
||||||
|
version.workspace = true
|
||||||
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||||
|
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||||
|
documentation = "https://docs.rs/rog-slash"
|
||||||
|
description = "ASUS Slash display"
|
||||||
|
keywords = ["ROG", "ASUS", "AniMe", "Slash"]
|
||||||
|
edition = "2021"
|
||||||
|
exclude = ["data"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["dbus", "detect"]
|
||||||
|
dbus = ["zbus"]
|
||||||
|
detect = ["dmi_id"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "rog_slash"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
png_pong.workspace = true
|
||||||
|
pix.workspace = true
|
||||||
|
gif.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
|
||||||
|
serde.workspace = true
|
||||||
|
serde_derive.workspace = true
|
||||||
|
|
||||||
|
glam.workspace = true
|
||||||
|
typeshare.workspace = true
|
||||||
|
|
||||||
|
zbus = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
dmi_id = { path = "../dmi-id", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
cargo-husky.workspace = true
|
||||||
137
rog-slash/src/data.rs
Normal file
137
rog-slash/src/data.rs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use typeshare::typeshare;
|
||||||
|
#[cfg(feature = "dbus")]
|
||||||
|
use zbus::zvariant::Type;
|
||||||
|
use zbus::zvariant::{OwnedValue, Value};
|
||||||
|
|
||||||
|
use crate::error::SlashError;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub enum SlashType {
|
||||||
|
GA403,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for SlashType {
|
||||||
|
type Err = SlashError;
|
||||||
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"ga403" | "GA403" => Self::GA403,
|
||||||
|
_ => Self::Unknown,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[typeshare]
|
||||||
|
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
|
||||||
|
pub enum SlashMode {
|
||||||
|
Bounce = 0x10,
|
||||||
|
Slash = 0x12,
|
||||||
|
Loading = 0x13,
|
||||||
|
BitStream = 0x1D,
|
||||||
|
Transmission = 0x1A,
|
||||||
|
Flow = 0x19,
|
||||||
|
Flux = 0x25,
|
||||||
|
Phantom = 0x24,
|
||||||
|
Spectrum = 0x26,
|
||||||
|
Hazard = 0x32,
|
||||||
|
Interfacing = 0x33,
|
||||||
|
Ramp = 0x34,
|
||||||
|
GameOver = 0x42,
|
||||||
|
Start = 0x43,
|
||||||
|
Buzzer = 0x44,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SlashMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
SlashMode::Flow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for SlashMode {
|
||||||
|
type Err = SlashError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, SlashError> {
|
||||||
|
match s {
|
||||||
|
"Bounce" => Ok(SlashMode::Bounce),
|
||||||
|
"Slash" => Ok(SlashMode::Slash),
|
||||||
|
"Loading" => Ok(SlashMode::Loading),
|
||||||
|
"BitStream" => Ok(SlashMode::BitStream),
|
||||||
|
"Transmission" => Ok(SlashMode::Transmission),
|
||||||
|
"Flow" => Ok(SlashMode::Flow),
|
||||||
|
"Flux" => Ok(SlashMode::Flux),
|
||||||
|
"Phantom" => Ok(SlashMode::Phantom),
|
||||||
|
"Spectrum" => Ok(SlashMode::Spectrum),
|
||||||
|
"Hazard" => Ok(SlashMode::Hazard),
|
||||||
|
"Interfacing" => Ok(SlashMode::Interfacing),
|
||||||
|
"Ramp" => Ok(SlashMode::Ramp),
|
||||||
|
"GameOver" => Ok(SlashMode::GameOver),
|
||||||
|
"Start" => Ok(SlashMode::Start),
|
||||||
|
"Buzzer" => Ok(SlashMode::Buzzer),
|
||||||
|
_ => Ok(SlashMode::Bounce),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Display for SlashMode {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let str = match &self {
|
||||||
|
SlashMode::Bounce => String::from("Bounce"),
|
||||||
|
SlashMode::Slash => String::from("Slash"),
|
||||||
|
SlashMode::Loading => String::from("Loading"),
|
||||||
|
SlashMode::BitStream => String::from("BitStream"),
|
||||||
|
SlashMode::Transmission => String::from("Transmission"),
|
||||||
|
SlashMode::Flow => String::from("Flow"),
|
||||||
|
SlashMode::Flux => String::from("Flux"),
|
||||||
|
SlashMode::Phantom => String::from("Phantom"),
|
||||||
|
SlashMode::Spectrum => String::from("Spectrum"),
|
||||||
|
SlashMode::Hazard => String::from("Hazard"),
|
||||||
|
SlashMode::Interfacing => String::from("Interfacing"),
|
||||||
|
SlashMode::Ramp => String::from("Ramp"),
|
||||||
|
SlashMode::GameOver => String::from("GameOver"),
|
||||||
|
SlashMode::Start => String::from("Start"),
|
||||||
|
SlashMode::Buzzer => String::from("Buzzer"),
|
||||||
|
};
|
||||||
|
write!(f, "{}", str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SlashMode {
|
||||||
|
|
||||||
|
pub fn list() -> [String; 15] {
|
||||||
|
[
|
||||||
|
SlashMode::Bounce.to_string(),
|
||||||
|
SlashMode::Slash.to_string(),
|
||||||
|
SlashMode::Loading.to_string(),
|
||||||
|
SlashMode::BitStream.to_string(),
|
||||||
|
SlashMode::Transmission.to_string(),
|
||||||
|
SlashMode::Flow.to_string(),
|
||||||
|
SlashMode::Flux.to_string(),
|
||||||
|
SlashMode::Phantom.to_string(),
|
||||||
|
SlashMode::Spectrum.to_string(),
|
||||||
|
SlashMode::Hazard.to_string(),
|
||||||
|
SlashMode::Interfacing.to_string(),
|
||||||
|
SlashMode::Ramp.to_string(),
|
||||||
|
SlashMode::GameOver.to_string(),
|
||||||
|
SlashMode::Start.to_string(),
|
||||||
|
SlashMode::Buzzer.to_string(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[typeshare]
|
||||||
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[typeshare]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct DeviceState {
|
||||||
|
pub slash_enabled: bool,
|
||||||
|
pub slash_brightness: u8,
|
||||||
|
pub slash_interval: u8,
|
||||||
|
pub slash_mode: SlashMode,
|
||||||
|
}
|
||||||
|
|
||||||
39
rog-slash/src/error.rs
Normal file
39
rog-slash/src/error.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
pub type Result<T> = std::result::Result<T, SlashError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SlashError {
|
||||||
|
Dbus(String),
|
||||||
|
Udev(String, std::io::Error),
|
||||||
|
NoDevice,
|
||||||
|
UnsupportedDevice,
|
||||||
|
DataBufferLength,
|
||||||
|
ParseError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SlashError {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
SlashError::ParseError(e) => write!(f, "Could not parse {e}"),
|
||||||
|
SlashError::Dbus(detail) => write!(f, "{}", detail),
|
||||||
|
SlashError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
|
||||||
|
SlashError::NoDevice => write!(f, "No Slash device found"),
|
||||||
|
SlashError::DataBufferLength => write!(
|
||||||
|
f,
|
||||||
|
"The data buffer was incorrect length for generating USB packets"
|
||||||
|
),
|
||||||
|
SlashError::UnsupportedDevice => write!(f, "Unsupported Slash device found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for SlashError {}
|
||||||
|
|
||||||
|
impl From<SlashError> for zbus::fdo::Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(err: SlashError) -> Self {
|
||||||
|
zbus::fdo::Error::Failed(format!("{}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
12
rog-slash/src/lib.rs
Normal file
12
rog-slash/src/lib.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/// The main data conversion for transfering in shortform over dbus or other,
|
||||||
|
/// or writing directly to the USB device
|
||||||
|
mod data;
|
||||||
|
pub use data::*;
|
||||||
|
|
||||||
|
/// Base errors that are possible
|
||||||
|
pub mod error;
|
||||||
|
|
||||||
|
/// Provides const methods to create the USB HID control packets
|
||||||
|
pub mod usb;
|
||||||
|
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
129
rog-slash/src/usb.rs
Normal file
129
rog-slash/src/usb.rs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
//! Utils for writing to the `Slash` 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 `SLashPacketType`
|
||||||
|
//! 3. Write the packet from `get_flush_packet()`, which tells the device to
|
||||||
|
//! display the data from step 2
|
||||||
|
//!
|
||||||
|
//! Step 1 needs to be applied only on fresh system boot.
|
||||||
|
|
||||||
|
use dmi_id::DMIID;
|
||||||
|
#[cfg(feature = "dbus")]
|
||||||
|
use crate::error::SlashError;
|
||||||
|
use crate::{SlashMode, SlashType};
|
||||||
|
|
||||||
|
const PACKET_SIZE: usize = 128;
|
||||||
|
const DEV_PAGE: u8 = 0x5e;
|
||||||
|
pub const VENDOR_ID: u16 = 0x0B05;
|
||||||
|
pub const PROD_ID: u16 = 0x193B;
|
||||||
|
pub const PROD_ID_STR: &str = "193B";
|
||||||
|
|
||||||
|
pub type SlashUsbPacket = [u8;PACKET_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
/// `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 `193B`.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_slash_type() -> Result<SlashType, SlashError> {
|
||||||
|
let dmi = DMIID::new().map_err(|_| SlashError::NoDevice)?; // TODO: better error
|
||||||
|
let board_name = dmi.board_name;
|
||||||
|
|
||||||
|
if board_name.contains("GA403") {
|
||||||
|
return Ok(SlashType::GA403);
|
||||||
|
}
|
||||||
|
log::warn!("AniMe Slash device found but not yet supported, will default to a GA403 layout");
|
||||||
|
Ok(SlashType::Unknown)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the two device initialization packets. These are required for device
|
||||||
|
/// start after the laptop boots.
|
||||||
|
#[inline]
|
||||||
|
pub const fn pkts_for_init() -> [SlashUsbPacket; 2] {
|
||||||
|
let mut pkt1 = [0;PACKET_SIZE];
|
||||||
|
pkt1[0] = DEV_PAGE;
|
||||||
|
pkt1[1] = 0xD7;
|
||||||
|
pkt1[2] = 0x00;
|
||||||
|
pkt1[3] = 0x00;
|
||||||
|
pkt1[4] = 0x01;
|
||||||
|
pkt1[5] = 0xAC;
|
||||||
|
|
||||||
|
let mut pkt2 = [0;PACKET_SIZE];
|
||||||
|
pkt2[0] = DEV_PAGE;
|
||||||
|
pkt2[1] = 0xD2;
|
||||||
|
pkt2[2] = 0x02;
|
||||||
|
pkt2[3] = 0x01;
|
||||||
|
pkt2[4] = 0x08;
|
||||||
|
pkt2[5] = 0xAB;
|
||||||
|
|
||||||
|
[pkt1, pkt2]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn pkt_save() -> SlashUsbPacket {
|
||||||
|
let mut pkt = [0;PACKET_SIZE];
|
||||||
|
pkt[0] = DEV_PAGE;
|
||||||
|
pkt[1] = 0xD4;
|
||||||
|
pkt[2] = 0x00;
|
||||||
|
pkt[3] = 0x00;
|
||||||
|
pkt[4] = 0x01;
|
||||||
|
pkt[5] = 0xAB;
|
||||||
|
|
||||||
|
pkt
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn pkt_set_mode(mode: SlashMode) -> [SlashUsbPacket; 2] {
|
||||||
|
let mut pkt1 = [0;PACKET_SIZE];
|
||||||
|
pkt1[0] = DEV_PAGE;
|
||||||
|
pkt1[1] = 0x02;
|
||||||
|
pkt1[2] = 0x03;
|
||||||
|
pkt1[3] = 0x00;
|
||||||
|
pkt1[4] = 0x0C;
|
||||||
|
|
||||||
|
let mut pkt2 = [0;PACKET_SIZE];
|
||||||
|
pkt2[0] = DEV_PAGE;
|
||||||
|
pkt2[1] = 0xD3;
|
||||||
|
pkt2[2] = 0x04;
|
||||||
|
pkt2[3] = 0x00;
|
||||||
|
pkt2[4] = 0x0C;
|
||||||
|
pkt2[5] = 0x01;
|
||||||
|
pkt2[6] = mode as u8;
|
||||||
|
pkt2[7] = 0x02;
|
||||||
|
pkt2[8] = 0x19;
|
||||||
|
pkt2[9] = 0x03;
|
||||||
|
pkt2[10] = 0x13;
|
||||||
|
pkt2[11] = 0x04;
|
||||||
|
pkt2[12] = 0x11;
|
||||||
|
pkt2[13] = 0x05;
|
||||||
|
pkt2[14] = 0x12;
|
||||||
|
pkt2[15] = 0x06;
|
||||||
|
pkt2[16] = 0x13;
|
||||||
|
|
||||||
|
[pkt1, pkt2]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn pkt_set_options(enabled: bool, brightness: u8, interval: u8) -> SlashUsbPacket {
|
||||||
|
let status_byte = if enabled { 0x01 } else { 0x00 };
|
||||||
|
|
||||||
|
let mut pkt = [0;PACKET_SIZE];
|
||||||
|
pkt[0] = DEV_PAGE;
|
||||||
|
pkt[1] = 0xD3;
|
||||||
|
pkt[2] = 0x03;
|
||||||
|
pkt[3] = 0x01;
|
||||||
|
pkt[4] = 0x08;
|
||||||
|
pkt[5] = 0xAB;
|
||||||
|
pkt[6] = 0xFF;
|
||||||
|
pkt[7] = 0x01;
|
||||||
|
pkt[8] = status_byte;
|
||||||
|
pkt[9] = 0x06;
|
||||||
|
pkt[10] = brightness;
|
||||||
|
pkt[11] = 0xFF;
|
||||||
|
pkt[12] = interval;
|
||||||
|
|
||||||
|
pkt
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user