Send fan-mode over dbus. Fix multizone dbus command

Closes issue #7
This commit is contained in:
Luke
2020-05-23 14:20:59 +12:00
parent de10fe13e7
commit 46041c0343
9 changed files with 121 additions and 21 deletions

1
Cargo.lock generated
View File

@@ -697,6 +697,7 @@ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"sysfs-class", "sysfs-class",
"thiserror",
"tokio", "tokio",
"toml", "toml",
"uhid-virt", "uhid-virt",

View File

@@ -147,6 +147,12 @@ If the daemon service is enabled then on boot the following will be reloaded fro
The daemon also saves the settings per mode as the keyboard does not do this itself - this means cycling through modes The daemon also saves the settings per mode as the keyboard does not do this itself - this means cycling through modes
with the Aura keys will use the settings that were used via CLI. with the Aura keys will use the settings that were used via CLI.
### DBUS Input
Commands: `FanMode`, `LedWriteBytes`, `LedWriteMultizone`, `LedWriteEffect`
TODO: fill in this info
### Wireshark captures ### Wireshark captures
TODO: see `./wireshark_data/` for some captures. TODO: see `./wireshark_data/` for some captures.

View File

@@ -89,7 +89,7 @@ impl AuraDbusWriter {
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
self.connection.process(Duration::from_micros(300))?; self.connection.process(Duration::from_micros(300))?;
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteEffect")? let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteMultizone")?
.append1(&group[0].to_vec()) .append1(&group[0].to_vec())
.append1(&group[1].to_vec()) .append1(&group[1].to_vec())
.append1(&group[2].to_vec()) .append1(&group[2].to_vec())
@@ -115,6 +115,19 @@ impl AuraDbusWriter {
Err(Box::new(dbus::Error::new_custom("name", "message"))) Err(Box::new(dbus::Error::new_custom("name", "message")))
} }
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
let msg =
Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "FanMode")?.append1(level);
let r = self
.connection
.send_with_reply_and_block(msg, Duration::from_millis(5000))?;
if let Some(reply) = r.get1::<&str>() {
return Ok(reply.to_owned());
}
Err(Box::new(dbus::Error::new_custom("name", "message")))
}
#[inline] #[inline]
pub fn write_builtin_mode( pub fn write_builtin_mode(
&self, &self,

View File

@@ -43,3 +43,5 @@ intel-pstate = "^0.2.1"
# virtualisation of HID, mainly for outputting consumer key codes # virtualisation of HID, mainly for outputting consumer key codes
uhid-virt = "^0.0.4" uhid-virt = "^0.0.4"
#keycode = "0.3" #keycode = "0.3"
thiserror = "^1.0.15"

View File

@@ -19,6 +19,7 @@ use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::sync::Mutex; use tokio::sync::Mutex;
type FanModeType = Arc<Mutex<Option<u8>>>;
type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>; type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>;
type EffectType = Arc<Mutex<Option<Vec<Vec<u8>>>>>; type EffectType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
@@ -81,7 +82,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
let (aura_command_send, aura_command_recv) = mpsc::sync_channel::<AuraCommand>(1); let (aura_command_send, aura_command_recv) = mpsc::sync_channel::<AuraCommand>(1);
let (tree, input, effect, effect_cancel_signal) = dbus_create_tree(); let (tree, input, effect, fan_mode, effect_cancel_signal) = dbus_create_tree();
// We add the tree to the connection so that incoming method calls will be handled. // We add the tree to the connection so that incoming method calls will be handled.
tree.start_receive_send(&*connection); tree.start_receive_send(&*connection);
@@ -97,6 +98,15 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
// start the keyboard reader and laptop-action loop // start the keyboard reader and laptop-action loop
let key_read_handle = tokio::spawn(async move { let key_read_handle = tokio::spawn(async move {
loop { loop {
// Fan mode
if let Ok(mut lock) = fan_mode.try_lock() {
if let Some(n) = lock.take() {
let mut config = config1.lock().await;
rogcore
.fan_mode_set(n, &mut config)
.unwrap_or_else(|err| warn!("{:?}", err));
}
}
let acs = aura_command_send.clone(); let acs = aura_command_send.clone();
let data = keyboard_reader.poll_keyboard().await; let data = keyboard_reader.poll_keyboard().await;
if let Some(bytes) = data { if let Some(bytes) = data {
@@ -227,7 +237,10 @@ fn dbus_create_ledmultizone_method(effect: EffectType) -> Method<MTSync, ()> {
let byte_array: Vec<Vec<u8>> = let byte_array: Vec<Vec<u8>> =
vec![iter.read()?, iter.read()?, iter.read()?, iter.read()?]; vec![iter.read()?, iter.read()?, iter.read()?, iter.read()?];
*lock = Some(byte_array); *lock = Some(byte_array);
let mret = m.msg.method_return().append1(&format!("Got effect part")); let mret = m
.msg
.method_return()
.append1(&"Got effect part".to_string());
Ok(vec![mret]) Ok(vec![mret])
} else { } else {
Err(MethodErr::failed("Could not lock daemon for access")) Err(MethodErr::failed("Could not lock daemon for access"))
@@ -263,14 +276,12 @@ fn dbus_create_ledeffect_method(effect: EffectType) -> Method<MTSync, ()> {
iter.read()?, iter.read()?,
]; ];
*lock = Some(byte_array); *lock = Some(byte_array);
let mret = m.msg.method_return().append1(&format!("Got effect part")); Ok(vec![])
Ok(vec![mret])
} else { } else {
Err(MethodErr::failed("Could not lock daemon for access")) Err(MethodErr::failed("Could not lock daemon for access"))
} }
} }
}) })
.outarg::<&str, _>("reply")
.inarg::<Vec<u8>, _>("bytearray") .inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray") .inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray") .inarg::<Vec<u8>, _>("bytearray")
@@ -284,9 +295,40 @@ fn dbus_create_ledeffect_method(effect: EffectType) -> Method<MTSync, ()> {
.inarg::<Vec<u8>, _>("bytearray") .inarg::<Vec<u8>, _>("bytearray")
} }
fn dbus_create_tree() -> (Tree<MTSync, ()>, LedMsgType, EffectType, Arc<Signal<()>>) { fn dbus_create_fan_mode_method(fan_mode: FanModeType) -> Method<MTSync, ()> {
let factory = Factory::new_sync::<()>();
factory
// method for ledmessage
.method("FanMode", (), {
move |m| {
if let Ok(mut lock) = fan_mode.try_lock() {
let mut iter = m.msg.iter_init();
let byte: u8 = iter.read()?;
*lock = Some(byte);
let mret = m
.msg
.method_return()
.append1(format!("Fan level set to {:?}", FanLevel::from(byte)));
Ok(vec![mret])
} else {
Err(MethodErr::failed("Could not lock daemon for access"))
}
}
})
.outarg::<&str, _>("reply")
.inarg::<u8, _>("byte")
}
fn dbus_create_tree() -> (
Tree<MTSync, ()>,
LedMsgType,
EffectType,
FanModeType,
Arc<Signal<()>>,
) {
let input_bytes: LedMsgType = Arc::new(Mutex::new(None)); let input_bytes: LedMsgType = Arc::new(Mutex::new(None));
let input_effect: EffectType = Arc::new(Mutex::new(None)); let input_effect: EffectType = Arc::new(Mutex::new(None));
let fan_mode: FanModeType = Arc::new(Mutex::new(None));
let factory = Factory::new_sync::<()>(); let factory = Factory::new_sync::<()>();
let effect_cancel_sig = Arc::new(factory.signal("LedCancelEffect", ())); let effect_cancel_sig = Arc::new(factory.signal("LedCancelEffect", ()));
@@ -297,8 +339,9 @@ fn dbus_create_tree() -> (Tree<MTSync, ()>, LedMsgType, EffectType, Arc<Signal<(
.add_m(dbus_create_ledmsg_method(input_bytes.clone())) .add_m(dbus_create_ledmsg_method(input_bytes.clone()))
.add_m(dbus_create_ledmultizone_method(input_effect.clone())) .add_m(dbus_create_ledmultizone_method(input_effect.clone()))
.add_m(dbus_create_ledeffect_method(input_effect.clone())) .add_m(dbus_create_ledeffect_method(input_effect.clone()))
.add_m(dbus_create_fan_mode_method(fan_mode.clone()))
.add_s(effect_cancel_sig.clone()), .add_s(effect_cancel_sig.clone()),
), ),
); );
(tree, input_bytes, input_effect, effect_cancel_sig) (tree, input_bytes, input_effect, fan_mode, effect_cancel_sig)
} }

