Massive refactor of led control

- Write brightness to kernel LED class path

Closes #63, #53
This commit is contained in:
Luke D Jones
2021-03-19 20:16:18 +13:00
parent 53ee6015d0
commit 6528ec95c2
30 changed files with 1131 additions and 964 deletions

View File

@@ -1,6 +1,6 @@
use log::{error, info, warn};
use rog_fan_curve::Curve;
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors};
use rog_types::gfx_vendors::GfxVendors;
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
@@ -10,6 +10,7 @@ use crate::config_old::*;
use crate::VERSION;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Deserialize, Serialize)]
pub struct Config {
@@ -20,9 +21,6 @@ pub struct Config {
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
pub kbd_backlight_modes: Vec<AuraModes>,
pub power_profiles: BTreeMap<String, Profile>,
}
@@ -40,9 +38,6 @@ impl Default for Config {
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
curr_fan_mode: 0,
bat_charge_limit: 100,
kbd_led_brightness: 1,
kbd_backlight_mode: 0,
kbd_backlight_modes: Vec::new(),
power_profiles: pwr,
}
}
@@ -50,7 +45,7 @@ impl Default for Config {
impl Config {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(supported_led_modes: &[u8]) -> Self {
pub fn load() -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
@@ -65,10 +60,15 @@ impl Config {
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return Config::create_default(&mut file, &supported_led_modes);
return Config::create_default(&mut file);
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
} else if let Ok(data) = serde_json::from_str::<ConfigV317>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV301>(&buf) {
let config = data.into_current();
config.write();
@@ -89,17 +89,11 @@ impl Config {
panic!("Please remove {} then restart asusd", CONFIG_PATH);
}
}
Config::create_default(&mut file, &supported_led_modes)
Config::create_default(&mut file)
}
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
// create a default config here
let mut config = Config::default();
for n in supported_led_modes {
config.kbd_backlight_modes.push(AuraModes::from(*n))
}
fn create_default(file: &mut File) -> Self {
let config = Config::default();
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string_pretty(&config).unwrap();
file.write_all(json.as_bytes())
@@ -141,26 +135,6 @@ impl Config {
file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
pub fn set_mode_data(&mut self, mode: AuraModes) {
let byte: u8 = (&mode).into();
for (index, n) in self.kbd_backlight_modes.iter().enumerate() {
if byte == u8::from(n) {
// Consume it, OMNOMNOMNOM
self.kbd_backlight_modes[index] = mode;
break;
}
}
}
pub fn get_led_mode_data(&self, num: u8) -> Option<&AuraModes> {
for mode in &self.kbd_backlight_modes {
if u8::from(mode) == num {
return Some(mode);
}
}
None
}
}
#[derive(Deserialize, Serialize)]

124
daemon/src/config_aura.rs Normal file
View File

@@ -0,0 +1,124 @@
use crate::laptops::LaptopLedData;
use log::{error, warn};
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
#[derive(Deserialize, Serialize)]
pub struct AuraConfig {
pub brightness: u8,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl Default for AuraConfig {
fn default() -> Self {
AuraConfig {
brightness: 1,
current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(),
multizone: None,
}
}
}
impl AuraConfig {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(supported_led_modes: &LaptopLedData) -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&AURA_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
AURA_CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return AuraConfig::create_default(&mut file, &supported_led_modes);
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
}
warn!("Could not deserialise {}", AURA_CONFIG_PATH);
panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH);
}
}
AuraConfig::create_default(&mut file, &supported_led_modes)
}
fn create_default(file: &mut File, support_data: &LaptopLedData) -> Self {
// create a default config here
let mut config = AuraConfig::default();
for n in &support_data.standard {
config
.builtins
.insert(*n, AuraEffect::default_with_mode(*n));
}
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string(&config).unwrap();
file.write_all(json.as_bytes())
.unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH));
config
}
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&AURA_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("File is empty {}", AURA_CONFIG_PATH);
} else {
let x: AuraConfig = serde_json::from_str(&buf)
.unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH));
*self = x;
}
}
}
pub fn write(&self) {
let mut file = File::create(AURA_CONFIG_PATH).expect("Couldn't overwrite config");
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
/// Multipurpose, will accecpt AuraEffect with zones and put in the correct store
pub fn set_builtin(&mut self, effect: AuraEffect) {
match effect.zone() {
AuraZone::None => {
self.builtins.insert(*effect.mode(), effect);
}
_ => {
if let Some(multi) = self.multizone.as_mut() {
multi.set(effect)
}
}
}
}
pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect; 4]> {
if let Some(multi) = &self.multizone {
if aura_type == AuraModeNum::Static {
return Some(multi.static_());
} else if aura_type == AuraModeNum::Breathe {
return Some(multi.breathe());
}
}
None
}
}

