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_derive",
"sysfs-class",
"thiserror",
"tokio",
"toml",
"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
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
TODO: see `./wireshark_data/` for some captures.

View File

@@ -89,7 +89,7 @@ impl AuraDbusWriter {
) -> Result<(), Box<dyn Error>> {
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[1].to_vec())
.append1(&group[2].to_vec())
@@ -115,6 +115,19 @@ impl AuraDbusWriter {
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]
pub fn write_builtin_mode(
&self,

View File

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

View File

@@ -19,6 +19,7 @@ use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use tokio::sync::Mutex;
type FanModeType = Arc<Mutex<Option<u8>>>;
type LedMsgType = Arc<Mutex<Option<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 (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.
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
let key_read_handle = tokio::spawn(async move {
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 data = keyboard_reader.poll_keyboard().await;
if let Some(bytes) = data {
@@ -227,7 +237,10 @@ fn dbus_create_ledmultizone_method(effect: EffectType) -> Method<MTSync, ()> {
let byte_array: Vec<Vec<u8>> =
vec![iter.read()?, iter.read()?, iter.read()?, iter.read()?];
*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])
} else {
Err(MethodErr::failed("Could not lock daemon for access"))
@@ -263,14 +276,12 @@ fn dbus_create_ledeffect_method(effect: EffectType) -> Method<MTSync, ()> {
iter.read()?,
];
*lock = Some(byte_array);
let mret = m.msg.method_return().append1(&format!("Got effect part"));
Ok(vec![mret])
Ok(vec![])
} else {
Err(MethodErr::failed("Could not lock daemon for access"))
}
}
})
.outarg::<&str, _>("reply")
.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")
}
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_effect: EffectType = Arc::new(Mutex::new(None));
let fan_mode: FanModeType = Arc::new(Mutex::new(None));
let factory = Factory::new_sync::<()>();
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_ledmultizone_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()),
),
);
(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;
/// A virtual "consumer device" to help emit the correct key codes
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)?;
}
_ => match writer.write_builtin_mode(&command) {
Ok(msg) => println!("Response: {}", msg),
Ok(msg) => println!("Daemon response: {}", msg),
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 {
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),
}
}

View File

@@ -1,6 +1,6 @@
// 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 rusb::DeviceHandle;
use std::error::Error;
@@ -10,6 +10,7 @@ use std::marker::{PhantomData, PhantomPinned};
use std::path::Path;
use std::process::Command;
use std::ptr::NonNull;
use std::str::FromStr;
use std::time::Duration;
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
@@ -118,10 +119,21 @@ impl RogCore {
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 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;
info!("Current fan mode: {:?}", FanLevel::from(n));
// wrap around the step number
@@ -130,15 +142,7 @@ impl RogCore {
} else {
n = 0;
}
info!("Fan mode stepped to: {:?}", FanLevel::from(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.fan_mode = n;
config.write();
Ok(())
self.fan_mode_set(n, config)
}
fn set_pstate_for_fan_mode(
@@ -310,6 +314,19 @@ pub enum FanLevel {
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 {
fn from(n: u8) -> Self {
match n {