10
rog-core/src/error.rs Normal file
View File

@@ -0,0 +1,10 @@
use std::fmt::Debug;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum RogError {
#[error("unable to parse string to fan mode")]
ParseFanLevel,
#[error("mode not supported")]
NotSupported,
}

View File

@@ -12,3 +12,5 @@ mod led_control;
pub mod rogcore; pub mod rogcore;
/// A virtual "consumer device" to help emit the correct key codes /// A virtual "consumer device" to help emit the correct key codes
mod virt_device; mod virt_device;
mod error;

View File

@@ -69,7 +69,7 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
writer.write_multizone(&byte_arr)?; writer.write_multizone(&byte_arr)?;
} }
_ => match writer.write_builtin_mode(&command) { _ => match writer.write_builtin_mode(&command) {
Ok(msg) => println!("Response: {}", msg), Ok(msg) => println!("Daemon response: {}", msg),
Err(err) => println!("Error: {}", err), Err(err) => println!("Error: {}", err),
}, },
} }
@@ -77,7 +77,13 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
if let Some(brightness) = parsed.bright { if let Some(brightness) = parsed.bright {
match writer.write_brightness(brightness.level()) { match writer.write_brightness(brightness.level()) {
Ok(msg) => println!("Response: {}", msg), Ok(msg) => println!("Daemon response: {}", msg),
Err(err) => println!("Error: {}", err),
}
}
if let Some(fan_level) = parsed.fan_mode {
match writer.write_fan_mode(fan_level.into()) {
Ok(msg) => println!("Daemon response: {}", msg),
Err(err) => println!("Error: {}", err), Err(err) => println!("Error: {}", err),
} }
} }