View File

@@ -1,10 +1,11 @@
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors};
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::config::{Config, Profile};
/// for parsing old v2.1.2 config
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct ConfigV212 {
gfx_managed: bool,
@@ -15,7 +16,7 @@ pub(crate) struct ConfigV212 {
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraModes>,
kbd_backlight_modes: Vec<AuraEffect>,
}
impl ConfigV212 {
@@ -27,15 +28,13 @@ impl ConfigV212 {
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.power_profile,
bat_charge_limit: self.bat_charge_limit,
kbd_led_brightness: self.kbd_led_brightness,
kbd_backlight_mode: self.kbd_backlight_mode,
kbd_backlight_modes: self.kbd_backlight_modes,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v2.2.2 config
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct ConfigV222 {
gfx_managed: bool,
@@ -46,7 +45,7 @@ pub(crate) struct ConfigV222 {
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraModes>,
kbd_backlight_modes: Vec<AuraEffect>,
}
impl ConfigV222 {
@@ -58,14 +57,12 @@ impl ConfigV222 {
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.power_profile,
bat_charge_limit: self.bat_charge_limit,
kbd_led_brightness: self.kbd_led_brightness,
kbd_backlight_mode: self.kbd_backlight_mode,
kbd_backlight_modes: self.kbd_backlight_modes,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v3.0.1 config
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV301 {
pub gfx_managed: bool,
@@ -78,7 +75,7 @@ pub(crate) struct ConfigV301 {
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
pub kbd_backlight_modes: Vec<AuraModes>,
pub kbd_backlight_modes: Vec<AuraEffect>,
pub power_profiles: BTreeMap<String, Profile>,
}
@@ -91,9 +88,37 @@ impl ConfigV301 {
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit,
kbd_led_brightness: self.kbd_led_brightness,
kbd_backlight_mode: self.kbd_backlight_mode,
kbd_backlight_modes: self.kbd_backlight_modes,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v3.1.7 config
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV317 {
pub gfx_mode: GfxVendors,
pub gfx_managed: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
#[serde(skip)]
pub kbd_backlight_modes: Option<bool>,
pub power_profiles: BTreeMap<String, Profile>,
}
impl ConfigV317 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles,
}
}

View File

@@ -43,7 +43,7 @@ trait Dbus {
impl Dbus for CtrlGraphics {
fn vendor(&self) -> String {
self.get_gfx_mode()
.map(|gfx| gfx.into())
.map(|gfx| (<&str>::from(gfx)).into())
.unwrap_or_else(|err| format!("Get vendor failed: {}", err))
}
@@ -238,7 +238,7 @@ impl CtrlGraphics {
Ok(())
}
fn write_modprobe_conf() -> Result<(), RogError> {
fn write_modprobe_conf(content: &[u8]) -> Result<(), RogError> {
info!("GFX: Writing {}", MODPROBE_PATH);
let mut file = std::fs::OpenOptions::new()
@@ -248,7 +248,7 @@ impl CtrlGraphics {
.open(MODPROBE_PATH)
.map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?;
file.write_all(MODPROBE_BASE)
file.write_all(content)
.and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
@@ -393,7 +393,14 @@ impl CtrlGraphics {
bus: &PciBus,
) -> Result<(), RogError> {
Self::write_xorg_conf(vendor)?;
Self::write_modprobe_conf()?; // TODO: Not required here, should put in startup?
// Write different modprobe to enable boot control to work
match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
Self::write_modprobe_conf(MODPROBE_BASE)?
}
// GfxVendors::Compute => {}
GfxVendors::Integrated => Self::write_modprobe_conf(MODPROBE_INTEGRATED)?,
}
// Rescan before doing remove or add drivers
bus.rescan()
@@ -408,8 +415,6 @@ impl CtrlGraphics {
})?;
}
}
// TODO: compute mode, needs different setup
// GfxVendors::Compute => {}
GfxVendors::Integrated => {
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;

View File

@@ -21,6 +21,15 @@ options nvidia NVreg_DynamicPowerManagement=0x02
options nvidia-drm modeset=1
"#;
static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd
blacklist i2c_nvidia_gpu
blacklist nvidia
blacklist nvidia-drm
blacklist nvidia-modeset
blacklist nouveau
alias nouveau off
"#;
const XORG_FILE: &str = "90-nvidia-primary.conf";
const XORG_PATH: &str = "/etc/X11/xorg.conf.d/";
@@ -29,8 +38,7 @@ Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
Option "AllowEmptyInitialConfiguration"
Option "AllowExternalGpus""#;
Option "AllowEmptyInitialConfiguration" "true""#;
static PRIMARY_GPU_NVIDIA: &[u8] = br#"
Option "PrimaryGPU" "true""#;

View File

@@ -5,15 +5,13 @@ static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
use crate::{
config::Config,
config_aura::AuraConfig,
error::RogError,
laptops::{match_laptop, HELP_ADDRESS},
laptops::{match_laptop, LaptopLedData, HELP_ADDRESS},
};
use log::{error, info, warn};
use rog_types::{
aura_brightness_bytes,
aura_modes::{AuraModes, PER_KEY},
fancy::KeyColourArray,
aura_modes::{AuraEffect, AuraModeNum},
LED_MSG_LEN,
};
use std::fs::OpenOptions;
@@ -29,7 +27,8 @@ use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct LedSupportedFunctions {
pub brightness_set: bool,
pub stock_led_modes: Option<Vec<u8>>,
pub stock_led_modes: Option<Vec<AuraModeNum>>,
pub multizone_led_mode: bool,
pub per_key_led_mode: bool,
}
@@ -39,21 +38,20 @@ impl GetSupported for CtrlKbdBacklight {
fn get_supported() -> Self::A {
// let mode = <&str>::from(&<AuraModes>::from(*mode));
let mut stock_led_modes = None;
let mut per_key_led_mode = false;
let multizone_led_mode = false;
let per_key_led_mode = false;
if let Some(laptop) = match_laptop() {
let modes = laptop.supported_modes().to_vec();
if modes.contains(&PER_KEY) {
per_key_led_mode = true;
let modes = modes.iter().filter(|x| **x != PER_KEY).copied().collect();
stock_led_modes = Some(modes);
stock_led_modes = if laptop.supported_modes().standard.is_empty() {
None
} else {
stock_led_modes = Some(modes);
}
Some(laptop.supported_modes().standard.clone())
};
}
LedSupportedFunctions {
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
stock_led_modes,
multizone_led_mode,
per_key_led_mode,
}
}
@@ -64,9 +62,9 @@ pub struct CtrlKbdBacklight {
#[allow(dead_code)]
kbd_node: Option<String>,
pub bright_node: String,
supported_modes: Vec<u8>,
supported_modes: LaptopLedData,
flip_effect_write: bool,
config: Arc<Mutex<Config>>,
config: AuraConfig,
}
pub struct DbusKbdBacklight {
@@ -96,48 +94,42 @@ impl crate::ZbusAdd for DbusKbdBacklight {
}
}
/// The main interface for changing, reading, or notfying signals
///
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusKbdBacklight {
fn set_led_mode(&mut self, data: String) {
if let Ok(data) = serde_json::from_str(&data) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
match &data {
AuraModes::PerKey(_) => {
ctrl.do_command(data, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
}
_ => {
if let Ok(json) = serde_json::to_string(&data) {
match ctrl.do_command(data, &mut cfg) {
Ok(_) => {
self.notify_led(&json).ok();
}
Err(err) => {
warn!("{}", err);
}
}
}
}
}
fn set_brightness(&mut self, brightness: u8) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_brightness(brightness)
.map_err(|err| warn!("{}", err))
.ok();
}
}
fn set_led_mode(&mut self, effect: AuraEffect) {
if let Ok(mut ctrl) = self.inner.try_lock() {
let mode_name = effect.mode_name();
match ctrl.do_command(effect) {
Ok(_) => {
self.notify_led(&mode_name).ok();
}
Err(err) => {
warn!("{}", err);
}
}
} else {
warn!("SetKeyBacklight could not deserialise");
}
}
fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.toggle_mode(false, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
ctrl.toggle_mode(false)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
@@ -145,40 +137,24 @@ impl DbusKbdBacklight {
fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.toggle_mode(true, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
ctrl.toggle_mode(true)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
/// Return the current mode data
#[dbus_interface(property)]
fn led_mode(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
return json;
}
}
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
if let Ok(json) = serde_json::to_string(&cfg.kbd_backlight_modes) {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
return json;
}
}
@@ -187,14 +163,25 @@ impl DbusKbdBacklight {
"SetKeyBacklight could not deserialise".to_string()
}
/// Return the current LED brightness
fn led_brightness(&self) -> i8 {
/// Return a list of available modes
#[dbus_interface(property)]
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
return cfg.kbd_led_brightness as i8;
if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
return json;
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not serialise".to_string()
}
/// Return the current LED brightness
#[dbus_interface(property)]
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.inner.try_lock() {
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
}
warn!("SetKeyBacklight could not serialise");
-1
}
@@ -205,44 +192,40 @@ impl DbusKbdBacklight {
impl crate::Reloadable for CtrlKbdBacklight {
fn reload(&mut self) -> Result<(), RogError> {
// set current mode (if any)
if let Ok(mut config) = self.config.clone().try_lock() {
if self.supported_modes.len() > 1 {
if self.supported_modes.contains(&config.kbd_backlight_mode) {
let mode = config
.get_led_mode_data(config.kbd_backlight_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
} else {
warn!(
"An unsupported mode was set: {}, reset to first mode available",
<&str>::from(&<AuraModes>::from(config.kbd_backlight_mode))
);
for (idx, mode) in config.kbd_backlight_modes.iter_mut().enumerate() {
if !self.supported_modes.contains(&mode.into()) {
config.kbd_backlight_modes.remove(idx);
config.write();
break;
}
}
config.kbd_backlight_mode = self.supported_modes[0];
// TODO: do a recursive call with a boxed dyn future later
let mode = config
.get_led_mode_data(config.kbd_backlight_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
}
if self.supported_modes.standard.len() > 1 {
let current_mode = self.config.current_mode;
if self.supported_modes.standard.contains(&(current_mode)) {
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
} else {
warn!(
"An unsupported mode was set: {}, reset to first mode available",
<&str>::from(&self.config.current_mode)
);
self.config.builtins.remove(&current_mode);
self.config.current_mode = AuraModeNum::Static;
// TODO: do a recursive call with a boxed dyn future later
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
}
// Reload brightness
let bright = config.kbd_led_brightness;
let bytes = aura_brightness_bytes(bright);
self.write_bytes(&bytes)?;
info!("Reloaded last used brightness");
}
// Reload brightness
let bright = self.config.brightness;
self.set_brightness(bright)?;
info!("Reloaded last used brightness");
Ok(())
}
}
@@ -262,12 +245,10 @@ impl crate::CtrlTask for CtrlKbdBacklight {
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if let Ok(mut config) = self.config.clone().try_lock() {
if config.kbd_led_brightness != num as u8 {
config.read();
config.kbd_led_brightness = num as u8;
config.write();
}
if self.config.brightness != num as u8 {
self.config.read();
self.config.brightness = num as u8;
self.config.write();
}
return Ok(());
}
@@ -280,8 +261,8 @@ impl CtrlKbdBacklight {
pub fn new(
id_product: &str,
condev_iface: Option<&String>,
supported_modes: Vec<u8>,
config: Arc<Mutex<Config>>,
supported_modes: LaptopLedData,
config: AuraConfig,
) -> Result<Self, RogError> {
// TODO: return error if *all* nodes are None
let led_node = Self::get_node_failover(id_product, None, Self::scan_led_node).map_or_else(
@@ -334,6 +315,37 @@ impl CtrlKbdBacklight {
}
}
pub fn get_brightness(&self) -> Result<u8, RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(buf[0])
}
pub fn set_brightness(&self, brightness: u8) -> Result<(), RogError> {
let mut file = OpenOptions::new()
.write(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
file.write_all(&[brightness])
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(())
}
fn get_node_failover(
id_product: &str,
iface: Option<&String>,
@@ -432,8 +444,8 @@ impl CtrlKbdBacklight {
))
}
pub fn do_command(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> {
self.set_and_save(mode, config)
pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> {
self.set_and_save(mode)
}
/// Should only be used if the bytes you are writing are verified correct
@@ -470,100 +482,61 @@ impl CtrlKbdBacklight {
///
/// This needs to be universal so that settings applied by dbus stick
#[inline]
fn set_and_save(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> {
match mode {
AuraModes::LedBrightness(n) => {
let bytes: [u8; LED_MSG_LEN] = (&mode).into();
self.write_bytes(&bytes)?;
config.read();
config.kbd_led_brightness = n;
config.write();
info!("LED brightness set to {:#?}", n);
}
AuraModes::PerKey(v) => {
if v.is_empty() || v[0].is_empty() {
let bytes = KeyColourArray::get_init_msg();
self.write_bytes(&bytes)?;
} else {
self.write_effect(&v)?;
}
}
_ => {
config.read();
let mode_num: u8 = u8::from(&mode);
self.write_mode(&mode)?;
config.kbd_backlight_mode = mode_num;
config.set_mode_data(mode);
config.write();
}
}
fn set_and_save(&mut self, mode: AuraEffect) -> Result<(), RogError> {
self.config.read();
self.write_mode(&mode)?;
self.config.current_mode = *mode.mode();
self.config.set_builtin(mode);
self.config.write();
Ok(())
}
#[inline]
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> {
let current = config.kbd_backlight_mode;
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) {
fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> {
let current = self.config.current_mode;
if let Some(idx) = self
.supported_modes
.standard
.iter()
.position(|v| *v == current)
{
let mut idx = idx;
// goes past end of array
if reverse {
if idx == 0 {
idx = self.supported_modes.len() - 1;
idx = self.supported_modes.standard.len() - 1;
} else {
idx -= 1;
}
} else {
idx += 1;
if idx == self.supported_modes.len() {
if idx == self.supported_modes.standard.len() {
idx = 0;
}
}
let next = self.supported_modes[idx];
let next = self.supported_modes.standard[idx];
config.read();
if let Some(data) = config.get_led_mode_data(next) {
self.config.read();
if let Some(data) = self.config.builtins.get(&next) {
self.write_mode(&data)?;
config.kbd_backlight_mode = next;
self.config.current_mode = next;
}
config.write();
self.config.write();
}
Ok(())
}
#[inline]
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
let mode_num: u8 = u8::from(mode);
if !self.supported_modes.contains(&mode_num) {
fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> {
if !self.supported_modes.standard.contains(&mode.mode()) {
return Err(RogError::NotSupported);
}
match mode {
AuraModes::PerKey(v) => {
if v.is_empty() || v[0].is_empty() {
let bytes = KeyColourArray::get_init_msg();
self.write_bytes(&bytes)?;
} else {
self.write_effect(v)?;
}
}
AuraModes::MultiStatic(_) | AuraModes::MultiBreathe(_) => {
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
for array in bytes.iter() {
self.write_bytes(array)?;
}
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
return Ok(());
}
_ => {
let bytes: [u8; LED_MSG_LEN] = mode.into();
self.write_bytes(&bytes)?;
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
}
}
let bytes: [u8; LED_MSG_LEN] = mode.into();
self.write_bytes(&bytes)?;
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
Ok(())
}
}

View File

@@ -1,10 +1,10 @@
use daemon::ctrl_charge::CtrlCharge;
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::laptops::match_laptop;
use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
};
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
use daemon::{CtrlTask, Reloadable, ZbusAdd};
@@ -50,12 +50,9 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
print_board_info();
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
let laptop = match_laptop();
let config = if let Some(laptop) = laptop.as_ref() {
Config::load(laptop.supported_modes())
} else {
Config::load(&[])
};
let config = Config::load();
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
let connection = Connection::new_system()?;
fdo::DBusProxy::new(&connection)?
@@ -64,9 +61,6 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
supported.add_to_server(&mut object_server);
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
match CtrlRogBios::new(config.clone()) {
Ok(mut ctrl) => {
// Do a reload of any settings
@@ -133,7 +127,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
// Collect tasks for task thread
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
if let Ok(mut ctrl) = CtrlFanAndCPU::new(config.clone()).map_err(|err| {
if let Ok(mut ctrl) = CtrlFanAndCPU::new(config).map_err(|err| {
error!("Profile control: {}", err);
}) {
ctrl.reload()
@@ -142,12 +136,14 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
};
if let Some(laptop) = laptop {
if let Some(laptop) = match_laptop() {
let aura_config = AuraConfig::load(laptop.supported_modes());
if let Ok(ctrl) = CtrlKbdBacklight::new(
laptop.usb_product(),
laptop.condev_iface(),
laptop.supported_modes().to_owned(),
config,
aura_config,
)
.map_err(|err| {
error!("Keyboard control: {}", err);

View File

@@ -1,20 +1,19 @@
use log::{info, warn};
use rog_types::aura_modes::{AuraModes, BREATHING, STATIC};
use rog_types::aura_modes::AuraModeNum;
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Read;
pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
static LAPTOP_DEVICES: [u16; 4] = [0x1866, 0x1869, 0x1854, 0x19b6];
/// A helper of sorts specifically for functions tied to laptop models
#[derive(Debug)]
pub struct LaptopBase {
usb_product: String,
condev_iface: Option<String>, // required for finding the Consumer Device interface
supported_modes: Vec<u8>,
led_support: LaptopLedData,
}
impl LaptopBase {
@@ -24,8 +23,8 @@ impl LaptopBase {
pub fn condev_iface(&self) -> Option<&String> {
self.condev_iface.as_ref()
}
pub fn supported_modes(&self) -> &[u8] {
&self.supported_modes
pub fn supported_modes(&self) -> &LaptopLedData {
&self.led_support
}
}
@@ -38,10 +37,7 @@ pub fn match_laptop() -> Option<LaptopBase> {
let prod_str = format!("{:x?}", device_desc.product_id());
if device_desc.product_id() == 0x1854 {
let mut laptop = laptop(prod_str, None);
if laptop.supported_modes.is_empty() {
laptop.supported_modes = vec![STATIC, BREATHING];
}
let laptop = laptop(prod_str, None);
return Some(laptop);
}
@@ -65,12 +61,18 @@ fn laptop(prod: String, condev_iface: Option<String>) -> LaptopBase {
let mut laptop = LaptopBase {
usb_product: prod,
condev_iface,
supported_modes: vec![],
led_support: LaptopLedData {
board_names: vec![],
prod_family: String::new(),
standard: vec![],
multizone: false,
per_key: false,
},
};
if let Some(modes) = LEDModeGroup::load_from_config() {
if let Some(modes) = LedSupportFile::load_from_config() {
if let Some(led_modes) = modes.matcher(&prod_family, &board_name) {
laptop.supported_modes = led_modes;
laptop.led_support = led_modes;
return laptop;
}
}
@@ -92,7 +94,7 @@ pub fn print_modes(supported_modes: &[u8]) {
if !supported_modes.is_empty() {
info!("Supported Keyboard LED modes are:");
for mode in supported_modes {
let mode = <&str>::from(&<AuraModes>::from(*mode));
let mode = <&str>::from(&<AuraModeNum>::from(*mode));
info!("- {}", mode);
}
info!(
@@ -105,19 +107,28 @@ pub fn print_modes(supported_modes: &[u8]) {
}
#[derive(Debug, Deserialize, Serialize)]
struct LEDModeGroup {
led_modes: Vec<LEDModes>,
struct LedSupportFile {
led_data: Vec<LaptopLedData>,
}
impl LEDModeGroup {
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LaptopLedData {
pub prod_family: String,
pub board_names: Vec<String>,
pub standard: Vec<AuraModeNum>,
pub multizone: bool,
pub per_key: bool,
}
impl LedSupportFile {
/// Consumes the LEDModes
fn matcher(self, prod_family: &str, board_name: &str) -> Option<Vec<u8>> {
for led_modes in self.led_modes {
if prod_family.contains(&led_modes.prod_family) {
for board in led_modes.board_names {
if board_name.contains(&board) {
info!("Matched to {} {}", led_modes.prod_family, board);
return Some(led_modes.led_modes);
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
for config in self.led_data {
if prod_family.contains(&config.prod_family) {
for board in &config.board_names {
if board_name.contains(board) {
info!("Matched to {} {}", config.prod_family, board);
return Some(config);
}
}
}
@@ -142,10 +153,3 @@ impl LEDModeGroup {
None
}
}
#[derive(Debug, Deserialize, Serialize)]
struct LEDModes {
prod_family: String,
board_names: Vec<String>,
led_modes: Vec<u8>,
}

View File

@@ -1,6 +1,7 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub mod config_aura;
pub(crate) mod config_old;
/// Control of AniMe matrix display
pub mod ctrl_anime;