mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-01-22 09:23:19 +01:00
230 lines
8.1 KiB
Rust
230 lines
8.1 KiB
Rust
use std::sync::Arc;
|
|
|
|
use config::AuraConfig;
|
|
use config_traits::StdConfig;
|
|
use log::info;
|
|
use rog_aura::keyboard::{AuraLaptopUsbPackets, LedUsbPackets};
|
|
use rog_aura::usb::{AURA_LAPTOP_LED_APPLY, AURA_LAPTOP_LED_SET};
|
|
use rog_aura::{AuraDeviceType, AuraEffect, LedBrightness, PowerZones, AURA_LAPTOP_LED_MSG_LEN};
|
|
use rog_platform::hid_raw::HidRaw;
|
|
use rog_platform::keyboard_led::KeyboardBacklight;
|
|
use tokio::sync::{Mutex, MutexGuard};
|
|
|
|
use crate::error::RogError;
|
|
|
|
pub mod config;
|
|
pub mod trait_impls;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Aura {
|
|
pub hid: Option<Arc<Mutex<HidRaw>>>,
|
|
pub backlight: Option<Arc<Mutex<KeyboardBacklight>>>,
|
|
pub config: Arc<Mutex<AuraConfig>>,
|
|
}
|
|
|
|
impl Aura {
|
|
/// Initialise the device if required.
|
|
pub async fn do_initialization(&self) -> Result<(), RogError> {
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn lock_config(&self) -> MutexGuard<'_, AuraConfig> {
|
|
self.config.lock().await
|
|
}
|
|
|
|
/// Will lock the internal config and update. If anything else has locked
|
|
/// this in scope then a deadlock can occur.
|
|
pub async fn update_config(&self) -> Result<(), RogError> {
|
|
let mut config = self.config.lock().await;
|
|
let bright = if let Some(bl) = self.backlight.as_ref() {
|
|
bl.lock().await.get_brightness().unwrap_or_default()
|
|
} else {
|
|
config.brightness.into()
|
|
};
|
|
config.read();
|
|
config.brightness = bright.into();
|
|
config.write();
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn write_current_config_mode(&self, config: &mut AuraConfig) -> Result<(), RogError> {
|
|
if config.multizone_on {
|
|
let mode = config.current_mode;
|
|
let mut create = false;
|
|
// There is no multizone config for this mode so create one here
|
|
// using the colours of rainbow if it exists, or first available
|
|
// mode, or random
|
|
if config.multizone.is_none() {
|
|
create = true;
|
|
} else if let Some(multizones) = config.multizone.as_ref() {
|
|
if !multizones.contains_key(&mode) {
|
|
create = true;
|
|
}
|
|
}
|
|
if create {
|
|
info!("No user-set config for zone founding, attempting a default");
|
|
config.create_multizone_default()?;
|
|
}
|
|
|
|
if let Some(multizones) = config.multizone.as_mut() {
|
|
if let Some(set) = multizones.get(&mode) {
|
|
for mode in set.clone() {
|
|
self.write_effect_and_apply(config.led_type, &mode).await?;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
let mode = config.current_mode;
|
|
if let Some(effect) = config.builtins.get(&mode).cloned() {
|
|
self.write_effect_and_apply(config.led_type, &effect)
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Write the AuraEffect to the device. Will lock `backlight` or `hid`.
|
|
///
|
|
/// If per-key or software-mode is active it must be marked as disabled in
|
|
/// config.
|
|
pub async fn write_effect_and_apply(
|
|
&self,
|
|
dev_type: AuraDeviceType,
|
|
mode: &AuraEffect,
|
|
) -> Result<(), RogError> {
|
|
if matches!(dev_type, AuraDeviceType::LaptopKeyboardTuf) {
|
|
if let Some(platform) = &self.backlight {
|
|
let buf = [
|
|
1, mode.mode as u8, mode.colour1.r, mode.colour1.g, mode.colour1.b,
|
|
mode.speed as u8,
|
|
];
|
|
platform.lock().await.set_kbd_rgb_mode(&buf)?;
|
|
}
|
|
} else if let Some(hid_raw) = &self.hid {
|
|
let bytes: [u8; AURA_LAPTOP_LED_MSG_LEN] = mode.into();
|
|
let hid_raw = hid_raw.lock().await;
|
|
hid_raw.write_bytes(&bytes)?;
|
|
hid_raw.write_bytes(&AURA_LAPTOP_LED_SET)?;
|
|
// Changes won't persist unless apply is set
|
|
hid_raw.write_bytes(&AURA_LAPTOP_LED_APPLY)?;
|
|
} else {
|
|
return Err(RogError::NoAuraKeyboard);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn set_brightness(&self, value: u8) -> Result<(), RogError> {
|
|
if let Some(backlight) = &self.backlight {
|
|
backlight.lock().await.set_brightness(value)?;
|
|
return Ok(());
|
|
}
|
|
Err(RogError::MissingFunction(
|
|
"No LED backlight control available".to_string(),
|
|
))
|
|
}
|
|
|
|
/// Set combination state for boot animation/sleep animation/all leds/keys
|
|
/// leds/side leds LED active
|
|
pub async fn set_power_states(&self, config: &AuraConfig) -> Result<(), RogError> {
|
|
if matches!(config.led_type, rog_aura::AuraDeviceType::LaptopKeyboardTuf) {
|
|
if let Some(backlight) = &self.backlight {
|
|
// TODO: tuf bool array
|
|
let buf = config.enabled.to_bytes(config.led_type);
|
|
backlight.lock().await.set_kbd_rgb_state(&buf)?;
|
|
}
|
|
} else if let Some(hid_raw) = &self.hid {
|
|
let hid_raw = hid_raw.lock().await;
|
|
if let Some(p) = config.enabled.states.first() {
|
|
if p.zone == PowerZones::Ally {
|
|
let msg = [
|
|
0x5d,
|
|
0xd1,
|
|
0x09,
|
|
0x01,
|
|
p.new_to_byte() as u8,
|
|
0x0,
|
|
0x0,
|
|
];
|
|
hid_raw.write_bytes(&msg)?;
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
let bytes = config.enabled.to_bytes(config.led_type);
|
|
let msg = [
|
|
0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3],
|
|
];
|
|
hid_raw.write_bytes(&msg)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Write an effect block. This is for per-key, but can be repurposed to
|
|
/// write the raw factory mode packets - when doing this it is expected that
|
|
/// only the first `Vec` (`effect[0]`) is valid.
|
|
pub async fn write_effect_block(
|
|
&self,
|
|
config: &mut AuraConfig,
|
|
effect: &AuraLaptopUsbPackets,
|
|
) -> Result<(), RogError> {
|
|
if config.brightness == LedBrightness::Off {
|
|
config.brightness = LedBrightness::Med;
|
|
config.write();
|
|
}
|
|
|
|
let pkt_type = effect[0][1];
|
|
const PER_KEY_TYPE: u8 = 0xbc;
|
|
|
|
if let Some(hid_raw) = &self.hid {
|
|
let hid_raw = hid_raw.lock().await;
|
|
if pkt_type != PER_KEY_TYPE {
|
|
config.per_key_mode_active = false;
|
|
hid_raw.write_bytes(&effect[0])?;
|
|
hid_raw.write_bytes(&AURA_LAPTOP_LED_SET)?;
|
|
// hid_raw.write_bytes(&LED_APPLY)?;
|
|
} else {
|
|
if !config.per_key_mode_active {
|
|
let init = LedUsbPackets::get_init_msg();
|
|
hid_raw.write_bytes(&init)?;
|
|
config.per_key_mode_active = true;
|
|
}
|
|
for row in effect.iter() {
|
|
hid_raw.write_bytes(row)?;
|
|
}
|
|
}
|
|
} else if matches!(config.led_type, rog_aura::AuraDeviceType::LaptopKeyboardTuf) {
|
|
if let Some(tuf) = &self.backlight {
|
|
for row in effect.iter() {
|
|
let r = row[9];
|
|
let g = row[10];
|
|
let b = row[11];
|
|
tuf.lock().await.set_kbd_rgb_mode(&[
|
|
0, 0, r, g, b, 0,
|
|
])?;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn fix_ally_power(&mut self) -> Result<(), RogError> {
|
|
if self.config.lock().await.led_type == AuraDeviceType::Ally {
|
|
if let Some(hid_raw) = &self.hid {
|
|
let mut config = self.config.lock().await;
|
|
if config.ally_fix.is_none() {
|
|
let msg = [
|
|
0x5d, 0xbd, 0x01, 0xff, 0xff, 0xff, 0xff,
|
|
];
|
|
hid_raw.lock().await.write_bytes(&msg)?;
|
|
info!("Reset Ally power settings to base");
|
|
config.ally_fix = Some(true);
|
|
}
|
|
config.write();
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|