View File

@@ -1,6 +1,6 @@
// Return show-stopping errors, otherwise map error to a log level // Return show-stopping errors, otherwise map error to a log level
use crate::{config::Config, virt_device::VirtKeys}; use crate::{config::Config, error::RogError, virt_device::VirtKeys};
use log::{error, info, warn}; use log::{error, info, warn};
use rusb::DeviceHandle; use rusb::DeviceHandle;
use std::error::Error; use std::error::Error;
@@ -10,6 +10,7 @@ use std::marker::{PhantomData, PhantomPinned};
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"; static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
@@ -118,10 +119,21 @@ impl RogCore {
Ok(()) Ok(())
} }
pub fn fan_mode_step(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> { pub fn fan_mode_set(&mut self, n: u8, config: &mut Config) -> Result<(), Box<dyn Error>> {
let path = RogCore::get_fan_path()?; let path = RogCore::get_fan_path()?;
let mut fan_ctrl = OpenOptions::new().read(true).write(true).open(path)?; let mut fan_ctrl = OpenOptions::new().read(true).write(true).open(path)?;
info!("Fan mode set to: {:?}", FanLevel::from(n));
config.fan_mode = n;
fan_ctrl
.write_all(format!("{:?}", config.fan_mode).as_bytes())
.unwrap_or_else(|err| error!("Could not write to {}, {:?}", path, err));
self.set_pstate_for_fan_mode(FanLevel::from(n), config)?;
config.write();
Ok(())
}
pub fn fan_mode_step(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
let mut n = config.fan_mode; let mut n = config.fan_mode;
info!("Current fan mode: {:?}", FanLevel::from(n)); info!("Current fan mode: {:?}", FanLevel::from(n));
// wrap around the step number // wrap around the step number
@@ -130,15 +142,7 @@ impl RogCore {
} else { } else {
n = 0; n = 0;
} }
info!("Fan mode stepped to: {:?}", FanLevel::from(n)); self.fan_mode_set(n, config)
fan_ctrl
.write_all(format!("{:?}", config.fan_mode).as_bytes())
.unwrap_or_else(|err| error!("Could not write to {}, {:?}", path, err));
self.set_pstate_for_fan_mode(FanLevel::from(n), config)?;
config.fan_mode = n;
config.write();
Ok(())
} }
fn set_pstate_for_fan_mode( fn set_pstate_for_fan_mode(
@@ -310,6 +314,19 @@ pub enum FanLevel {
Silent, Silent,
} }
impl FromStr for FanLevel {
type Err = RogError;
fn from_str(s: &str) -> Result<Self, RogError> {
match s.to_lowercase().as_str() {
"normal" => Ok(FanLevel::Normal),
"boost" => Ok(FanLevel::Boost),
"silent" => Ok(FanLevel::Silent),
_ => Err(RogError::ParseFanLevel),
}
}
}
impl From<u8> for FanLevel { impl From<u8> for FanLevel {
fn from(n: u8) -> Self { fn from(n: u8) -> Self {
match n { match n {