Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions asusctl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,23 +668,39 @@ fn handle_led_power_1_do_1866(
power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> {
let mut states = Vec::new();
if power.keyboard {
states.push(AuraPowerState {
zone: PowerZones::Keyboard,
boot: power.boot.unwrap_or_default(),
awake: power.awake.unwrap_or_default(),
sleep: power.sleep.unwrap_or_default(),
shutdown: false,
});
}
if power.lightbar {
states.push(AuraPowerState {
zone: PowerZones::Lightbar,
boot: power.boot.unwrap_or_default(),
awake: power.awake.unwrap_or_default(),
sleep: power.sleep.unwrap_or_default(),
shutdown: false,
});
let is_tuf = aura.device_type()?.is_tuf_laptop();

// TUF laptops have only a keyboard zone; lightbar does not exist.
if is_tuf {
if power.keyboard || power.lightbar {
states.push(AuraPowerState {
zone: PowerZones::Keyboard,
boot: power.boot.unwrap_or_default(),
awake: power.awake.unwrap_or_default(),
sleep: power.sleep.unwrap_or_default(),
shutdown: false,
});
}
} else {
// Pre-2021 0x1866 keyboards may have separate keyboard and lightbar zones.
if power.keyboard {
states.push(AuraPowerState {
zone: PowerZones::Keyboard,
boot: power.boot.unwrap_or_default(),
awake: power.awake.unwrap_or_default(),
sleep: power.sleep.unwrap_or_default(),
shutdown: false,
});
}
if power.lightbar {
states.push(AuraPowerState {
zone: PowerZones::Lightbar,
boot: power.boot.unwrap_or_default(),
awake: power.awake.unwrap_or_default(),
sleep: power.sleep.unwrap_or_default(),
shutdown: false,
});
}
}

let states = LaptopAuraPower { states };
Expand Down
21 changes: 20 additions & 1 deletion asusd/src/aura_laptop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,16 @@ impl Aura {
} else {
config.brightness.into()
};
// These fields are derived during device discovery and deliberately
// excluded from the on-disk configuration. `read()` replaces the
// entire struct, so retain them when refreshing settings for sleep.
let led_type = config.led_type;
let support_data = config.support_data.clone();
let per_key_mode_active = config.per_key_mode_active;
config.read();
config.led_type = led_type;
config.support_data = support_data;
config.per_key_mode_active = per_key_mode_active;
config.brightness = bright.into();
config.write();
Ok(())
Expand Down Expand Up @@ -144,7 +153,17 @@ impl Aura {
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)?;
let backlight = backlight.lock().await;
// Some FA401UH firmware/kernel combinations expose brightness
// and RGB mode but not the optional power-state attribute.
// Power changes must not make the whole Aura interface fail.
if backlight.has_kbd_rgb_state() {
backlight.set_kbd_rgb_state(&buf)?;
} else {
log::debug!(
"TUF keyboard does not expose kbd_rgb_state; skipping power-state write"
);
}
}
} else if let Some(hid_raw) = &self.hid {
let hid_raw = hid_raw.lock().await;
Expand Down
97 changes: 57 additions & 40 deletions asusd/src/aura_laptop/trait_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,27 @@ impl AuraZbus {
pub async fn start_tasks(
mut self,
connection: &Connection,
// _signal_ctx: SignalEmitter<'static>,
path: OwnedObjectPath,
) -> Result<(), RogError> {
// let task = zbus.clone();
// let signal_ctx = signal_ctx.clone();
self.reload()
.await
.unwrap_or_else(|err| warn!("Controller error: {}", err));
let task = self.clone();
connection
.object_server()
.at(path.clone(), self)
.await
.map_err(|e| error!("Couldn't add server at path: {path}, {e:?}"))
.ok();
// TODO: skip this until we keep handles to tasks so they can be killed
// task.create_tasks(signal_ctx).await
// Subscribe to logind sleep/shutdown events. Without this call the
// Aura interface is available, but the keyboard controller never
// receives on_prepare_for_sleep notifications.
let signal_ctx = SignalEmitter::new(connection, AURA_ZBUS_PATH)?;
info!("Starting CtrlKbdLedTask system-event subscription");
task.create_tasks(signal_ctx).await?;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
info!("Started CtrlKbdLedTask system-event subscription");
Ok(())
}
}
Expand Down Expand Up @@ -241,62 +246,74 @@ impl CtrlTask for AuraZbus {
}

async fn create_tasks(&self, _: SignalEmitter<'static>) -> Result<(), RogError> {
info!("Creating Aura system-event callbacks");
let inner1 = self.0.clone();
let inner3 = self.0.clone();
self.create_sys_event_tasks(
move |sleeping| {
let inner1 = inner1.clone();
// unwrap as we want to bomb out of the task
async move {
if !sleeping {
info!("CtrlKbdLedTask received prepare_for_sleep({sleeping})");
if sleeping {
let (sleep_enabled, led_type, user_brightness) = {
let config = inner1.config.lock().await;
(
config.enabled.states.iter()
.any(|s| s.zone == rog_aura::PowerZones::Keyboard && s.sleep),
config.led_type,
u8::from(config.brightness),
)
};

let config = inner1.config.lock().await;
if let Err(e) = inner1.set_power_states(&config).await {
error!("CtrlKbdLedTask sleep power state write: {e}");
}

if sleep_enabled && led_type.is_tuf_laptop() {
info!("CtrlKbdLedTask sleep: TUF sleep strobe requires non-zero brightness");
if let Some(backlight) = &inner1.backlight {
let target_brightness: u8 = if user_brightness == 0 { 3 } else { user_brightness };
if let Err(e) = backlight.lock().await.set_brightness(target_brightness) {
error!("CtrlKbdLedTask sleep brightness: {e}");
}
}
}
} else {
info!("CtrlKbdLedTask reloading brightness and modes");
let (brightness, led_type) = {
let config = inner1.config.lock().await;
(config.brightness.into(), config.led_type)
};
if let Some(backlight) = &inner1.backlight {
backlight
.lock()
.await
.set_brightness(inner1.config.lock().await.brightness.into())
.map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})
.unwrap();
if let Err(e) = backlight.lock().await.set_brightness(brightness) {
error!("CtrlKbdLedTask wake brightness: {e}");
return;
}
}
let mut config = inner1.config.lock().await;
inner1
.write_current_config_mode(&mut config)
.await
.map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})
.unwrap();
} else if sleeping {
inner1
.update_config()
.await
.map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})
.unwrap();
if let Err(e) = inner1.write_current_config_mode(&mut config).await {
error!("CtrlKbdLedTask wake mode: {e}");
return;
}
if led_type.is_tuf_laptop()
&& let Err(e) = inner1.set_power_states(&config).await
{
error!("CtrlKbdLedTask wake power state: {e}");
}
}
}
},
move |_shutting_down| {
let inner3 = inner3.clone();
async move {
info!("CtrlKbdLedTask reloading brightness and modes");
let brightness = inner3.config.lock().await.brightness.into();
if let Some(backlight) = &inner3.backlight {
// unwrap as we want to bomb out of the task
backlight
.lock()
.await
.set_brightness(inner3.config.lock().await.brightness.into())
.map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})
.unwrap();
if let Err(e) = backlight.lock().await.set_brightness(brightness) {
error!("CtrlKbdLedTask: {e}");
}
}
}
},
Expand Down
19 changes: 13 additions & 6 deletions asusd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,14 +435,21 @@ pub trait CtrlTask {
tokio::spawn({
let logind_manager = logind_manager.clone();
async move {
if let Ok(mut notif) = logind_manager.receive_prepare_for_sleep().await {
while let Some(event) = notif.next().await {
// blocks thread :|
if let Ok(args) = event.args() {
debug!("Doing on_prepare_for_sleep({})", args.start);
on_prepare_for_sleep(args.start).await;
match logind_manager.receive_prepare_for_sleep().await {
Ok(mut notif) => {
info!("Subscribed to logind PrepareForSleep");
while let Some(event) = notif.next().await {
// blocks thread :|
if let Ok(args) = event.args() {
debug!("Doing on_prepare_for_sleep({})", args.start);
on_prepare_for_sleep(args.start).await;
} else {
warn!("Failed to decode logind PrepareForSleep signal");
}
}
warn!("logind PrepareForSleep stream ended");
}
Err(err) => warn!("Could not subscribe to logind PrepareForSleep: {err}"),
}
}
});
Expand Down
9 changes: 9 additions & 0 deletions rog-aura/data/aura_support.ron
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
([
(
device_name: "FA401",
product_id: "",
layout_name: "fa507",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FA506I",
product_id: "",
Expand Down
22 changes: 22 additions & 0 deletions rog-aura/src/keyboard/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,28 @@ mod test {
)
}

#[test]
fn tuf_power_bytes_include_boot_awake_and_sleep() {
let power = LaptopAuraPower {
states: vec![
AuraPowerState {
zone: PowerZones::Keyboard,
boot: true,
awake: false,
sleep: true,
shutdown: false,
},
],
};

assert_eq!(
power.to_bytes(AuraDeviceType::LaptopKeyboardTuf),
vec![
1, 1, 0, 1, 1
]
);
}

#[test]
fn check_0x1866_control_bytes() {
let power = LaptopAuraPower {
Expand Down