mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Allow configuration of intel pstates paired with fan-modes
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -667,7 +667,7 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rog-aura"
|
name = "rog-aura"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dbus",
|
"dbus",
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
@@ -678,7 +678,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rog-daemon"
|
name = "rog-daemon"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dbus",
|
"dbus",
|
||||||
"dbus-tokio",
|
"dbus-tokio",
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ $ sudo systemctl start rog-core.service
|
|||||||
$ sudo systemctl enable rog-core.service
|
$ sudo systemctl enable rog-core.service
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
Occasionally I might break things for you by tweaking or changing the config file layout. Usually this will mean you need to remove `/etc/rog-core.toml' and restart the daemon to create a new one. You *can* back up the old one and copy settings back over (then restart daemon again).
|
||||||
|
|
||||||
## Use
|
## Use
|
||||||
|
|
||||||
Running the program as a daemon manually will require root. Standard (non-daemon) mode expects to be communicating with the daemon mode over dbus.
|
Running the program as a daemon manually will require root. Standard (non-daemon) mode expects to be communicating with the daemon mode over dbus.
|
||||||
@@ -116,7 +120,9 @@ Bus 001 Device 005: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|||||||
|
|
||||||
Then do `sudo lsusb -vd 0b05:1866 > ~/laptop_info` and give that to me.
|
Then do `sudo lsusb -vd 0b05:1866 > ~/laptop_info` and give that to me.
|
||||||
|
|
||||||
Also required:
|
Other helpful info can be gained from `sudo usbhid-dump`, for which you may need to unload kernel drivers. Please google this.
|
||||||
|
|
||||||
|
Also required (for my book-keeping of data):
|
||||||
- `cat /sys/class/dmi/id/product_name`
|
- `cat /sys/class/dmi/id/product_name`
|
||||||
- `cat /sys/class/dmi/id/product_family`
|
- `cat /sys/class/dmi/id/product_family`
|
||||||
- `cat /sys/class/dmi/id/board_name`
|
- `cat /sys/class/dmi/id/board_name`
|
||||||
|
|||||||
@@ -3,6 +3,33 @@ use gumdrop::Options;
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Debug, Options)]
|
||||||
|
pub struct LedBrightness {
|
||||||
|
level: u8,
|
||||||
|
}
|
||||||
|
impl LedBrightness {
|
||||||
|
pub fn level(&self) -> u8 {
|
||||||
|
self.level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromStr for LedBrightness {
|
||||||
|
type Err = AuraError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let s = s.to_lowercase();
|
||||||
|
match s.as_str() {
|
||||||
|
"off" => Ok(LedBrightness { level: 0x00 }),
|
||||||
|
"low" => Ok(LedBrightness { level: 0x01 }),
|
||||||
|
"med" => Ok(LedBrightness { level: 0x02 }),
|
||||||
|
"high" => Ok(LedBrightness { level: 0x03 }),
|
||||||
|
_ => {
|
||||||
|
println!("Missing required argument, must be one of:\noff,low,med,high\n");
|
||||||
|
Err(AuraError::ParseBrightness)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Colour(pub u8, pub u8, pub u8);
|
pub struct Colour(pub u8, pub u8, pub u8);
|
||||||
impl Default for Colour {
|
impl Default for Colour {
|
||||||
|
|||||||
@@ -11,10 +11,13 @@ pub struct Config {
|
|||||||
pub brightness: u8,
|
pub brightness: u8,
|
||||||
pub current_mode: [u8; 4],
|
pub current_mode: [u8; 4],
|
||||||
pub builtin_modes: BuiltInModeBytes,
|
pub builtin_modes: BuiltInModeBytes,
|
||||||
|
pub mode_performance: FanModeSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn read(mut self) -> Self {
|
/// `load` will attempt to read the config, but if it is not found it
|
||||||
|
/// will create a new default config and write that out.
|
||||||
|
pub fn load(mut self) -> Self {
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
@@ -33,12 +36,30 @@ impl Config {
|
|||||||
.expect("Writing default config failed");
|
.expect("Writing default config failed");
|
||||||
self = c;
|
self = c;
|
||||||
} else {
|
} else {
|
||||||
self = toml::from_str(&buf).unwrap();
|
self =
|
||||||
|
toml::from_str(&buf).expect(&format!("Could not deserialise {}", CONFIG_PATH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self) {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&CONFIG_PATH)
|
||||||
|
.expect("config file error");
|
||||||
|
let mut buf = String::new();
|
||||||
|
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||||
|
if l == 0 {
|
||||||
|
panic!("Missing {}", CONFIG_PATH);
|
||||||
|
} else {
|
||||||
|
let x: Config =
|
||||||
|
toml::from_str(&buf).expect(&format!("Could not deserialise {}", CONFIG_PATH));
|
||||||
|
*self = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write(&self) {
|
pub fn write(&self) {
|
||||||
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
||||||
let toml = toml::to_string(self).expect("Parse config to JSON failed");
|
let toml = toml::to_string(self).expect("Parse config to JSON failed");
|
||||||
@@ -55,3 +76,27 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
|
pub struct FanModeSettings {
|
||||||
|
pub normal: IntelPState,
|
||||||
|
pub boost: IntelPState,
|
||||||
|
pub silent: IntelPState,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct IntelPState {
|
||||||
|
pub min_percentage: u8,
|
||||||
|
pub max_percentage: u8,
|
||||||
|
pub no_turbo: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IntelPState {
|
||||||
|
fn default() -> Self {
|
||||||
|
IntelPState {
|
||||||
|
min_percentage: 0,
|
||||||
|
max_percentage: 100,
|
||||||
|
no_turbo: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,18 +37,14 @@ static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode
|
|||||||
/// - `LED_INIT4`
|
/// - `LED_INIT4`
|
||||||
/// - `LED_INIT2`
|
/// - `LED_INIT2`
|
||||||
/// - `LED_INIT4`
|
/// - `LED_INIT4`
|
||||||
pub(crate) struct RogCore {
|
pub struct RogCore {
|
||||||
handle: DeviceHandle<rusb::GlobalContext>,
|
handle: DeviceHandle<rusb::GlobalContext>,
|
||||||
virt_keys: VirtKeys,
|
virt_keys: VirtKeys,
|
||||||
_pin: PhantomPinned,
|
_pin: PhantomPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RogCore {
|
impl RogCore {
|
||||||
pub(crate) fn new(
|
pub fn new(vendor: u16, product: u16, led_endpoint: u8) -> Result<RogCore, Box<dyn Error>> {
|
||||||
vendor: u16,
|
|
||||||
product: u16,
|
|
||||||
led_endpoint: u8,
|
|
||||||
) -> Result<RogCore, Box<dyn Error>> {
|
|
||||||
let mut dev_handle = RogCore::get_device(vendor, product)?;
|
let mut dev_handle = RogCore::get_device(vendor, product)?;
|
||||||
dev_handle.set_active_configuration(0).unwrap_or(());
|
dev_handle.set_active_configuration(0).unwrap_or(());
|
||||||
|
|
||||||
@@ -81,16 +77,7 @@ impl RogCore {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn reload(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
pub async fn reload(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
||||||
// let mode_curr = self.config.current_mode[3];
|
|
||||||
// let mode = self
|
|
||||||
// .config
|
|
||||||
// .builtin_modes
|
|
||||||
// .get_field_from(BuiltInModeByte::from(mode_curr).into())
|
|
||||||
// .unwrap()
|
|
||||||
// .to_owned();
|
|
||||||
// self.aura_write_messages(&[&mode])?;
|
|
||||||
|
|
||||||
let path = if Path::new(FAN_TYPE_1_PATH).exists() {
|
let path = if Path::new(FAN_TYPE_1_PATH).exists() {
|
||||||
FAN_TYPE_1_PATH
|
FAN_TYPE_1_PATH
|
||||||
} else if Path::new(FAN_TYPE_2_PATH).exists() {
|
} else if Path::new(FAN_TYPE_2_PATH).exists() {
|
||||||
@@ -101,12 +88,12 @@ impl RogCore {
|
|||||||
|
|
||||||
let mut file = OpenOptions::new().write(true).open(path)?;
|
let mut file = OpenOptions::new().write(true).open(path)?;
|
||||||
file.write_all(format!("{:?}\n", config.fan_mode).as_bytes())?;
|
file.write_all(format!("{:?}\n", config.fan_mode).as_bytes())?;
|
||||||
self.set_pstate_for_fan_mode(FanLevel::from(config.fan_mode))?;
|
self.set_pstate_for_fan_mode(FanLevel::from(config.fan_mode), config)?;
|
||||||
info!("Reloaded last saved settings");
|
info!("Reloaded last saved settings");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn virt_keys(&mut self) -> &mut VirtKeys {
|
pub fn virt_keys(&mut self) -> &mut VirtKeys {
|
||||||
&mut self.virt_keys
|
&mut self.virt_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +110,7 @@ impl RogCore {
|
|||||||
Err(rusb::Error::NoDevice)
|
Err(rusb::Error::NoDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fan_mode_step(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
pub fn fan_mode_step(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
||||||
let path = if Path::new(FAN_TYPE_1_PATH).exists() {
|
let path = if Path::new(FAN_TYPE_1_PATH).exists() {
|
||||||
FAN_TYPE_1_PATH
|
FAN_TYPE_1_PATH
|
||||||
} else if Path::new(FAN_TYPE_2_PATH).exists() {
|
} else if Path::new(FAN_TYPE_2_PATH).exists() {
|
||||||
@@ -146,34 +133,55 @@ impl RogCore {
|
|||||||
}
|
}
|
||||||
info!("Fan mode stepped to: {:#?}", FanLevel::from(n));
|
info!("Fan mode stepped to: {:#?}", FanLevel::from(n));
|
||||||
fan_ctrl.write_all(format!("{:?}\n", n).as_bytes())?;
|
fan_ctrl.write_all(format!("{:?}\n", n).as_bytes())?;
|
||||||
self.set_pstate_for_fan_mode(FanLevel::from(n))?;
|
self.set_pstate_for_fan_mode(FanLevel::from(n), config)?;
|
||||||
config.fan_mode = n;
|
config.fan_mode = n;
|
||||||
config.write();
|
config.write();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pstate_for_fan_mode(&self, mode: FanLevel) -> Result<(), Box<dyn Error>> {
|
fn set_pstate_for_fan_mode(
|
||||||
|
&self,
|
||||||
|
mode: FanLevel,
|
||||||
|
config: &mut Config,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
// Set CPU pstate
|
// Set CPU pstate
|
||||||
if let Ok(pstate) = intel_pstate::PState::new() {
|
if let Ok(pstate) = intel_pstate::PState::new() {
|
||||||
|
// re-read the config here in case a user changed the pstate settings
|
||||||
|
config.read();
|
||||||
match mode {
|
match mode {
|
||||||
FanLevel::Normal => {
|
FanLevel::Normal => {
|
||||||
pstate.set_min_perf_pct(0)?;
|
pstate.set_min_perf_pct(config.mode_performance.normal.min_percentage)?;
|
||||||
pstate.set_max_perf_pct(100)?;
|
pstate.set_max_perf_pct(config.mode_performance.normal.max_percentage)?;
|
||||||
pstate.set_no_turbo(false)?;
|
pstate.set_no_turbo(config.mode_performance.normal.no_turbo)?;
|
||||||
info!("CPU pstate: normal");
|
info!(
|
||||||
|
"CPU Power: min-freq: {:?}, max-freq: {:?}, turbo: {:?}",
|
||||||
|
config.mode_performance.normal.min_percentage,
|
||||||
|
config.mode_performance.normal.max_percentage,
|
||||||
|
!config.mode_performance.normal.no_turbo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
FanLevel::Boost => {
|
FanLevel::Boost => {
|
||||||
pstate.set_min_perf_pct(50)?;
|
pstate.set_min_perf_pct(config.mode_performance.boost.min_percentage)?;
|
||||||
pstate.set_max_perf_pct(100)?;
|
pstate.set_max_perf_pct(config.mode_performance.boost.max_percentage)?;
|
||||||
pstate.set_no_turbo(false)?;
|
pstate.set_no_turbo(config.mode_performance.boost.no_turbo)?;
|
||||||
info!("CPU pstate: boost");
|
info!(
|
||||||
|
"CPU Power: min-freq: {:?}, max-freq: {:?}, turbo: {:?}",
|
||||||
|
config.mode_performance.boost.min_percentage,
|
||||||
|
config.mode_performance.boost.max_percentage,
|
||||||
|
!config.mode_performance.boost.no_turbo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
FanLevel::Silent => {
|
FanLevel::Silent => {
|
||||||
pstate.set_min_perf_pct(0)?;
|
pstate.set_min_perf_pct(config.mode_performance.silent.min_percentage)?;
|
||||||
pstate.set_max_perf_pct(70)?;
|
pstate.set_max_perf_pct(config.mode_performance.silent.max_percentage)?;
|
||||||
pstate.set_no_turbo(true)?;
|
pstate.set_no_turbo(config.mode_performance.silent.no_turbo)?;
|
||||||
info!("CPU pstate: silent, no-turbo");
|
info!(
|
||||||
|
"CPU Power: min-freq: {:?}, max-freq: {:?}, turbo: {:?}",
|
||||||
|
config.mode_performance.silent.min_percentage,
|
||||||
|
config.mode_performance.silent.max_percentage,
|
||||||
|
!config.mode_performance.silent.no_turbo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +192,7 @@ impl RogCore {
|
|||||||
///
|
///
|
||||||
/// This avoids desktop environments being required to handle it
|
/// This avoids desktop environments being required to handle it
|
||||||
/// (which means it works while in a TTY also)
|
/// (which means it works while in a TTY also)
|
||||||
pub(crate) fn suspend_with_systemd(&self) {
|
pub fn suspend_with_systemd(&self) {
|
||||||
std::process::Command::new("systemctl")
|
std::process::Command::new("systemctl")
|
||||||
.arg("suspend")
|
.arg("suspend")
|
||||||
.spawn()
|
.spawn()
|
||||||
@@ -195,7 +203,7 @@ impl RogCore {
|
|||||||
///
|
///
|
||||||
/// This avoids desktop environments being required to handle it (which
|
/// This avoids desktop environments being required to handle it (which
|
||||||
/// means it works while in a TTY also)
|
/// means it works while in a TTY also)
|
||||||
pub(crate) fn toggle_airplane_mode(&self) {
|
pub fn toggle_airplane_mode(&self) {
|
||||||
match Command::new("rfkill").arg("list").output() {
|
match Command::new("rfkill").arg("list").output() {
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
@@ -230,7 +238,7 @@ impl RogCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_raw_device_handle(&mut self) -> NonNull<DeviceHandle<rusb::GlobalContext>> {
|
pub fn get_raw_device_handle(&mut self) -> NonNull<DeviceHandle<rusb::GlobalContext>> {
|
||||||
// Breaking every damn lifetime guarantee rust gives us
|
// Breaking every damn lifetime guarantee rust gives us
|
||||||
unsafe {
|
unsafe {
|
||||||
NonNull::new_unchecked(&mut self.handle as *mut DeviceHandle<rusb::GlobalContext>)
|
NonNull::new_unchecked(&mut self.handle as *mut DeviceHandle<rusb::GlobalContext>)
|
||||||
@@ -239,7 +247,7 @@ impl RogCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lifetime is tied to `DeviceHandle` from `RogCore`
|
/// Lifetime is tied to `DeviceHandle` from `RogCore`
|
||||||
pub(crate) struct KeyboardReader<'d, C: 'd>
|
pub struct KeyboardReader<'d, C: 'd>
|
||||||
where
|
where
|
||||||
C: rusb::UsbContext,
|
C: rusb::UsbContext,
|
||||||
{
|
{
|
||||||
@@ -271,7 +279,7 @@ where
|
|||||||
///
|
///
|
||||||
/// `report_filter_bytes` is used to filter the data read from the interupt so
|
/// `report_filter_bytes` is used to filter the data read from the interupt so
|
||||||
/// only the relevant byte array is returned.
|
/// only the relevant byte array is returned.
|
||||||
pub(crate) async fn poll_keyboard(&self) -> Option<[u8; 32]> {
|
pub async fn poll_keyboard(&self) -> Option<[u8; 32]> {
|
||||||
let mut buf = [0u8; 32];
|
let mut buf = [0u8; 32];
|
||||||
match unsafe { self.handle.as_ref() }.read_interrupt(
|
match unsafe { self.handle.as_ref() }.read_interrupt(
|
||||||
self.endpoint,
|
self.endpoint,
|
||||||
@@ -299,7 +307,7 @@ where
|
|||||||
/// Because we're holding a pointer to something that *may* go out of scope while the
|
/// Because we're holding a pointer to something that *may* go out of scope while the
|
||||||
/// pointer is held. We're relying on access to struct to be behind a Mutex, and for behaviour
|
/// pointer is held. We're relying on access to struct to be behind a Mutex, and for behaviour
|
||||||
/// that may cause invalididated pointer to cause the program to panic rather than continue.
|
/// that may cause invalididated pointer to cause the program to panic rather than continue.
|
||||||
pub(crate) struct LedWriter<'d, C: 'd>
|
pub struct LedWriter<'d, C: 'd>
|
||||||
where
|
where
|
||||||
C: rusb::UsbContext,
|
C: rusb::UsbContext,
|
||||||
{
|
{
|
||||||
@@ -326,7 +334,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn aura_write(&mut self, message: &[u8]) -> Result<(), AuraError> {
|
/// Should only be used if the bytes you are writing are verified correct
|
||||||
|
pub async fn aura_write(&mut self, message: &[u8]) -> Result<(), AuraError> {
|
||||||
match unsafe { self.handle.as_ref() }.write_interrupt(
|
match unsafe { self.handle.as_ref() }.write_interrupt(
|
||||||
self.led_endpoint,
|
self.led_endpoint,
|
||||||
message,
|
message,
|
||||||
@@ -384,7 +393,8 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn aura_set_and_save(
|
/// Used to set a builtin mode and save the settings for it
|
||||||
|
pub async fn aura_set_and_save(
|
||||||
&mut self,
|
&mut self,
|
||||||
supported_modes: &[BuiltInModeByte],
|
supported_modes: &[BuiltInModeByte],
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
@@ -405,7 +415,7 @@ where
|
|||||||
Err(AuraError::NotSupported)
|
Err(AuraError::NotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn aura_bright_inc(
|
pub async fn aura_bright_inc(
|
||||||
&mut self,
|
&mut self,
|
||||||
supported_modes: &[BuiltInModeByte],
|
supported_modes: &[BuiltInModeByte],
|
||||||
max_bright: u8,
|
max_bright: u8,
|
||||||
@@ -423,7 +433,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn aura_bright_dec(
|
pub async fn aura_bright_dec(
|
||||||
&mut self,
|
&mut self,
|
||||||
supported_modes: &[BuiltInModeByte],
|
supported_modes: &[BuiltInModeByte],
|
||||||
min_bright: u8,
|
min_bright: u8,
|
||||||
@@ -444,7 +454,7 @@ where
|
|||||||
/// Select next Aura effect
|
/// Select next Aura effect
|
||||||
///
|
///
|
||||||
/// If the current effect is the last one then the effect selected wraps around to the first.
|
/// If the current effect is the last one then the effect selected wraps around to the first.
|
||||||
pub(crate) async fn aura_mode_next(
|
pub async fn aura_mode_next(
|
||||||
&mut self,
|
&mut self,
|
||||||
supported_modes: &[BuiltInModeByte],
|
supported_modes: &[BuiltInModeByte],
|
||||||
config: &mut Config,
|
config: &mut Config,
|
||||||
@@ -471,7 +481,7 @@ where
|
|||||||
/// Select previous Aura effect
|
/// Select previous Aura effect
|
||||||
///
|
///
|
||||||
/// If the current effect is the first one then the effect selected wraps around to the last.
|
/// If the current effect is the first one then the effect selected wraps around to the last.
|
||||||
pub(crate) async fn aura_mode_prev(
|
pub async fn aura_mode_prev(
|
||||||
&mut self,
|
&mut self,
|
||||||
supported_modes: &[BuiltInModeByte],
|
supported_modes: &[BuiltInModeByte],
|
||||||
config: &mut Config,
|
config: &mut Config,
|
||||||
@@ -496,33 +506,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Options)]
|
|
||||||
pub struct LedBrightness {
|
|
||||||
level: u8,
|
|
||||||
}
|
|
||||||
impl LedBrightness {
|
|
||||||
pub fn level(&self) -> u8 {
|
|
||||||
self.level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromStr for LedBrightness {
|
|
||||||
type Err = AuraError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let s = s.to_lowercase();
|
|
||||||
match s.as_str() {
|
|
||||||
"off" => Ok(LedBrightness { level: 0x00 }),
|
|
||||||
"low" => Ok(LedBrightness { level: 0x01 }),
|
|
||||||
"med" => Ok(LedBrightness { level: 0x02 }),
|
|
||||||
"high" => Ok(LedBrightness { level: 0x03 }),
|
|
||||||
_ => {
|
|
||||||
println!("Missing required argument, must be one of:\noff,low,med,high\n");
|
|
||||||
Err(AuraError::ParseBrightness)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum FanLevel {
|
enum FanLevel {
|
||||||
Normal,
|
Normal,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use dbus::{
|
|||||||
};
|
};
|
||||||
use dbus_tokio::connection;
|
use dbus_tokio::connection;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_aura::{DBUS_IFACE, DBUS_PATH};
|
use rog_aura::{BuiltInModeByte, DBUS_IFACE, DBUS_PATH};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
@@ -25,7 +25,8 @@ type EffectType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
|
|||||||
// DBUS processing takes 6ms if not tokiod
|
// DBUS processing takes 6ms if not tokiod
|
||||||
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
let laptop = match_laptop();
|
let laptop = match_laptop();
|
||||||
let mut config = Config::default().read();
|
let mut config = Config::default().load();
|
||||||
|
info!("Config loaded");
|
||||||
|
|
||||||
let mut rogcore = RogCore::new(
|
let mut rogcore = RogCore::new(
|
||||||
laptop.usb_vendor(),
|
laptop.usb_vendor(),
|
||||||
@@ -42,14 +43,22 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
daemon
|
daemon
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reload settings
|
// Reload settings
|
||||||
rogcore.reload(&mut config).await?;
|
rogcore.reload(&mut config).await?;
|
||||||
|
let mut led_writer = LedWriter::new(rogcore.get_raw_device_handle(), laptop.led_endpoint());
|
||||||
|
{
|
||||||
|
let mode_curr = config.current_mode[3];
|
||||||
|
let mode = config
|
||||||
|
.builtin_modes
|
||||||
|
.get_field_from(BuiltInModeByte::from(mode_curr).into())
|
||||||
|
.unwrap()
|
||||||
|
.to_owned();
|
||||||
|
led_writer.aura_write(&mode).await?;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the mutexes
|
// Set up the mutexes
|
||||||
let led_writer = Arc::new(Mutex::new(LedWriter::new(
|
let led_writer = Arc::new(Mutex::new(led_writer));
|
||||||
rogcore.get_raw_device_handle(),
|
|
||||||
laptop.led_endpoint(),
|
|
||||||
)));
|
|
||||||
let config = Arc::new(Mutex::new(config));
|
let config = Arc::new(Mutex::new(config));
|
||||||
let (resource, connection) = connection::new_system_sync()?;
|
let (resource, connection) = connection::new_system_sync()?;
|
||||||
tokio::spawn(async {
|
tokio::spawn(async {
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ impl LaptopBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum GX502Keys {
|
pub enum GX502Keys {
|
||||||
Rog = 0x38,
|
Rog = 0x38,
|
||||||
MicToggle = 0x7C,
|
MicToggle = 0x7C,
|
||||||
Fan = 0xAE,
|
Fan = 0xAE,
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
/// Configuration loading, saving
|
||||||
mod config;
|
mod config;
|
||||||
/// The core module which allows writing to LEDs or polling the
|
/// The core module which allows writing to LEDs or polling the
|
||||||
/// laptop keyboard attached devices
|
/// laptop keyboard attached devices
|
||||||
pub mod core;
|
mod core;
|
||||||
|
/// Start the daemon loop
|
||||||
pub mod daemon;
|
pub mod daemon;
|
||||||
pub mod laptops;
|
/// Laptop matching to determine capabilities
|
||||||
|
mod laptops;
|
||||||
|
/// A virtual "consumer device" to help emit the correct key codes
|
||||||
mod virt_device;
|
mod virt_device;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
use daemon::{core::LedBrightness, daemon::start_daemon};
|
use daemon::daemon::start_daemon;
|
||||||
use env_logger::{Builder, Target};
|
use env_logger::{Builder, Target};
|
||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use rog_aura::{cli_options::SetAuraBuiltin, AuraDbusWriter, LED_MSG_LEN};
|
use rog_aura::{
|
||||||
|
cli_options::{LedBrightness, SetAuraBuiltin},
|
||||||
|
AuraDbusWriter, LED_MSG_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
static VERSION: &'static str = "0.8.0";
|
static VERSION: &'static str = "0.8.0";
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ use uhid_virt::{Bus, CreateParams, UHIDDevice};
|
|||||||
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]); // Sleep`
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]); // Sleep`
|
||||||
///
|
///
|
||||||
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]); // Power (menu)`
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]); // Power (menu)`
|
||||||
pub(crate) struct VirtKeys {
|
pub struct VirtKeys {
|
||||||
device: UHIDDevice<std::fs::File>,
|
device: UHIDDevice<std::fs::File>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtKeys {
|
impl VirtKeys {
|
||||||
pub(crate) fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
VirtKeys {
|
VirtKeys {
|
||||||
device: UHIDDevice::create(CreateParams {
|
device: UHIDDevice::create(CreateParams {
|
||||||
name: String::from("Virtual ROG buttons"),
|
name: String::from("Virtual ROG buttons"),
|
||||||
@@ -96,7 +96,7 @@ impl VirtKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A single on/off key press
|
/// A single on/off key press
|
||||||
pub(crate) fn press(&mut self, input: [u8; 32]) {
|
pub fn press(&mut self, input: [u8; 32]) {
|
||||||
self.device.write(&input).unwrap();
|
self.device.write(&input).unwrap();
|
||||||
let mut reset = [0u8; 32];
|
let mut reset = [0u8; 32];
|
||||||
reset[0] = input[0];
|
reset[0] = input[0];
|
||||||
@@ -106,7 +106,7 @@ impl VirtKeys {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum ConsumerKeys {
|
pub enum ConsumerKeys {
|
||||||
Power = 0x30,
|
Power = 0x30,
|
||||||
Sleep = 0x32,
|
Sleep = 0x32,
|
||||||
Menu = 0x0040,
|
Menu = 0x0040,
|
||||||
|
|||||||
Reference in New Issue
Block a user