mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-01-22 17:33:19 +01:00
feature: add support for screenpad brightness
This commit is contained in:
@@ -73,7 +73,7 @@ sg = { git = "https://github.com/flukejones/sg-rs.git" }
|
|||||||
[profile.release]
|
[profile.release]
|
||||||
# thin = 57s, asusd = 9.0M
|
# thin = 57s, asusd = 9.0M
|
||||||
# fat = 72s, asusd = 6.4M
|
# fat = 72s, asusd = 6.4M
|
||||||
lto = "thin"
|
lto = "fat"
|
||||||
debug = false
|
debug = false
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ pub enum CliCommand {
|
|||||||
driver, some of the settings will be the same as the older platform interface"
|
driver, some of the settings will be the same as the older platform interface"
|
||||||
)]
|
)]
|
||||||
Armoury(ArmouryCommand),
|
Armoury(ArmouryCommand),
|
||||||
|
#[options(name = "backlight", help = "Set screen backlight levels")]
|
||||||
|
Backlight(BacklightCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Options)]
|
#[derive(Debug, Clone, Options)]
|
||||||
@@ -102,3 +104,21 @@ pub struct ArmouryCommand {
|
|||||||
)]
|
)]
|
||||||
pub free: Vec<String>,
|
pub free: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
pub struct BacklightCommand {
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
pub help: bool,
|
||||||
|
#[options(meta = "", help = "Set screen brightness <0-100>")]
|
||||||
|
pub screenpad_brightness: Option<i32>,
|
||||||
|
#[options(
|
||||||
|
meta = "",
|
||||||
|
help = "Set screenpad gamma brightness 0.5 - 2.2, 1.0 == linear"
|
||||||
|
)]
|
||||||
|
pub screenpad_gamma: Option<f32>,
|
||||||
|
#[options(
|
||||||
|
meta = "",
|
||||||
|
help = "Set screenpad brightness to sync with primary display"
|
||||||
|
)]
|
||||||
|
pub sync_screenpad_brightness: Option<bool>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use rog_dbus::list_iface_blocking;
|
|||||||
use rog_dbus::scsi_aura::ScsiAuraProxyBlocking;
|
use rog_dbus::scsi_aura::ScsiAuraProxyBlocking;
|
||||||
use rog_dbus::zbus_anime::AnimeProxyBlocking;
|
use rog_dbus::zbus_anime::AnimeProxyBlocking;
|
||||||
use rog_dbus::zbus_aura::AuraProxyBlocking;
|
use rog_dbus::zbus_aura::AuraProxyBlocking;
|
||||||
|
use rog_dbus::zbus_backlight::BacklightProxyBlocking;
|
||||||
use rog_dbus::zbus_fan_curves::FanCurvesProxyBlocking;
|
use rog_dbus::zbus_fan_curves::FanCurvesProxyBlocking;
|
||||||
use rog_dbus::zbus_platform::PlatformProxyBlocking;
|
use rog_dbus::zbus_platform::PlatformProxyBlocking;
|
||||||
use rog_dbus::zbus_slash::SlashProxyBlocking;
|
use rog_dbus::zbus_slash::SlashProxyBlocking;
|
||||||
@@ -218,6 +219,7 @@ fn do_parsed(
|
|||||||
Some(CliCommand::Slash(cmd)) => handle_slash(cmd)?,
|
Some(CliCommand::Slash(cmd)) => handle_slash(cmd)?,
|
||||||
Some(CliCommand::Scsi(cmd)) => handle_scsi(cmd)?,
|
Some(CliCommand::Scsi(cmd)) => handle_scsi(cmd)?,
|
||||||
Some(CliCommand::Armoury(cmd)) => handle_armoury_command(cmd)?,
|
Some(CliCommand::Armoury(cmd)) => handle_armoury_command(cmd)?,
|
||||||
|
Some(CliCommand::Backlight(cmd)) => handle_backlight(cmd)?,
|
||||||
None => {
|
None => {
|
||||||
if (!parsed.show_supported
|
if (!parsed.show_supported
|
||||||
&& parsed.kbd_bright.is_none()
|
&& parsed.kbd_bright.is_none()
|
||||||
@@ -381,6 +383,46 @@ fn do_gfx() {
|
|||||||
println!("This command will be removed in future");
|
println!("This command will be removed in future");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_backlight(cmd: &BacklightCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if (cmd.screenpad_brightness.is_none()
|
||||||
|
&& cmd.screenpad_gamma.is_none()
|
||||||
|
&& cmd.sync_screenpad_brightness.is_none())
|
||||||
|
|| cmd.help
|
||||||
|
{
|
||||||
|
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||||
|
|
||||||
|
let backlights = find_iface::<BacklightProxyBlocking>("xyz.ljones.Backlight")?;
|
||||||
|
for backlight in backlights {
|
||||||
|
println!("Current screenpad settings:");
|
||||||
|
println!(" Brightness: {}", backlight.screenpad_brightness()?);
|
||||||
|
println!(" Gamma: {}", backlight.screenpad_gamma()?);
|
||||||
|
println!(
|
||||||
|
" Sync with primary: {}",
|
||||||
|
backlight.screenpad_sync_with_primary()?
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let backlights = find_iface::<BacklightProxyBlocking>("xyz.ljones.Backlight")?;
|
||||||
|
for backlight in backlights {
|
||||||
|
if let Some(brightness) = cmd.screenpad_brightness {
|
||||||
|
backlight.set_screenpad_brightness(brightness)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(gamma) = cmd.screenpad_gamma {
|
||||||
|
backlight.set_screenpad_gamma(gamma.to_string().as_str())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(sync) = cmd.sync_screenpad_brightness {
|
||||||
|
backlight.set_screenpad_sync_with_primary(sync)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_anime(cmd: &AnimeCommand) -> Result<(), Box<dyn std::error::Error>> {
|
fn handle_anime(cmd: &AnimeCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if (cmd.command.is_none()
|
if (cmd.command.is_none()
|
||||||
&& cmd.enable_display.is_none()
|
&& cmd.enable_display.is_none()
|
||||||
|
|||||||
254
asusd/src/ctrl_backlight.rs
Normal file
254
asusd/src/ctrl_backlight.rs
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use futures_util::lock::Mutex;
|
||||||
|
use log::{info, warn};
|
||||||
|
use rog_platform::backlight::{Backlight, BacklightType};
|
||||||
|
use zbus::fdo::Error as FdoErr;
|
||||||
|
use zbus::object_server::SignalEmitter;
|
||||||
|
use zbus::{interface, Connection};
|
||||||
|
|
||||||
|
use crate::error::RogError;
|
||||||
|
use crate::ASUS_ZBUS_PATH;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CtrlBacklight {
|
||||||
|
backlights: Vec<Backlight>,
|
||||||
|
sync_all: Arc<Mutex<bool>>,
|
||||||
|
gamma: Arc<Mutex<f32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlBacklight {
|
||||||
|
pub fn new() -> Result<Self, RogError> {
|
||||||
|
let mut backlights = Vec::new();
|
||||||
|
|
||||||
|
if let Ok(primary) = Backlight::new(BacklightType::Primary) {
|
||||||
|
info!("Found primary display backlight");
|
||||||
|
backlights.push(primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(screenpad) = Backlight::new(BacklightType::Screenpad) {
|
||||||
|
info!("Found screenpad backlight");
|
||||||
|
backlights.push(screenpad);
|
||||||
|
}
|
||||||
|
|
||||||
|
if backlights.is_empty() {
|
||||||
|
return Err(RogError::MissingFunction("No backlights found".into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
backlights,
|
||||||
|
sync_all: Arc::new(Mutex::new(true)),
|
||||||
|
gamma: Arc::new(Mutex::new(1.0)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_backlight(&self, device_type: &BacklightType) -> Option<&Backlight> {
|
||||||
|
self.backlights
|
||||||
|
.iter()
|
||||||
|
.find(|b| b.device_type() == device_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_brightness_with_sync(
|
||||||
|
&self,
|
||||||
|
device_type: &BacklightType,
|
||||||
|
level: i32,
|
||||||
|
) -> Result<(), FdoErr> {
|
||||||
|
if let Some(backlight) = self.get_backlight(device_type) {
|
||||||
|
let max = backlight.get_max_brightness().map_err(|e| {
|
||||||
|
warn!("Failed to get max brightness: {}", e);
|
||||||
|
FdoErr::Failed(format!("Failed to get max brightness: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let scaled = if *device_type == BacklightType::Screenpad {
|
||||||
|
// Apply non-linear scaling with the configurable gamma value only for Screenpad
|
||||||
|
let gamma = *self.gamma.lock().await;
|
||||||
|
let normalized_level = level as f32 / 100.0;
|
||||||
|
let gamma_corrected = normalized_level.powf(gamma);
|
||||||
|
(gamma_corrected * max as f32) as i32
|
||||||
|
} else {
|
||||||
|
// Linear scaling for other devices
|
||||||
|
level * max / 100
|
||||||
|
};
|
||||||
|
|
||||||
|
backlight.set_brightness(scaled).map_err(|e| {
|
||||||
|
warn!("Failed to set brightness: {}", e);
|
||||||
|
FdoErr::Failed(format!("Failed to set brightness: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if *self.sync_all.lock().await {
|
||||||
|
for other in self
|
||||||
|
.backlights
|
||||||
|
.iter()
|
||||||
|
.filter(|b| b.device_type() != device_type)
|
||||||
|
{
|
||||||
|
if let Ok(other_max) = other.get_max_brightness() {
|
||||||
|
let other_scaled = if other.device_type() == &BacklightType::Screenpad {
|
||||||
|
// Apply gamma only to Screenpad
|
||||||
|
let gamma = *self.gamma.lock().await;
|
||||||
|
let normalized_level = level as f32 / 100.0;
|
||||||
|
let gamma_corrected = normalized_level.powf(gamma);
|
||||||
|
(gamma_corrected * other_max as f32) as i32
|
||||||
|
} else {
|
||||||
|
// Linear scaling for other devices
|
||||||
|
level * other_max / 100
|
||||||
|
};
|
||||||
|
let _ = other.set_brightness(other_scaled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(FdoErr::NotSupported(format!(
|
||||||
|
"Backlight {:?} not found",
|
||||||
|
device_type
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_brightness_percent(&self, device_type: &BacklightType) -> Result<i32, FdoErr> {
|
||||||
|
if let Some(backlight) = self.get_backlight(device_type) {
|
||||||
|
let brightness = backlight.get_brightness().map_err(|e| {
|
||||||
|
warn!("Failed to get brightness: {}", e);
|
||||||
|
FdoErr::Failed(format!("Failed to get brightness: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let max = backlight.get_max_brightness().map_err(|e| {
|
||||||
|
warn!("Failed to get max brightness: {}", e);
|
||||||
|
FdoErr::Failed(format!("Failed to get max brightness: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok((brightness as u32 * 100 / max as u32) as i32)
|
||||||
|
} else {
|
||||||
|
Err(FdoErr::NotSupported(format!(
|
||||||
|
"Backlight {:?} not found",
|
||||||
|
device_type
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interface(name = "xyz.ljones.Backlight")]
|
||||||
|
impl CtrlBacklight {
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn screenpad_sync_with_primary(&self) -> bool {
|
||||||
|
*self.sync_all.lock().await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_screenpad_sync_with_primary(&self, sync: bool) -> Result<(), zbus::Error> {
|
||||||
|
*self.sync_all.lock().await = sync;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn screenpad_gamma(&self) -> String {
|
||||||
|
(*self.gamma.lock().await).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_screenpad_gamma(&self, value: &str) -> Result<(), zbus::Error> {
|
||||||
|
let gamma: f32 = value
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| FdoErr::Failed("Invalid gamma value, must be a valid number".into()))?;
|
||||||
|
|
||||||
|
if gamma < 0.1 {
|
||||||
|
return Err(FdoErr::Failed("Gamma value must be greater than 0".into()).into());
|
||||||
|
}
|
||||||
|
if gamma > 2.0 {
|
||||||
|
return Err(FdoErr::Failed("Gamma value must be 2.0 or less".into()).into());
|
||||||
|
}
|
||||||
|
*self.gamma.lock().await = gamma;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn primary_brightness(&self) -> Result<i32, FdoErr> {
|
||||||
|
self.get_brightness_percent(&BacklightType::Primary)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_primary_brightness(
|
||||||
|
&self,
|
||||||
|
#[zbus(signal_context)] ctxt: SignalEmitter<'_>,
|
||||||
|
level: i32,
|
||||||
|
) -> Result<(), zbus::Error> {
|
||||||
|
if level > 100 {
|
||||||
|
return Err(FdoErr::Failed("Brightness level must be 0-100".into()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_brightness_with_sync(&BacklightType::Primary, level)
|
||||||
|
.await?;
|
||||||
|
self.primary_brightness_changed(&ctxt).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn screenpad_brightness(&self) -> Result<i32, FdoErr> {
|
||||||
|
self.get_brightness_percent(&BacklightType::Screenpad)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_screenpad_brightness(
|
||||||
|
&self,
|
||||||
|
#[zbus(signal_context)] ctxt: SignalEmitter<'_>,
|
||||||
|
level: i32,
|
||||||
|
) -> Result<(), zbus::Error> {
|
||||||
|
if level > 100 {
|
||||||
|
return Err(FdoErr::Failed("Brightness level must be 0-100".into()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_brightness_with_sync(&BacklightType::Screenpad, level)
|
||||||
|
.await?;
|
||||||
|
self.screenpad_brightness_changed(&ctxt).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn screenpad_power(&self) -> Result<bool, FdoErr> {
|
||||||
|
if let Some(backlight) = self.get_backlight(&BacklightType::Screenpad) {
|
||||||
|
let power = backlight.get_bl_power().map_err(|e| {
|
||||||
|
warn!("Failed to get backlight power: {}", e);
|
||||||
|
FdoErr::Failed(format!("Failed to get backlight power: {}", e))
|
||||||
|
})?;
|
||||||
|
Ok(power == 0)
|
||||||
|
} else {
|
||||||
|
Err(FdoErr::NotSupported("Screenpad backlight not found".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_screenpad_power(
|
||||||
|
&self,
|
||||||
|
#[zbus(signal_context)] ctxt: SignalEmitter<'_>,
|
||||||
|
power: bool,
|
||||||
|
) -> Result<(), zbus::Error> {
|
||||||
|
if let Some(backlight) = self.get_backlight(&BacklightType::Screenpad) {
|
||||||
|
backlight
|
||||||
|
.set_bl_power(if power { 0 } else { 1 })
|
||||||
|
.map_err(|e| {
|
||||||
|
warn!("Failed to set backlight power: {}", e);
|
||||||
|
FdoErr::Failed(format!("Failed to set backlight power: {}", e))
|
||||||
|
})?;
|
||||||
|
self.screenpad_power_changed(&ctxt).await?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(FdoErr::NotSupported("Screenpad backlight not found".into()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::ZbusRun for CtrlBacklight {
|
||||||
|
async fn add_to_server(self, server: &mut Connection) {
|
||||||
|
Self::add_to_server_helper(self, ASUS_ZBUS_PATH, server).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlBacklight {
|
||||||
|
async fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
info!("Reloading backlight settings");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,9 +6,10 @@ use ::zbus::Connection;
|
|||||||
use asusd::asus_armoury::start_attributes_zbus;
|
use asusd::asus_armoury::start_attributes_zbus;
|
||||||
use asusd::aura_manager::DeviceManager;
|
use asusd::aura_manager::DeviceManager;
|
||||||
use asusd::config::Config;
|
use asusd::config::Config;
|
||||||
|
use asusd::ctrl_backlight::CtrlBacklight;
|
||||||
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, ZbusRun, DBUS_NAME};
|
||||||
use config_traits::{StdConfig, StdConfigLoad1};
|
use config_traits::{StdConfig, StdConfigLoad1};
|
||||||
use futures_util::lock::Mutex;
|
use futures_util::lock::Mutex;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
@@ -90,6 +91,15 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match CtrlBacklight::new() {
|
||||||
|
Ok(backlight) => {
|
||||||
|
backlight.add_to_server(&mut server).await;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Backlight: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match CtrlPlatform::new(
|
match CtrlPlatform::new(
|
||||||
platform,
|
platform,
|
||||||
power,
|
power,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#![deny(unused_must_use)]
|
#![deny(unused_must_use)]
|
||||||
/// Configuration loading, saving
|
/// Configuration loading, saving
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod ctrl_backlight;
|
||||||
/// Control platform profiles + fan-curves if available
|
/// Control platform profiles + fan-curves if available
|
||||||
pub mod ctrl_fancurves;
|
pub mod ctrl_fancurves;
|
||||||
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
|
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ pub mod asus_armoury;
|
|||||||
pub mod scsi_aura;
|
pub mod scsi_aura;
|
||||||
pub mod zbus_anime;
|
pub mod zbus_anime;
|
||||||
pub mod zbus_aura;
|
pub mod zbus_aura;
|
||||||
|
pub mod zbus_backlight;
|
||||||
pub mod zbus_fan_curves;
|
pub mod zbus_fan_curves;
|
||||||
pub mod zbus_platform;
|
pub mod zbus_platform;
|
||||||
pub mod zbus_slash;
|
pub mod zbus_slash;
|
||||||
|
|||||||
59
rog-dbus/src/zbus_backlight.rs
Normal file
59
rog-dbus/src/zbus_backlight.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
//! # D-Bus interface proxy for: `xyz.ljones.Backlight`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `5.1.0` from D-Bus introspection
|
||||||
|
//! data. Source: `Interface '/xyz/ljones' from service 'xyz.ljones.Asusd' on
|
||||||
|
//! system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the [Writing a client proxy] section of the
|
||||||
|
//! zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This type implements the [D-Bus standard interfaces],
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus API can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//!
|
||||||
|
//! Consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
//!
|
||||||
|
//! [Writing a client proxy]: https://dbus2.github.io/zbus/client.html
|
||||||
|
//! [D-Bus standard interfaces]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces,
|
||||||
|
use zbus::proxy;
|
||||||
|
#[proxy(
|
||||||
|
interface = "xyz.ljones.Backlight",
|
||||||
|
default_service = "xyz.ljones.Asusd",
|
||||||
|
default_path = "/xyz/ljones"
|
||||||
|
)]
|
||||||
|
pub trait Backlight {
|
||||||
|
/// PrimaryBrightness property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn primary_brightness(&self) -> zbus::Result<i32>;
|
||||||
|
#[zbus(property)]
|
||||||
|
fn set_primary_brightness(&self, value: i32) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// ScreenpadBrightness property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn screenpad_brightness(&self) -> zbus::Result<i32>;
|
||||||
|
#[zbus(property)]
|
||||||
|
fn set_screenpad_brightness(&self, value: i32) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// ScreenpadGamma property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn screenpad_gamma(&self) -> zbus::Result<String>;
|
||||||
|
#[zbus(property)]
|
||||||
|
fn set_screenpad_gamma(&self, value: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// ScreenpadPower property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn screenpad_power(&self) -> zbus::Result<bool>;
|
||||||
|
#[zbus(property)]
|
||||||
|
fn set_screenpad_power(&self, value: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// ScreenpadSyncWithPrimary property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn screenpad_sync_with_primary(&self) -> zbus::Result<bool>;
|
||||||
|
#[zbus(property)]
|
||||||
|
fn set_screenpad_sync_with_primary(&self, value: bool) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
75
rog-platform/src/backlight.rs
Normal file
75
rog-platform/src/backlight.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use log::{info, warn};
|
||||||
|
|
||||||
|
use crate::error::{PlatformError, Result};
|
||||||
|
use crate::{attr_num, to_device};
|
||||||
|
|
||||||
|
/// The "backlight" device provides access to screen brightness control
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
|
||||||
|
pub struct Backlight {
|
||||||
|
path: PathBuf,
|
||||||
|
device_type: BacklightType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
|
||||||
|
pub enum BacklightType {
|
||||||
|
Primary,
|
||||||
|
Screenpad,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backlight {
|
||||||
|
attr_num!("brightness", path, i32);
|
||||||
|
|
||||||
|
attr_num!("max_brightness", path, i32);
|
||||||
|
|
||||||
|
attr_num!("bl_power", path, i32);
|
||||||
|
|
||||||
|
pub fn new(device_type: BacklightType) -> Result<Self> {
|
||||||
|
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
PlatformError::Udev("enumerator failed".into(), err)
|
||||||
|
})?;
|
||||||
|
enumerator.match_subsystem("backlight").map_err(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
for device in enumerator.scan_devices().map_err(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
PlatformError::Udev("scan_devices failed".into(), err)
|
||||||
|
})? {
|
||||||
|
info!("Backlight: Checking {:?}", device.syspath());
|
||||||
|
match device_type {
|
||||||
|
BacklightType::Primary => {
|
||||||
|
if device.sysname().to_string_lossy() == "intel_backlight" {
|
||||||
|
info!("Found primary backlight at {:?}", device.sysname());
|
||||||
|
return Ok(Self {
|
||||||
|
path: device.syspath().to_path_buf(),
|
||||||
|
device_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BacklightType::Screenpad => {
|
||||||
|
let name = device.sysname().to_string_lossy();
|
||||||
|
if name == "asus_screenpad" || name == "asus_screenpad_backlight" {
|
||||||
|
info!("Found screenpad backlight at {:?}", device.sysname());
|
||||||
|
return Ok(Self {
|
||||||
|
path: device.syspath().to_path_buf(),
|
||||||
|
device_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(PlatformError::MissingFunction(format!(
|
||||||
|
"Backlight {:?} not found",
|
||||||
|
device_type
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_type(&self) -> &BacklightType {
|
||||||
|
&self.device_type
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use crate::error::{PlatformError, Result};
|
use crate::error::{PlatformError, Result};
|
||||||
use crate::{attr_u8, has_attr, set_attr_u8_array, to_device};
|
use crate::{attr_num, has_attr, set_attr_u8_array, to_device};
|
||||||
|
|
||||||
/// The sysfs control for backlight levels. This is only for the 3-step
|
/// The sysfs control for backlight levels. This is only for the 3-step
|
||||||
/// backlight setting, and for TUF laptops. It is not a hard requirement
|
/// backlight setting, and for TUF laptops. It is not a hard requirement
|
||||||
@@ -14,7 +14,7 @@ pub struct KeyboardBacklight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardBacklight {
|
impl KeyboardBacklight {
|
||||||
attr_u8!("brightness", path);
|
attr_num!("brightness", path, u8);
|
||||||
|
|
||||||
has_attr!("kbd_rgb_mode" path);
|
has_attr!("kbd_rgb_mode" path);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//! on ROG, Strix, and TUF laptops.
|
//! on ROG, Strix, and TUF laptops.
|
||||||
|
|
||||||
pub mod asus_armoury;
|
pub mod asus_armoury;
|
||||||
|
pub mod backlight;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod hid_raw;
|
pub mod hid_raw;
|
||||||
@@ -55,18 +56,29 @@ pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result<u8> {
|
pub fn read_attr_num<T>(device: &Device, attr_name: &str) -> Result<T>
|
||||||
|
where
|
||||||
|
T: std::str::FromStr,
|
||||||
|
<T as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
|
{
|
||||||
if let Some(value) = device.attribute_value(attr_name) {
|
if let Some(value) = device.attribute_value(attr_name) {
|
||||||
let tmp = value.to_string_lossy();
|
let tmp = value.to_string_lossy();
|
||||||
return tmp.parse::<u8>().map_err(|_e| PlatformError::ParseNum);
|
return tmp.parse::<T>().map_err(|_e| PlatformError::ParseNum);
|
||||||
}
|
}
|
||||||
Err(PlatformError::AttrNotFound(attr_name.to_owned()))
|
Err(PlatformError::AttrNotFound(attr_name.to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_attr_u8(device: &mut Device, attr: &str, value: u8) -> Result<()> {
|
pub fn write_attr_num<T>(device: &mut Device, attr_name: &str, value: T) -> Result<()>
|
||||||
device
|
where
|
||||||
.set_attribute_value(attr, value.to_string())
|
T: std::fmt::Display,
|
||||||
.map_err(|e| PlatformError::IoPath(attr.into(), e))
|
{
|
||||||
|
if device
|
||||||
|
.set_attribute_value(attr_name, format!("{value}"))
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(PlatformError::AttrNotFound(attr_name.to_owned()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result<Vec<u8>> {
|
pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result<Vec<u8>> {
|
||||||
|
|||||||
@@ -74,36 +74,41 @@ macro_rules! attr_bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! get_attr_u8 {
|
macro_rules! get_attr_num {
|
||||||
($(#[$attr:meta])* $attr_name:literal $item:ident) => {
|
($(#[$attr:meta])* $attr_name:literal $item:ident $type:ty) => {
|
||||||
concat_idents::concat_idents!(fn_name = get_, $attr_name {
|
concat_idents::concat_idents!(fn_name = get_, $attr_name {
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
pub fn fn_name(&self) -> Result<u8> {
|
pub fn fn_name(&self) -> Result<$type> {
|
||||||
$crate::read_attr_u8(&to_device(&self.$item)?, $attr_name)
|
$crate::read_attr_num::<$type>(&to_device(&self.$item)?, $attr_name)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
($(#[$attr:meta])* $attr_name:literal $item:ident) => {
|
||||||
|
$crate::get_attr_num!($(#[$attr])* $attr_name $item $type);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Most attributes expect `u8` as a char, so `1` should be written as `b'1'`.
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! set_attr_u8 {
|
macro_rules! set_attr_num {
|
||||||
($(#[$attr:meta])* $attr_name:literal $item:ident) => {
|
($(#[$attr:meta])* $attr_name:literal $item:ident $type:ty) => {
|
||||||
concat_idents::concat_idents!(fn_name = set_, $attr_name {
|
concat_idents::concat_idents!(fn_name = set_, $attr_name {
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
pub fn fn_name(&self, value: u8) -> Result<()> {
|
pub fn fn_name(&self, value: $type) -> Result<()> {
|
||||||
$crate::write_attr_u8(&mut to_device(&self.$item)?, $attr_name, value)
|
$crate::write_attr_num(&mut to_device(&self.$item)?, $attr_name, value as $type)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
($(#[$attr:meta])* $attr_name:literal $item:ident) => {
|
||||||
|
$crate::set_attr_num!($(#[$attr])* $attr_name $item $type);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! attr_u8 {
|
macro_rules! attr_num {
|
||||||
($(#[$attr:meta])* $attr_name:literal, $item:ident) => {
|
($(#[$attr:meta])* $attr_name:literal, $item:ident, $type:ty) => {
|
||||||
$crate::has_attr!($(#[$attr])* $attr_name $item);
|
$crate::has_attr!($(#[$attr])* $attr_name $item);
|
||||||
$crate::get_attr_u8!($(#[$attr])* $attr_name $item);
|
$crate::get_attr_num!($(#[$attr])* $attr_name $item $type);
|
||||||
$crate::set_attr_u8!($(#[$attr])* $attr_name $item);
|
$crate::set_attr_num!($(#[$attr])* $attr_name $item $type);
|
||||||
$crate::watch_attr!($(#[$attr])* $attr_name $item);
|
$crate::watch_attr!($(#[$attr])* $attr_name $item);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use crate::error::{PlatformError, Result};
|
use crate::error::{PlatformError, Result};
|
||||||
use crate::{attr_u8, to_device};
|
use crate::{attr_num, to_device};
|
||||||
|
|
||||||
/// The "platform" device provides access to things like:
|
/// The "platform" device provides access to things like:
|
||||||
/// - `dgpu_disable`
|
/// - `dgpu_disable`
|
||||||
@@ -20,9 +20,9 @@ pub struct AsusPower {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsusPower {
|
impl AsusPower {
|
||||||
attr_u8!("charge_control_end_threshold", battery);
|
attr_num!("charge_control_end_threshold", battery, u8);
|
||||||
|
|
||||||
attr_u8!("online", mains);
|
attr_num!("online", mains, u8);
|
||||||
|
|
||||||
/// When checking for battery this will look in order:
|
/// When checking for battery this will look in order:
|
||||||
/// - if attr `manufacturer` contains `asus`
|
/// - if attr `manufacturer` contains `asus`
|
||||||
|
|||||||
Reference in New Issue
Block a user