mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-01-22 17:33:19 +01:00
Refactor dbus commands and internal data structures
This commit is contained in:
@@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Changed
|
||||
- Dbus command LedWriteBytes renamed to SetKeyBacklight
|
||||
- Dbus signal LedCancelEffect renamed to KeyBacklightChanged
|
||||
- Dbus command SetKeyBacklight will now take a JSON string instead of an array of bytes
|
||||
- Config file is now in JSON format, and will store only the LED modes that a laptop
|
||||
supports rather than the whole set
|
||||
|
||||
## [0.12.2] - 2020-29-06
|
||||
### Changed
|
||||
|
||||
35
Cargo.lock
generated
35
Cargo.lock
generated
@@ -419,6 +419,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
@@ -736,6 +742,7 @@ dependencies = [
|
||||
"gumdrop",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tinybmp",
|
||||
"yansi-term",
|
||||
@@ -755,10 +762,10 @@ dependencies = [
|
||||
"rusb",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sysfs-class",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml",
|
||||
"uhid-virt",
|
||||
]
|
||||
|
||||
@@ -799,6 +806,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "0.1.2"
|
||||
@@ -837,6 +850,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "0.1.1"
|
||||
@@ -1011,15 +1035,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uhid-virt"
|
||||
version = "0.0.4"
|
||||
|
||||
2
Makefile
2
Makefile
@@ -54,6 +54,6 @@ vendor:
|
||||
|
||||
target/release/$(BIN): $(SRC)
|
||||
ifeq ($(VENDORED),1)
|
||||
tar pxf vendor.tar.xz
|
||||
tar pxf vendor_rog-core_<version>.tar.xz
|
||||
endif
|
||||
cargo build $(ARGS)
|
||||
|
||||
@@ -1,32 +1,149 @@
|
||||
fan_mode = 0
|
||||
brightness = 1
|
||||
current_mode = [93, 179, 0, 0]
|
||||
|
||||
[builtin_modes]
|
||||
stable = [93, 179, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
breathe = [93, 179, 0, 1, 255, 0, 0, 235, 0, 0, 255, 0, 0, 0, 0, 0, 0]
|
||||
strobe = [93, 179, 0, 2, 0, 0, 0, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
rainbow = [93, 179, 0, 3, 0, 0, 0, 225, 2, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
star = [93, 179, 0, 4, 255, 255, 255, 225, 0, 255, 0, 0, 0, 0, 0, 0, 0]
|
||||
rain = [93, 179, 0, 5, 0, 0, 0, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
highlight = [93, 179, 0, 6, 255, 0, 0, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
laser = [93, 179, 0, 7, 255, 0, 0, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
ripple = [93, 179, 0, 8, 255, 0, 0, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
pulse = [93, 179, 0, 10, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
comet = [93, 179, 0, 11, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
flash = [93, 179, 0, 12, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
multi_static = [[93, 179, 1, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [93, 179, 2, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [93, 179, 3, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [93, 179, 4, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
|
||||
[mode_performance.normal]
|
||||
min_percentage = 0
|
||||
max_percentage = 100
|
||||
no_turbo = false
|
||||
|
||||
[mode_performance.boost]
|
||||
min_percentage = 0
|
||||
max_percentage = 100
|
||||
no_turbo = false
|
||||
|
||||
[mode_performance.silent]
|
||||
min_percentage = 0
|
||||
max_percentage = 100
|
||||
no_turbo = true
|
||||
{
|
||||
"fan_mode": 1,
|
||||
"bat_charge_limit": 100,
|
||||
"brightness": 1,
|
||||
"current_mode": 0,
|
||||
"builtin_modes": [
|
||||
{
|
||||
"Stable": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Breathe": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"colour2": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Strobe": {
|
||||
"help": false,
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Rainbow": {
|
||||
"help": false,
|
||||
"direction": "Up",
|
||||
"speed": "Low"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Star": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"colour2": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Rain": {
|
||||
"help": false,
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Highlight": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Laser": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Ripple": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"speed": "Med"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Pulse": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Comet": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Flash": {
|
||||
"help": false,
|
||||
"colour": [
|
||||
255,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"mode_performance": {
|
||||
"normal": {
|
||||
"min_percentage": 0,
|
||||
"max_percentage": 100,
|
||||
"no_turbo": false
|
||||
},
|
||||
"boost": {
|
||||
"min_percentage": 0,
|
||||
"max_percentage": 100,
|
||||
"no_turbo": false
|
||||
},
|
||||
"silent": {
|
||||
"min_percentage": 0,
|
||||
"max_percentage": 80,
|
||||
"no_turbo": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ gumdrop = "^0.8.0"
|
||||
dbus = { version = "^0.8.2" }
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
thiserror = "^1.0.15"
|
||||
yansi-term = "0.1.2"
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use rog_client::{AniMeDbusWriter, AniMeMatrix, AniMePacketType, HEIGHT, WIDTH};
|
||||
use rog_client::anime_dbus::AniMeDbusWriter;
|
||||
use rog_client::anime_matrix::{AniMeMatrix, AniMePacketType, HEIGHT, WIDTH};
|
||||
use tinybmp::{Bmp, Pixel};
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use rog_client::{AuraDbusWriter, GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||
use rog_client::{
|
||||
core_dbus::AuraDbusWriter,
|
||||
fancy::{GX502Layout, Key, KeyColourArray, KeyLayout},
|
||||
};
|
||||
use std::collections::LinkedList;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use rog_client::{AuraDbusWriter, GX502Layout, KeyColourArray, KeyLayout};
|
||||
use rog_client::{
|
||||
core_dbus::AuraDbusWriter,
|
||||
fancy::{GX502Layout, KeyColourArray, KeyLayout},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut writer = AuraDbusWriter::new()?;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use rog_client::{AuraDbusWriter, GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||
use rog_client::{
|
||||
core_dbus::AuraDbusWriter,
|
||||
fancy::{GX502Layout, Key, KeyColourArray, KeyLayout},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut writer = AuraDbusWriter::new()?;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use rog_client::{AuraDbusWriter, Key, KeyColourArray};
|
||||
use rog_client::{
|
||||
core_dbus::AuraDbusWriter,
|
||||
fancy::{Key, KeyColourArray},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut writer = AuraDbusWriter::new()?;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use rog_client::{AuraDbusWriter, GX502Layout, KeyColourArray, KeyLayout};
|
||||
use rog_client::{
|
||||
core_dbus::AuraDbusWriter,
|
||||
fancy::{GX502Layout, KeyColourArray, KeyLayout},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut writer = AuraDbusWriter::new()?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::anime_matrix::AniMePacketType;
|
||||
use crate::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
||||
use dbus::channel::Sender;
|
||||
use dbus::{blocking::Connection, Message};
|
||||
use std::error::Error;
|
||||
@@ -153,7 +153,7 @@ impl From<AniMeMatrix> for AniMePacketType {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{AniMeMatrix, AniMePacketType};
|
||||
use crate::anime_matrix::{AniMeMatrix, AniMePacketType};
|
||||
|
||||
#[test]
|
||||
fn check_data_alignment() {
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
use super::*;
|
||||
use dbus::blocking::BlockingSender;
|
||||
use dbus::channel::Sender;
|
||||
use dbus::{blocking::Connection, Message};
|
||||
use std::error::Error;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
/// Simplified way to write a effect block
|
||||
pub struct AuraDbusWriter {
|
||||
connection: Box<Connection>,
|
||||
block_time: u64,
|
||||
stop: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl AuraDbusWriter {
|
||||
#[inline]
|
||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
||||
let connection = Connection::new_system()?;
|
||||
Ok(AuraDbusWriter {
|
||||
connection: Box::new(connection),
|
||||
block_time: 33333,
|
||||
stop: Arc::new(AtomicBool::new(false)),
|
||||
})
|
||||
}
|
||||
|
||||
/// This method must always be called before the very first write to initialise
|
||||
/// the keyboard LED EC in the correct mode
|
||||
#[inline]
|
||||
pub fn init_effect(&self) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let match_rule = dbus::message::MatchRule::new_signal(DBUS_IFACE, "LedCancelEffect");
|
||||
let stopper = self.stop.clone();
|
||||
self.connection
|
||||
.add_match(match_rule, move |_: (), _, msg| {
|
||||
println!("GOT {:?}", msg);
|
||||
if let Ok(stop) = msg.read1::<bool>() {
|
||||
if stop {
|
||||
stopper.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
true
|
||||
})?;
|
||||
|
||||
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteBytes")?
|
||||
.append1(KeyColourArray::get_init_msg());
|
||||
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")))
|
||||
}
|
||||
|
||||
/// Write a single colour block.
|
||||
///
|
||||
/// Intentionally blocks for 10ms after sending to allow the block to
|
||||
/// be written to the keyboard EC. This should not be async.
|
||||
#[inline]
|
||||
pub fn write_colour_block(
|
||||
&mut self,
|
||||
key_colour_array: &KeyColourArray,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let group = key_colour_array.get();
|
||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteEffect")?
|
||||
.append3(&group[0].to_vec(), &group[1].to_vec(), &group[2].to_vec())
|
||||
.append3(&group[3].to_vec(), &group[4].to_vec(), &group[5].to_vec())
|
||||
.append3(&group[6].to_vec(), &group[7].to_vec(), &group[8].to_vec())
|
||||
.append2(&group[9].to_vec(), &group[10].to_vec());
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
thread::sleep(Duration::from_micros(self.block_time));
|
||||
if self.stop.load(Ordering::Relaxed) {
|
||||
panic!("Got signal to stop!");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_multizone(
|
||||
&mut self,
|
||||
group: &[[u8; LED_MSG_LEN]; 4],
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut 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())
|
||||
.append1(&group[3].to_vec());
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_bytes(&self, bytes: &[u8]) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteBytes")?
|
||||
.append1(bytes.to_vec());
|
||||
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_fan_mode(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetFanMode")?
|
||||
.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_charge_limit(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetChargeLimit")?
|
||||
.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,
|
||||
mode: &SetAuraBuiltin,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let bytes = <[u8; LED_MSG_LEN]>::from(mode);
|
||||
self.write_bytes(&bytes)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_brightness(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
|
||||
self.write_bytes(&aura_brightness_bytes(level))
|
||||
}
|
||||
}
|
||||
107
rog-client/src/aura_modes.rs
Normal file
107
rog-client/src/aura_modes.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use crate::cli_options::*;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
pub const SINGLE: u8 = 0x00;
|
||||
pub const BREATHING: u8 = 0x01;
|
||||
pub const STROBE: u8 = 0x02;
|
||||
pub const RAINBOW: u8 = 0x03;
|
||||
pub const STAR: u8 = 0x04;
|
||||
pub const RAIN: u8 = 0x05;
|
||||
pub const HIGHLIGHT: u8 = 0x06;
|
||||
pub const LASER: u8 = 0x07;
|
||||
pub const RIPPLE: u8 = 0x08;
|
||||
pub const PULSE: u8 = 0x0a;
|
||||
pub const COMET: u8 = 0x0b;
|
||||
pub const FLASH: u8 = 0x0c;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum AuraModes {
|
||||
Stable(SingleColour),
|
||||
Breathe(TwoColourSpeed),
|
||||
Strobe(SingleSpeed),
|
||||
Rainbow(SingleSpeedDirection),
|
||||
Star(TwoColourSpeed),
|
||||
Rain(SingleSpeed),
|
||||
Highlight(SingleColourSpeed),
|
||||
Laser(SingleColourSpeed),
|
||||
Ripple(SingleColourSpeed),
|
||||
Pulse(SingleColour),
|
||||
Comet(SingleColour),
|
||||
Flash(SingleColour),
|
||||
MultiStatic(MultiColour),
|
||||
LedBrightness(u8),
|
||||
Aura,
|
||||
}
|
||||
|
||||
impl From<SetAuraBuiltin> for AuraModes {
|
||||
fn from(mode: SetAuraBuiltin) -> Self {
|
||||
match mode {
|
||||
SetAuraBuiltin::Stable(x) => AuraModes::Stable(x),
|
||||
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x),
|
||||
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x),
|
||||
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x),
|
||||
SetAuraBuiltin::Star(x) => AuraModes::Star(x),
|
||||
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x),
|
||||
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x),
|
||||
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x),
|
||||
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x),
|
||||
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x),
|
||||
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x),
|
||||
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x),
|
||||
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuraModes> for u8 {
|
||||
fn from(mode: AuraModes) -> Self {
|
||||
u8::from(&mode)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mut AuraModes> for u8 {
|
||||
fn from(mode: &mut AuraModes) -> Self {
|
||||
u8::from(&*mode)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AuraModes> for u8 {
|
||||
fn from(mode: &AuraModes) -> Self {
|
||||
match mode {
|
||||
AuraModes::Stable(_) => 0x00,
|
||||
AuraModes::Breathe(_) => 0x01,
|
||||
AuraModes::Strobe(_) => 0x02,
|
||||
AuraModes::Rainbow(_) => 0x03,
|
||||
AuraModes::Star(_) => 0x04,
|
||||
AuraModes::Rain(_) => 0x05,
|
||||
AuraModes::Highlight(_) => 0x06,
|
||||
AuraModes::Laser(_) => 0x07,
|
||||
AuraModes::Ripple(_) => 0x08,
|
||||
AuraModes::Pulse(_) => 0x0a,
|
||||
AuraModes::Comet(_) => 0x0b,
|
||||
AuraModes::Flash(_) => 0x0c,
|
||||
AuraModes::MultiStatic(_) => 0x0d,
|
||||
_ => panic!("Invalid mode"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for AuraModes {
|
||||
fn from(byte: u8) -> Self {
|
||||
match byte {
|
||||
SINGLE => AuraModes::Stable(SingleColour::default()),
|
||||
BREATHING => AuraModes::Breathe(TwoColourSpeed::default()),
|
||||
STROBE => AuraModes::Strobe(SingleSpeed::default()),
|
||||
RAINBOW => AuraModes::Rainbow(SingleSpeedDirection::default()),
|
||||
STAR => AuraModes::Star(TwoColourSpeed::default()),
|
||||
RAIN => AuraModes::Rain(SingleSpeed::default()),
|
||||
HIGHLIGHT => AuraModes::Highlight(SingleColourSpeed::default()),
|
||||
LASER => AuraModes::Laser(SingleColourSpeed::default()),
|
||||
RIPPLE => AuraModes::Ripple(SingleColourSpeed::default()),
|
||||
PULSE => AuraModes::Pulse(SingleColour::default()),
|
||||
COMET => AuraModes::Comet(SingleColour::default()),
|
||||
FLASH => AuraModes::Flash(SingleColour::default()),
|
||||
_ => panic!("Invalid mode byte"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
use super::cli_options::*;
|
||||
use super::LED_MSG_LEN;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
/// Container for the byte strings used in modes. Generally useful for settings
|
||||
/// and other usecases.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct BuiltInModeBytes {
|
||||
pub stable: [u8; LED_MSG_LEN],
|
||||
pub breathe: [u8; LED_MSG_LEN],
|
||||
pub strobe: [u8; LED_MSG_LEN],
|
||||
pub rainbow: [u8; LED_MSG_LEN],
|
||||
pub star: [u8; LED_MSG_LEN],
|
||||
pub rain: [u8; LED_MSG_LEN],
|
||||
pub highlight: [u8; LED_MSG_LEN],
|
||||
pub laser: [u8; LED_MSG_LEN],
|
||||
pub ripple: [u8; LED_MSG_LEN],
|
||||
pub pulse: [u8; LED_MSG_LEN],
|
||||
pub comet: [u8; LED_MSG_LEN],
|
||||
pub flash: [u8; LED_MSG_LEN],
|
||||
pub multi_static: [[u8; LED_MSG_LEN]; 4],
|
||||
}
|
||||
impl BuiltInModeBytes {
|
||||
#[inline]
|
||||
pub fn set_field_from(&mut self, bytes: &[u8]) {
|
||||
if bytes[0] == 0x5d && bytes[1] == 0xb3 {
|
||||
let b = BuiltInModeByte::from(bytes[3]);
|
||||
match b {
|
||||
BuiltInModeByte::Single => self.stable.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Breathing => self.breathe.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Strobe => self.strobe.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Rainbow => self.rainbow.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Star => self.star.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Rain => self.rain.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Highlight => self.highlight.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Laser => self.laser.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Ripple => self.ripple.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Pulse => self.pulse.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Comet => self.comet.copy_from_slice(bytes),
|
||||
BuiltInModeByte::Flash => self.flash.copy_from_slice(bytes),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_field_from(&self, byte: u8) -> Option<&[u8]> {
|
||||
let bytes = match BuiltInModeByte::from(byte) {
|
||||
BuiltInModeByte::Single => &self.stable,
|
||||
BuiltInModeByte::Breathing => &self.breathe,
|
||||
BuiltInModeByte::Strobe => &self.strobe,
|
||||
BuiltInModeByte::Rainbow => &self.rainbow,
|
||||
BuiltInModeByte::Star => &self.star,
|
||||
BuiltInModeByte::Rain => &self.rain,
|
||||
BuiltInModeByte::Highlight => &self.highlight,
|
||||
BuiltInModeByte::Laser => &self.laser,
|
||||
BuiltInModeByte::Ripple => &self.ripple,
|
||||
BuiltInModeByte::Pulse => &self.pulse,
|
||||
BuiltInModeByte::Comet => &self.comet,
|
||||
BuiltInModeByte::Flash => &self.flash,
|
||||
_ => return None,
|
||||
};
|
||||
Some(bytes)
|
||||
}
|
||||
}
|
||||
impl Default for BuiltInModeBytes {
|
||||
fn default() -> Self {
|
||||
BuiltInModeBytes {
|
||||
stable: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Stable(SingleColour::default())),
|
||||
breathe: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Breathe(TwoColourSpeed::default())),
|
||||
strobe: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Strobe(SingleSpeed::default())),
|
||||
rainbow: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Rainbow(
|
||||
SingleSpeedDirection::default(),
|
||||
)),
|
||||
star: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Star(TwoColourSpeed::default())),
|
||||
rain: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Rain(SingleSpeed::default())),
|
||||
highlight: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Highlight(
|
||||
SingleColourSpeed::default(),
|
||||
)),
|
||||
laser: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Laser(SingleColourSpeed::default())),
|
||||
ripple: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Ripple(SingleColourSpeed::default())),
|
||||
pulse: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Pulse(SingleColour::default())),
|
||||
comet: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Comet(SingleColour::default())),
|
||||
flash: <[u8; LED_MSG_LEN]>::from(SetAuraBuiltin::Flash(SingleColour::default())),
|
||||
multi_static: <[[u8; LED_MSG_LEN]; 4]>::from(SetAuraBuiltin::MultiStatic(
|
||||
MultiColour::default(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||
pub enum BuiltInModeByte {
|
||||
Single = 0x00,
|
||||
Breathing = 0x01,
|
||||
Strobe = 0x02,
|
||||
Rainbow = 0x03,
|
||||
Star = 0x04,
|
||||
Rain = 0x05,
|
||||
Highlight = 0x06,
|
||||
Laser = 0x07,
|
||||
Ripple = 0x08,
|
||||
Pulse = 0x0a,
|
||||
Comet = 0x0b,
|
||||
Flash = 0x0c,
|
||||
MultiStatic,
|
||||
None,
|
||||
}
|
||||
impl Default for BuiltInModeByte {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
BuiltInModeByte::Single
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for BuiltInModeByte {
|
||||
#[inline]
|
||||
fn from(byte: u8) -> Self {
|
||||
match byte {
|
||||
0x00 => Self::Single,
|
||||
0x01 => Self::Breathing,
|
||||
0x02 => Self::Strobe,
|
||||
0x03 => Self::Rainbow,
|
||||
0x04 => Self::Star,
|
||||
0x05 => Self::Rain,
|
||||
0x06 => Self::Highlight,
|
||||
0x07 => Self::Laser,
|
||||
0x08 => Self::Ripple,
|
||||
0x0a => Self::Pulse,
|
||||
0x0b => Self::Comet,
|
||||
0x0c => Self::Flash,
|
||||
_ => Self::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&u8> for BuiltInModeByte {
|
||||
#[inline]
|
||||
fn from(byte: &u8) -> Self {
|
||||
Self::from(*byte)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BuiltInModeByte> for u8 {
|
||||
#[inline]
|
||||
fn from(byte: BuiltInModeByte) -> Self {
|
||||
match byte {
|
||||
BuiltInModeByte::Single => 0x00,
|
||||
BuiltInModeByte::Breathing => 0x01,
|
||||
BuiltInModeByte::Strobe => 0x02,
|
||||
BuiltInModeByte::Rainbow => 0x03,
|
||||
BuiltInModeByte::Star => 0x04,
|
||||
BuiltInModeByte::Rain => 0x05,
|
||||
BuiltInModeByte::Highlight => 0x06,
|
||||
BuiltInModeByte::Laser => 0x07,
|
||||
BuiltInModeByte::Ripple => 0x08,
|
||||
BuiltInModeByte::Pulse => 0x0a,
|
||||
BuiltInModeByte::Comet => 0x0b,
|
||||
BuiltInModeByte::Flash => 0x0c,
|
||||
BuiltInModeByte::MultiStatic => 0x00,
|
||||
BuiltInModeByte::None => 0xff,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::error::AuraError;
|
||||
use gumdrop::Options;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -30,7 +31,7 @@ impl FromStr for LedBrightness {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Colour(pub u8, pub u8, pub u8);
|
||||
impl Default for Colour {
|
||||
fn default() -> Self {
|
||||
@@ -51,7 +52,7 @@ impl FromStr for Colour {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
pub enum Speed {
|
||||
Low = 0xe1,
|
||||
Med = 0xeb,
|
||||
@@ -79,7 +80,7 @@ impl FromStr for Speed {
|
||||
/// Used for Rainbow mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
pub enum Direction {
|
||||
Right,
|
||||
Left,
|
||||
@@ -106,7 +107,7 @@ impl FromStr for Direction {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Options)]
|
||||
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||
pub struct TwoColourSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
@@ -118,7 +119,7 @@ pub struct TwoColourSpeed {
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Options)]
|
||||
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||
pub struct SingleSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
@@ -126,7 +127,7 @@ pub struct SingleSpeed {
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Options)]
|
||||
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||
pub struct SingleColour {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
@@ -134,7 +135,7 @@ pub struct SingleColour {
|
||||
pub colour: Colour,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Options)]
|
||||
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||
pub struct MultiColour {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
@@ -148,7 +149,7 @@ pub struct MultiColour {
|
||||
pub colour4: Colour,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Options)]
|
||||
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||
pub struct SingleSpeedDirection {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
@@ -162,7 +163,7 @@ pub struct SingleSpeedDirection {
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Options)]
|
||||
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||
pub struct SingleColourSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
@@ -172,10 +173,16 @@ pub struct SingleColourSpeed {
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Options, Clone, Deserialize, Serialize, Default)]
|
||||
pub struct FreeOpts {
|
||||
#[options(free)]
|
||||
free: Vec<String>,
|
||||
}
|
||||
|
||||
/// Byte value for setting the built-in mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
#[derive(Debug, Options)]
|
||||
#[derive(Debug, Clone, Options, Deserialize, Serialize)]
|
||||
pub enum SetAuraBuiltin {
|
||||
#[options(help = "set a single static colour")]
|
||||
Stable(SingleColour),
|
||||
|
||||
140
rog-client/src/core_dbus.rs
Normal file
140
rog-client/src/core_dbus.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
use super::*;
|
||||
use crate::fancy::KeyColourArray;
|
||||
use dbus::channel::Sender;
|
||||
use dbus::{blocking::Connection, channel::Token, Message};
|
||||
use std::error::Error;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
/// Simplified way to write a effect block
|
||||
pub struct AuraDbusWriter {
|
||||
connection: Box<Connection>,
|
||||
block_time: u64,
|
||||
stop: Arc<AtomicBool>,
|
||||
stop_token: Token,
|
||||
}
|
||||
|
||||
impl AuraDbusWriter {
|
||||
#[inline]
|
||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
||||
let connection = Connection::new_system()?;
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let stopper2 = stop.clone();
|
||||
let match_rule = dbus::message::MatchRule::new_signal(DBUS_IFACE, "KeyBacklightChanged");
|
||||
let stop_token = connection.add_match(match_rule, move |_: (), _, msg| {
|
||||
dbg!(&msg);
|
||||
if let Ok(stop) = msg.read1::<bool>() {
|
||||
if stop {
|
||||
stopper2.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
true
|
||||
})?;
|
||||
|
||||
Ok(AuraDbusWriter {
|
||||
connection: Box::new(connection),
|
||||
block_time: 33333,
|
||||
stop,
|
||||
stop_token,
|
||||
})
|
||||
}
|
||||
|
||||
/// This method must always be called before the very first write to initialise
|
||||
/// the keyboard LED EC in the correct mode
|
||||
#[inline]
|
||||
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mode = AuraModes::Aura;
|
||||
let mut msg =
|
||||
Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetKeyBacklight")?
|
||||
.append1(serde_json::to_string(&mode)?);
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write a single colour block.
|
||||
///
|
||||
/// Intentionally blocks for 10ms after sending to allow the block to
|
||||
/// be written to the keyboard EC. This should not be async.
|
||||
#[inline]
|
||||
pub fn write_colour_block(
|
||||
&mut self,
|
||||
key_colour_array: &KeyColourArray,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let group = key_colour_array.get();
|
||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteEffect")?
|
||||
.append3(&group[0].to_vec(), &group[1].to_vec(), &group[2].to_vec())
|
||||
.append3(&group[3].to_vec(), &group[4].to_vec(), &group[5].to_vec())
|
||||
.append3(&group[6].to_vec(), &group[7].to_vec(), &group[8].to_vec())
|
||||
.append2(&group[9].to_vec(), &group[10].to_vec());
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
thread::sleep(Duration::from_micros(self.block_time));
|
||||
self.connection.process(Duration::from_micros(500))?;
|
||||
if self.stop.load(Ordering::Relaxed) {
|
||||
self.connection.remove_match(self.stop_token)?;
|
||||
println!("Keyboard backlight was changed, exiting");
|
||||
std::process::exit(1)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_multizone(
|
||||
&mut self,
|
||||
group: &[[u8; LED_MSG_LEN]; 4],
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut 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())
|
||||
.append1(&group[3].to_vec());
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_bytes(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut msg =
|
||||
Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetKeyBacklight")?
|
||||
.append1(serde_json::to_string(mode)?);
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetFanMode")?
|
||||
.append1(level);
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_charge_limit(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetChargeLimit")?
|
||||
.append1(level);
|
||||
msg.set_no_reply(true);
|
||||
self.connection.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_builtin_mode(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.write_bytes(mode)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_brightness(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
|
||||
self.write_bytes(&AuraModes::LedBrightness(level))?;
|
||||
Ok(String::new())
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,25 @@ pub static DBUS_PATH: &str = "/org/rogcore/Daemon";
|
||||
pub static DBUS_IFACE: &str = "org.rogcore.Daemon";
|
||||
pub const LED_MSG_LEN: usize = 17;
|
||||
|
||||
mod builtins;
|
||||
pub use builtins::*;
|
||||
pub mod aura_modes;
|
||||
use aura_modes::AuraModes;
|
||||
|
||||
/// Contains mostly only what is required for parsing CLI options
|
||||
pub mod cli_options;
|
||||
mod fancy;
|
||||
|
||||
mod aura_dbus;
|
||||
pub use aura_dbus::*;
|
||||
/// Enables you to create fancy RGB effects
|
||||
pub mod fancy;
|
||||
|
||||
pub use fancy::*;
|
||||
/// The main dbus group for system controls, e.g, fan control, keyboard LED's
|
||||
pub mod core_dbus;
|
||||
|
||||
mod animatrix_dbus;
|
||||
pub use animatrix_dbus::*;
|
||||
/// Specific dbus for writing to the AniMe Matrix display (if supported)
|
||||
pub mod anime_dbus;
|
||||
|
||||
mod anime_matrix;
|
||||
pub use anime_matrix::*;
|
||||
/// Helper functions for the AniMe display
|
||||
pub mod anime_matrix;
|
||||
|
||||
pub mod error;
|
||||
use crate::cli_options::*;
|
||||
|
||||
/// Writes aout the correct byte string for brightness
|
||||
///
|
||||
@@ -56,7 +55,7 @@ pub fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
||||
]
|
||||
}
|
||||
|
||||
/// Parses `SetAuraBuiltin` in to packet data
|
||||
/// Parses `AuraCommands` in to packet data
|
||||
///
|
||||
/// Byte structure:
|
||||
///
|
||||
@@ -133,40 +132,41 @@ pub fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
||||
/// ```
|
||||
///
|
||||
/// This descriptor is also used for the per-key LED settings
|
||||
impl From<&SetAuraBuiltin> for [u8; LED_MSG_LEN] {
|
||||
fn from(mode: &SetAuraBuiltin) -> Self {
|
||||
impl From<&AuraModes> for [u8; LED_MSG_LEN] {
|
||||
fn from(mode: &AuraModes) -> Self {
|
||||
let mut msg = [0u8; LED_MSG_LEN];
|
||||
msg[0] = 0x5d;
|
||||
msg[1] = 0xb3;
|
||||
match mode {
|
||||
SetAuraBuiltin::Stable(_) => msg[3] = 0x00,
|
||||
SetAuraBuiltin::Breathe(_) => msg[3] = 0x01,
|
||||
SetAuraBuiltin::Strobe(_) => msg[3] = 0x02,
|
||||
SetAuraBuiltin::Rainbow(_) => msg[3] = 0x03,
|
||||
SetAuraBuiltin::Star(_) => msg[3] = 0x04,
|
||||
SetAuraBuiltin::Rain(_) => msg[3] = 0x05,
|
||||
SetAuraBuiltin::Highlight(_) => msg[3] = 0x06,
|
||||
SetAuraBuiltin::Laser(_) => msg[3] = 0x07,
|
||||
SetAuraBuiltin::Ripple(_) => msg[3] = 0x08,
|
||||
SetAuraBuiltin::Pulse(_) => msg[3] = 0x0a,
|
||||
SetAuraBuiltin::Comet(_) => msg[3] = 0x0b,
|
||||
SetAuraBuiltin::Flash(_) => msg[3] = 0x0c,
|
||||
AuraModes::LedBrightness(n) => return aura_brightness_bytes(*n),
|
||||
AuraModes::Stable(_) => msg[3] = 0x00,
|
||||
AuraModes::Breathe(_) => msg[3] = 0x01,
|
||||
AuraModes::Strobe(_) => msg[3] = 0x02,
|
||||
AuraModes::Rainbow(_) => msg[3] = 0x03,
|
||||
AuraModes::Star(_) => msg[3] = 0x04,
|
||||
AuraModes::Rain(_) => msg[3] = 0x05,
|
||||
AuraModes::Highlight(_) => msg[3] = 0x06,
|
||||
AuraModes::Laser(_) => msg[3] = 0x07,
|
||||
AuraModes::Ripple(_) => msg[3] = 0x08,
|
||||
AuraModes::Pulse(_) => msg[3] = 0x0a,
|
||||
AuraModes::Comet(_) => msg[3] = 0x0b,
|
||||
AuraModes::Flash(_) => msg[3] = 0x0c,
|
||||
_ => panic!("Mode not convertable to array"),
|
||||
}
|
||||
|
||||
match mode {
|
||||
SetAuraBuiltin::Rainbow(settings) => {
|
||||
AuraModes::Rainbow(settings) => {
|
||||
msg[7] = settings.speed as u8;
|
||||
msg[8] = settings.direction as u8;
|
||||
}
|
||||
SetAuraBuiltin::Star(settings) => {
|
||||
AuraModes::Star(settings) => {
|
||||
msg[4] = settings.colour.0;
|
||||
msg[5] = settings.colour.1;
|
||||
msg[6] = settings.colour.2;
|
||||
msg[7] = settings.speed as u8;
|
||||
msg[9] = settings.colour2.2;
|
||||
}
|
||||
SetAuraBuiltin::Breathe(settings) => {
|
||||
AuraModes::Breathe(settings) => {
|
||||
msg[4] = settings.colour.0;
|
||||
msg[5] = settings.colour.1;
|
||||
msg[6] = settings.colour.2;
|
||||
@@ -175,21 +175,21 @@ impl From<&SetAuraBuiltin> for [u8; LED_MSG_LEN] {
|
||||
msg[11] = settings.colour2.1;
|
||||
msg[12] = settings.colour2.2;
|
||||
}
|
||||
SetAuraBuiltin::Strobe(settings) | SetAuraBuiltin::Rain(settings) => {
|
||||
AuraModes::Strobe(settings) | AuraModes::Rain(settings) => {
|
||||
msg[7] = settings.speed as u8;
|
||||
}
|
||||
SetAuraBuiltin::Highlight(settings)
|
||||
| SetAuraBuiltin::Laser(settings)
|
||||
| SetAuraBuiltin::Ripple(settings) => {
|
||||
AuraModes::Highlight(settings)
|
||||
| AuraModes::Laser(settings)
|
||||
| AuraModes::Ripple(settings) => {
|
||||
msg[4] = settings.colour.0;
|
||||
msg[5] = settings.colour.1;
|
||||
msg[6] = settings.colour.2;
|
||||
msg[7] = settings.speed as u8;
|
||||
}
|
||||
SetAuraBuiltin::Stable(settings)
|
||||
| SetAuraBuiltin::Pulse(settings)
|
||||
| SetAuraBuiltin::Comet(settings)
|
||||
| SetAuraBuiltin::Flash(settings) => {
|
||||
AuraModes::Stable(settings)
|
||||
| AuraModes::Pulse(settings)
|
||||
| AuraModes::Comet(settings)
|
||||
| AuraModes::Flash(settings) => {
|
||||
msg[4] = settings.colour.0;
|
||||
msg[5] = settings.colour.1;
|
||||
msg[6] = settings.colour.2;
|
||||
@@ -200,16 +200,16 @@ impl From<&SetAuraBuiltin> for [u8; LED_MSG_LEN] {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SetAuraBuiltin> for [u8; LED_MSG_LEN] {
|
||||
impl From<AuraModes> for [u8; LED_MSG_LEN] {
|
||||
#[inline]
|
||||
fn from(mode: SetAuraBuiltin) -> Self {
|
||||
fn from(mode: AuraModes) -> Self {
|
||||
<[u8; LED_MSG_LEN]>::from(&mode)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SetAuraBuiltin> for [[u8; LED_MSG_LEN]; 4] {
|
||||
impl From<AuraModes> for [[u8; LED_MSG_LEN]; 4] {
|
||||
#[inline]
|
||||
fn from(mode: SetAuraBuiltin) -> Self {
|
||||
fn from(mode: AuraModes) -> Self {
|
||||
let mut msg = [[0u8; LED_MSG_LEN]; 4];
|
||||
for (i, row) in msg.iter_mut().enumerate() {
|
||||
row[0] = 0x5d;
|
||||
@@ -218,7 +218,7 @@ impl From<SetAuraBuiltin> for [[u8; LED_MSG_LEN]; 4] {
|
||||
}
|
||||
|
||||
match mode {
|
||||
SetAuraBuiltin::MultiStatic(settings) => {
|
||||
AuraModes::MultiStatic(settings) => {
|
||||
msg[0][4] = settings.colour1.0;
|
||||
msg[0][5] = settings.colour1.1;
|
||||
msg[0][6] = settings.colour1.2;
|
||||
|
||||
@@ -34,7 +34,7 @@ tokio = { version = "0.2.4", features = ["rt-threaded", "sync"] }
|
||||
# serialisation
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
toml = "0.5"
|
||||
serde_json = "1.0"
|
||||
|
||||
# Device control
|
||||
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rog_client::BuiltInModeBytes;
|
||||
use rog_client::aura_modes::AuraModes;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
@@ -10,15 +10,15 @@ pub struct Config {
|
||||
pub fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub brightness: u8,
|
||||
pub current_mode: [u8; 4],
|
||||
pub builtin_modes: BuiltInModeBytes,
|
||||
pub current_mode: u8,
|
||||
pub builtin_modes: Vec<AuraModes>,
|
||||
pub mode_performance: FanModeSettings,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// `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 {
|
||||
pub fn load(mut self, supported_led_modes: &[u8]) -> Self {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
@@ -31,15 +31,20 @@ impl Config {
|
||||
// create a default config here
|
||||
let mut c = Config::default();
|
||||
c.bat_charge_limit = 100;
|
||||
c.current_mode[0] = 0x5d;
|
||||
c.current_mode[1] = 0xb3;
|
||||
c.current_mode = 0;
|
||||
|
||||
for n in supported_led_modes {
|
||||
c.builtin_modes.push(AuraModes::from(*n))
|
||||
}
|
||||
dbg!(&c.builtin_modes);
|
||||
|
||||
// Should be okay to unwrap this as is since it is a Default
|
||||
let toml = toml::to_string(&c).unwrap();
|
||||
file.write_all(toml.as_bytes())
|
||||
let json = serde_json::to_string_pretty(&c).unwrap();
|
||||
file.write_all(json.as_bytes())
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
|
||||
self = c;
|
||||
} else {
|
||||
self = toml::from_str(&buf)
|
||||
self = serde_json::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
|
||||
}
|
||||
}
|
||||
@@ -56,7 +61,7 @@ impl Config {
|
||||
if l == 0 {
|
||||
panic!("Missing {}", CONFIG_PATH);
|
||||
} else {
|
||||
let x: Config = toml::from_str(&buf)
|
||||
let x: Config = serde_json::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
|
||||
*self = x;
|
||||
}
|
||||
@@ -65,19 +70,29 @@ impl Config {
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
||||
let toml = toml::to_string(self).expect("Parse config to JSON failed");
|
||||
file.write_all(toml.as_bytes())
|
||||
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
||||
file.write_all(json.as_bytes())
|
||||
.expect("Saving config failed");
|
||||
}
|
||||
|
||||
pub fn set_field_from(&mut self, bytes: &[u8]) {
|
||||
if bytes[0] == 0x5a && bytes[1] == 0xba {
|
||||
self.brightness = bytes[4];
|
||||
} else if bytes[0] == 0x5d && bytes[1] == 0xb3 {
|
||||
self.current_mode.copy_from_slice(&bytes[0..4]);
|
||||
self.builtin_modes.set_field_from(bytes);
|
||||
pub fn set_mode_data(&mut self, mode: AuraModes) {
|
||||
let byte: u8 = (&mode).into();
|
||||
for (index, n) in self.builtin_modes.iter().enumerate() {
|
||||
if byte == u8::from(n) {
|
||||
self.builtin_modes[index] = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_led_mode_data(&self, num: u8) -> Option<&AuraModes> {
|
||||
for mode in &self.builtin_modes {
|
||||
if u8::from(mode) == num {
|
||||
return Some(mode);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
|
||||
@@ -11,7 +11,7 @@ use dbus::{channel::Sender, nonblock::Process};
|
||||
|
||||
use dbus_tokio::connection;
|
||||
use log::{error, info, warn};
|
||||
use rog_client::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
||||
use rog_client::{aura_modes::AuraModes, DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -29,7 +29,8 @@ pub(super) type DbusU8Type = Arc<Mutex<Option<u8>>>;
|
||||
// DBUS processing takes 6ms if not tokiod
|
||||
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
let laptop = match_laptop();
|
||||
let mut config = Config::default().load();
|
||||
let mut config = Config::default().load(laptop.supported_modes());
|
||||
|
||||
info!("Config loaded");
|
||||
|
||||
let mut rogcore = RogCore::new(
|
||||
@@ -59,12 +60,9 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
let mut led_writer = LedWriter::new(
|
||||
rogcore.get_raw_device_handle(),
|
||||
laptop.led_endpoint(),
|
||||
(laptop.min_led_bright(), laptop.max_led_bright()),
|
||||
laptop.supported_modes().to_owned(),
|
||||
);
|
||||
led_writer
|
||||
.do_command(AuraCommand::ReloadLast, &mut config)
|
||||
.await?;
|
||||
led_writer.reload_last_builtin(&mut config).await?;
|
||||
|
||||
// Set up the mutexes
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
@@ -148,6 +146,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
});
|
||||
|
||||
// For helping with processing signals
|
||||
let connection1 = connection.clone();
|
||||
let config1 = config.clone();
|
||||
tokio::spawn(async move {
|
||||
@@ -188,20 +187,39 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
while let Some(command) = aura_command_recv.recv().await {
|
||||
let mut config = config.lock().await;
|
||||
match command {
|
||||
match &command {
|
||||
AuraCommand::WriteEffect(_) | AuraCommand::WriteMultizone(_) => led_writer
|
||||
.do_command(command, &mut config)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{:?}", err)),
|
||||
_ => {
|
||||
led_writer
|
||||
.do_command(command, &mut config)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||
connection
|
||||
.send(effect_cancel_signal.msg(&DBUS_PATH.into(), &DBUS_IFACE.into()))
|
||||
.unwrap_or_else(|_| 0);
|
||||
}
|
||||
AuraCommand::WriteMode(mode) => match mode {
|
||||
AuraModes::Aura => {
|
||||
led_writer
|
||||
.do_command(command, &mut config)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||
}
|
||||
_ => {
|
||||
led_writer
|
||||
.do_command(command, &mut config)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||
connection
|
||||
.send(
|
||||
effect_cancel_signal
|
||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
||||
.append1(true),
|
||||
)
|
||||
.unwrap_or_else(|_| 0);
|
||||
connection
|
||||
.send(
|
||||
effect_cancel_signal
|
||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
||||
.append1(false),
|
||||
)
|
||||
.unwrap_or_else(|_| 0);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
use crate::{config::Config, led_control::AuraCommand, rogcore::RogCore};
|
||||
use rog_client::{error::AuraError, BuiltInModeByte};
|
||||
use rog_client::{
|
||||
aura_modes::{
|
||||
AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, PULSE, RAIN, RAINBOW, RIPPLE, SINGLE,
|
||||
STAR, STROBE,
|
||||
},
|
||||
error::AuraError,
|
||||
};
|
||||
//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState};
|
||||
use crate::virt_device::ConsumerKeys;
|
||||
use log::{info, warn};
|
||||
@@ -22,11 +28,7 @@ pub(crate) fn match_laptop() -> LaptopBase {
|
||||
led_endpoint: 0x04,
|
||||
//from `lsusb -vd 0b05:1866`
|
||||
key_endpoint: 0x83,
|
||||
supported_modes: vec![
|
||||
BuiltInModeByte::Single,
|
||||
BuiltInModeByte::Breathing,
|
||||
BuiltInModeByte::Strobe,
|
||||
],
|
||||
supported_modes: vec![SINGLE, BREATHING, STROBE],
|
||||
support_animatrix: false,
|
||||
// backlight: Backlight::new("intel_backlight").unwrap(),
|
||||
};
|
||||
@@ -71,39 +73,18 @@ fn choose_1866_device(prod: u16) -> LaptopBase {
|
||||
// GX502, G712
|
||||
} else if board_name.starts_with("GX502") {
|
||||
laptop.supported_modes = vec![
|
||||
BuiltInModeByte::Single,
|
||||
BuiltInModeByte::Breathing,
|
||||
BuiltInModeByte::Strobe,
|
||||
BuiltInModeByte::Rainbow,
|
||||
BuiltInModeByte::Star,
|
||||
BuiltInModeByte::Rain,
|
||||
BuiltInModeByte::Highlight,
|
||||
BuiltInModeByte::Laser,
|
||||
BuiltInModeByte::Ripple,
|
||||
BuiltInModeByte::Pulse,
|
||||
BuiltInModeByte::Comet,
|
||||
BuiltInModeByte::Flash,
|
||||
SINGLE, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET,
|
||||
FLASH,
|
||||
];
|
||||
// GM501
|
||||
} else if board_name.starts_with("GM501") {
|
||||
laptop.supported_modes = vec![
|
||||
BuiltInModeByte::Single,
|
||||
BuiltInModeByte::Breathing,
|
||||
BuiltInModeByte::Strobe,
|
||||
BuiltInModeByte::Rainbow,
|
||||
];
|
||||
laptop.supported_modes = vec![SINGLE, BREATHING, STROBE, RAINBOW];
|
||||
// G531
|
||||
} else if board_name.starts_with("GX531")
|
||||
|| board_name.starts_with("G531")
|
||||
|| board_name.starts_with("G712")
|
||||
{
|
||||
laptop.supported_modes = vec![
|
||||
BuiltInModeByte::Single,
|
||||
BuiltInModeByte::Breathing,
|
||||
BuiltInModeByte::Strobe,
|
||||
BuiltInModeByte::Rainbow,
|
||||
BuiltInModeByte::Pulse,
|
||||
];
|
||||
laptop.supported_modes = vec![SINGLE, BREATHING, STROBE, RAINBOW, PULSE];
|
||||
} else {
|
||||
panic!(
|
||||
"Unsupported laptop, please request support at\nhttps://github.com/flukejones/rog-core"
|
||||
@@ -121,7 +102,7 @@ pub(super) struct LaptopBase {
|
||||
max_led_bright: u8,
|
||||
led_endpoint: u8,
|
||||
key_endpoint: u8,
|
||||
supported_modes: Vec<BuiltInModeByte>,
|
||||
supported_modes: Vec<u8>,
|
||||
support_animatrix: bool,
|
||||
//backlight: Backlight,
|
||||
}
|
||||
@@ -137,30 +118,68 @@ impl LaptopBase {
|
||||
key_buf: [u8; 32],
|
||||
mut aura_command: mpsc::Sender<AuraCommand>,
|
||||
) -> Result<(), AuraError> {
|
||||
let mut config = config.lock().await;
|
||||
match FnKeys::from(key_buf[1]) {
|
||||
FnKeys::LedBrightUp => {
|
||||
let mut bright = config.brightness;
|
||||
if bright < self.max_led_bright {
|
||||
bright += 1;
|
||||
info!("Increased LED brightness to {:#?}", bright);
|
||||
}
|
||||
aura_command
|
||||
.send(AuraCommand::BrightInc)
|
||||
.send(AuraCommand::WriteMode(AuraModes::LedBrightness(bright)))
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("LedBrightUp: {}", err));
|
||||
}
|
||||
FnKeys::LedBrightDown => {
|
||||
let mut bright = config.brightness;
|
||||
if bright > self.min_led_bright {
|
||||
bright -= 1;
|
||||
}
|
||||
aura_command
|
||||
.send(AuraCommand::BrightDec)
|
||||
.send(AuraCommand::WriteMode(AuraModes::LedBrightness(bright)))
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("LedBrightDown: {}", err));
|
||||
}
|
||||
FnKeys::AuraNext => {
|
||||
aura_command
|
||||
.send(AuraCommand::BuiltinNext)
|
||||
.await
|
||||
.unwrap_or_else(|_| {});
|
||||
if let Ok(idx) = self
|
||||
.supported_modes
|
||||
.binary_search(&config.current_mode.into())
|
||||
{
|
||||
let idx_next = if idx < self.supported_modes.len() - 1 {
|
||||
idx + 1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
if let Some(data) = config.get_led_mode_data(self.supported_modes[idx_next]) {
|
||||
aura_command
|
||||
.send(AuraCommand::WriteMode(data.to_owned()))
|
||||
.await
|
||||
.unwrap_or_else(|_| {});
|
||||
}
|
||||
} else {
|
||||
warn!("Tried to step to next LED mode while in non-supported mode");
|
||||
}
|
||||
}
|
||||
FnKeys::AuraPrevious => {
|
||||
aura_command
|
||||
.send(AuraCommand::BuiltinPrev)
|
||||
.await
|
||||
.unwrap_or_else(|_| {});
|
||||
if let Ok(idx) = self
|
||||
.supported_modes
|
||||
.binary_search(&config.current_mode.into())
|
||||
{
|
||||
let idx_next = if idx > 0 {
|
||||
idx - 1
|
||||
} else {
|
||||
self.supported_modes.len() - 1
|
||||
};
|
||||
if let Some(data) = config.get_led_mode_data(self.supported_modes[idx_next]) {
|
||||
aura_command
|
||||
.send(AuraCommand::WriteMode(data.to_owned()))
|
||||
.await
|
||||
.unwrap_or_else(|_| {});
|
||||
}
|
||||
} else {
|
||||
warn!("Tried to step to next LED mode while in non-supported mode");
|
||||
}
|
||||
}
|
||||
FnKeys::ScreenBrightUp => rogcore.virt_keys().press(ConsumerKeys::BacklightInc.into()), //self.backlight.step_up(),
|
||||
FnKeys::ScreenBrightDn => rogcore.virt_keys().press(ConsumerKeys::BacklightDec.into()),
|
||||
@@ -169,7 +188,6 @@ impl LaptopBase {
|
||||
FnKeys::AirplaneMode => rogcore.toggle_airplane_mode(),
|
||||
FnKeys::MicToggle => {}
|
||||
FnKeys::Fan => {
|
||||
let mut config = config.lock().await;
|
||||
rogcore.fan_mode_step(&mut config).unwrap_or_else(|err| {
|
||||
warn!("Couldn't toggle fan mode: {:?}", err);
|
||||
});
|
||||
@@ -199,12 +217,6 @@ impl LaptopBase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn min_led_bright(&self) -> u8 {
|
||||
self.min_led_bright
|
||||
}
|
||||
pub(super) fn max_led_bright(&self) -> u8 {
|
||||
self.max_led_bright
|
||||
}
|
||||
pub(super) fn led_endpoint(&self) -> u8 {
|
||||
self.led_endpoint
|
||||
}
|
||||
@@ -220,7 +232,7 @@ impl LaptopBase {
|
||||
pub(super) fn usb_product(&self) -> u16 {
|
||||
self.usb_product
|
||||
}
|
||||
pub(super) fn supported_modes(&self) -> &[BuiltInModeByte] {
|
||||
pub(super) fn supported_modes(&self) -> &[u8] {
|
||||
&self.supported_modes
|
||||
}
|
||||
pub(super) fn support_animatrix(&self) -> bool {
|
||||
|
||||
@@ -10,7 +10,10 @@ static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
use crate::config::Config;
|
||||
use log::{error, info, warn};
|
||||
use rog_client::{aura_brightness_bytes, error::AuraError, BuiltInModeByte};
|
||||
use rog_client::{
|
||||
aura_brightness_bytes, aura_modes::AuraModes, error::AuraError, fancy::KeyColourArray,
|
||||
LED_MSG_LEN,
|
||||
};
|
||||
use rusb::DeviceHandle;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::NonNull;
|
||||
@@ -18,13 +21,8 @@ use std::time::Duration;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AuraCommand {
|
||||
BrightInc,
|
||||
BrightDec,
|
||||
BuiltinNext,
|
||||
BuiltinPrev,
|
||||
WriteBytes(Vec<u8>),
|
||||
WriteMode(AuraModes),
|
||||
WriteEffect(Vec<Vec<u8>>),
|
||||
ReloadLast,
|
||||
WriteMultizone(Vec<Vec<u8>>),
|
||||
}
|
||||
|
||||
@@ -38,8 +36,7 @@ where
|
||||
C: rusb::UsbContext,
|
||||
{
|
||||
handle: NonNull<DeviceHandle<C>>,
|
||||
bright_min_max: (u8, u8),
|
||||
supported_modes: Vec<BuiltInModeByte>,
|
||||
supported_modes: Vec<u8>,
|
||||
led_endpoint: u8,
|
||||
initialised: bool,
|
||||
flip_effect_write: bool,
|
||||
@@ -58,13 +55,11 @@ where
|
||||
pub fn new(
|
||||
device_handle: NonNull<DeviceHandle<C>>,
|
||||
led_endpoint: u8,
|
||||
bright_min_max: (u8, u8),
|
||||
supported_modes: Vec<BuiltInModeByte>,
|
||||
supported_modes: Vec<u8>,
|
||||
) -> Self {
|
||||
LedWriter {
|
||||
handle: device_handle,
|
||||
led_endpoint,
|
||||
bright_min_max,
|
||||
supported_modes,
|
||||
initialised: false,
|
||||
flip_effect_write: false,
|
||||
@@ -87,60 +82,9 @@ where
|
||||
}
|
||||
|
||||
match command {
|
||||
AuraCommand::BrightInc => {
|
||||
let mut bright = config.brightness;
|
||||
if bright < self.bright_min_max.1 {
|
||||
bright += 1;
|
||||
config.brightness = bright;
|
||||
let bytes = aura_brightness_bytes(bright);
|
||||
self.set_and_save(&bytes, config).await?;
|
||||
info!("Increased LED brightness to {:#?}", bright);
|
||||
}
|
||||
}
|
||||
AuraCommand::BrightDec => {
|
||||
let mut bright = config.brightness;
|
||||
if bright > self.bright_min_max.0 {
|
||||
bright -= 1;
|
||||
config.brightness = bright;
|
||||
let bytes = aura_brightness_bytes(bright);
|
||||
self.set_and_save(&bytes, config).await?;
|
||||
info!("Decreased LED brightness to {:#?}", bright);
|
||||
}
|
||||
}
|
||||
AuraCommand::BuiltinNext => {
|
||||
// TODO: different path for multi-zone (byte 2 controlled, non-zero)
|
||||
let mode_curr = config.current_mode[3];
|
||||
if let Ok(idx) = self.supported_modes.binary_search(&mode_curr.into()) {
|
||||
let idx_next = if idx < self.supported_modes.len() - 1 {
|
||||
idx + 1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
self.set_builtin(config, idx_next).await?;
|
||||
} else {
|
||||
warn!("Tried to step to next LED mode while in non-supported mode");
|
||||
self.set_builtin(config, 0).await?;
|
||||
}
|
||||
}
|
||||
AuraCommand::BuiltinPrev => {
|
||||
// TODO: different path for multi-zone (byte 2 controlled, non-zero)
|
||||
let mode_curr = config.current_mode[3];
|
||||
if let Ok(idx) = self.supported_modes.binary_search(&mode_curr.into()) {
|
||||
let idx_next = if idx > 0 {
|
||||
idx - 1
|
||||
} else {
|
||||
self.supported_modes.len() - 1
|
||||
};
|
||||
self.set_builtin(config, idx_next).await?;
|
||||
} else {
|
||||
warn!("Tried to step to next LED mode while in non-supported mode");
|
||||
self.set_builtin(config, 0).await?;
|
||||
}
|
||||
}
|
||||
AuraCommand::WriteBytes(bytes) => self.set_and_save(&bytes, config).await?,
|
||||
AuraCommand::WriteMode(mode) => self.set_and_save(mode, config).await?,
|
||||
AuraCommand::WriteMultizone(effect) => self.write_multizone(effect).await?,
|
||||
AuraCommand::WriteEffect(effect) => self.write_effect(effect).await?,
|
||||
AuraCommand::ReloadLast => self.reload_last_builtin(&config).await?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -162,17 +106,6 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn write_array_of_bytes(&self, messages: &[&[u8]]) -> Result<(), AuraError> {
|
||||
for message in messages {
|
||||
self.write_bytes(*message).await?;
|
||||
self.write_bytes(&LED_SET).await?;
|
||||
}
|
||||
// Changes won't persist unless apply is set
|
||||
self.write_bytes(&LED_APPLY).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write an effect block
|
||||
///
|
||||
/// `aura_effect_init` must be called any effect routine, and called only once.
|
||||
@@ -202,34 +135,55 @@ where
|
||||
}
|
||||
|
||||
/// Used to set a builtin mode and save the settings for it
|
||||
///
|
||||
/// This needs to be universal so that settings applied by dbus stick
|
||||
#[inline]
|
||||
async fn set_and_save(&self, bytes: &[u8], config: &mut Config) -> Result<(), AuraError> {
|
||||
let mode = BuiltInModeByte::from(bytes[3]);
|
||||
// safety pass-through of possible effect write
|
||||
if bytes[1] == 0xbc {
|
||||
self.write_bytes(bytes).await?;
|
||||
return Ok(());
|
||||
} else if self.supported_modes.contains(&mode) || bytes[1] == 0xba {
|
||||
let messages = [bytes];
|
||||
self.write_array_of_bytes(&messages).await?;
|
||||
config.set_field_from(bytes);
|
||||
config.write();
|
||||
return Ok(());
|
||||
async fn set_and_save(&self, mode: AuraModes, config: &mut Config) -> Result<(), AuraError> {
|
||||
match mode {
|
||||
AuraModes::Aura => {
|
||||
let bytes = KeyColourArray::get_init_msg();
|
||||
self.write_bytes(&bytes).await?;
|
||||
return Ok(());
|
||||
}
|
||||
AuraModes::LedBrightness(n) => {
|
||||
let bytes: [u8; LED_MSG_LEN] = (&mode).into();
|
||||
self.write_bytes(&bytes).await?;
|
||||
config.brightness = n;
|
||||
config.write();
|
||||
info!("LED brightness set to {:#?}", n);
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
let mode_num: u8 = u8::from(&mode).into();
|
||||
if self.supported_modes.contains(&mode_num) {
|
||||
let bytes: [u8; LED_MSG_LEN] = (&mode).into();
|
||||
self.write_bytes(&bytes).await?;
|
||||
self.write_bytes(&LED_SET).await?;
|
||||
// Changes won't persist unless apply is set
|
||||
self.write_bytes(&LED_APPLY).await?;
|
||||
|
||||
config.current_mode = mode_num;
|
||||
config.set_mode_data(mode);
|
||||
config.write();
|
||||
info!("Switched LED mode to {:#?}", config.current_mode);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warn!("{:?} not supported", mode);
|
||||
Err(AuraError::NotSupported)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn reload_last_builtin(&self, config: &Config) -> Result<(), AuraError> {
|
||||
pub async fn reload_last_builtin(&self, config: &Config) -> Result<(), AuraError> {
|
||||
// set current mode (if any)
|
||||
if self.supported_modes.len() > 1 {
|
||||
let mode_curr = config.current_mode[3];
|
||||
let mode = config
|
||||
.builtin_modes
|
||||
.get_field_from(mode_curr)
|
||||
.get_led_mode_data(config.current_mode)
|
||||
.ok_or(AuraError::NotSupported)?
|
||||
.to_owned();
|
||||
let mode: [u8; LED_MSG_LEN] = mode.into();
|
||||
self.write_bytes(&mode).await?;
|
||||
info!("Reloaded last used mode");
|
||||
}
|
||||
@@ -241,19 +195,4 @@ where
|
||||
info!("Reloaded last used brightness");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn set_builtin(&self, config: &mut Config, index: usize) -> Result<(), AuraError> {
|
||||
if let Some(mode) = self.supported_modes.get(index) {
|
||||
let mode_next = config
|
||||
.builtin_modes
|
||||
.get_field_from(mode.to_owned().into())
|
||||
.ok_or(AuraError::NotSupported)?
|
||||
.to_owned();
|
||||
self.set_and_save(&mode_next, config).await?;
|
||||
info!("Switched LED mode to {:#?}", self.supported_modes[index]);
|
||||
return Ok(());
|
||||
}
|
||||
Err(AuraError::NotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ use env_logger::{Builder, Target};
|
||||
use gumdrop::Options;
|
||||
use log::LevelFilter;
|
||||
use rog_client::{
|
||||
aura_modes::AuraModes,
|
||||
cli_options::{LedBrightness, SetAuraBuiltin},
|
||||
AuraDbusWriter, LED_MSG_LEN,
|
||||
core_dbus::AuraDbusWriter,
|
||||
LED_MSG_LEN,
|
||||
};
|
||||
|
||||
static VERSION: &str = "0.12.2";
|
||||
@@ -67,33 +69,22 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Check for special modes here, eg, per-key or multi-zone
|
||||
match command {
|
||||
SetAuraBuiltin::MultiStatic(_) => {
|
||||
let command: AuraModes = command.into();
|
||||
let byte_arr = <[[u8; LED_MSG_LEN]; 4]>::from(command);
|
||||
writer.write_multizone(&byte_arr)?;
|
||||
}
|
||||
_ => match writer.write_builtin_mode(&command) {
|
||||
Ok(msg) => println!("Daemon response: {}", msg),
|
||||
Err(err) => println!("Error: {}", err),
|
||||
},
|
||||
_ => writer.write_builtin_mode(&command.into())?,
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(brightness) = parsed.bright {
|
||||
match writer.write_brightness(brightness.level()) {
|
||||
Ok(msg) => println!("Daemon response: {}", msg),
|
||||
Err(err) => println!("Error: {}", err),
|
||||
}
|
||||
writer.write_brightness(brightness.level())?;
|
||||
}
|
||||
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),
|
||||
}
|
||||
writer.write_fan_mode(fan_level.into())?;
|
||||
}
|
||||
if let Some(charge_limit) = parsed.charge_limit {
|
||||
match writer.write_charge_limit(charge_limit) {
|
||||
Ok(msg) => println!("Daemon response: {}", msg),
|
||||
Err(err) => println!("Error: {}", err),
|
||||
}
|
||||
writer.write_charge_limit(charge_limit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::config::Config;
|
||||
use crate::daemon::DbusU8Type;
|
||||
use crate::led_control::AuraCommand;
|
||||
use crate::rogcore::FanLevel;
|
||||
use dbus::tree::{Factory, MTSync, Method, MethodErr, Signal, Tree};
|
||||
use log::warn;
|
||||
use rog_client::{DBUS_IFACE, DBUS_PATH};
|
||||
@@ -15,25 +14,26 @@ pub(super) fn dbus_set_ledmsg(sender: Mutex<Sender<AuraCommand>>) -> Method<MTSy
|
||||
let factory = Factory::new_sync::<()>();
|
||||
factory
|
||||
// method for ledmessage
|
||||
.method("LedWriteBytes", (), {
|
||||
.method("SetKeyBacklight", (), {
|
||||
move |m| {
|
||||
let bytes: Vec<u8> = m.msg.read1()?;
|
||||
let json: &str = m.msg.read1()?;
|
||||
if let Ok(mut lock) = sender.try_lock() {
|
||||
let command = AuraCommand::WriteBytes(bytes.to_vec());
|
||||
lock.try_send(command)
|
||||
.unwrap_or_else(|err| warn!("LedWriteBytes over mpsc failed: {}", err));
|
||||
let mret = m
|
||||
.msg
|
||||
.method_return()
|
||||
.append1(&format!("Wrote {:x?}", bytes));
|
||||
Ok(vec![mret])
|
||||
if let Ok(data) = serde_json::from_str(json) {
|
||||
let command = AuraCommand::WriteMode(data);
|
||||
lock.try_send(command).unwrap_or_else(|err| {
|
||||
warn!("SetKeyBacklight over mpsc failed: {}", err)
|
||||
});
|
||||
} else {
|
||||
warn!("SetKeyBacklight could not deserialise");
|
||||
}
|
||||
Ok(vec![])
|
||||
} else {
|
||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
||||
}
|
||||
}
|
||||
})
|
||||
.outarg::<&str, _>("reply")
|
||||
.inarg::<Vec<u8>, _>("bytearray")
|
||||
.inarg::<&str, _>("json")
|
||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
||||
}
|
||||
|
||||
pub(super) fn dbus_set_ledmultizone(sender: Mutex<Sender<AuraCommand>>) -> Method<MTSync, ()> {
|
||||
@@ -145,18 +145,14 @@ pub(super) fn dbus_set_fan_mode(data: DbusU8Type) -> Method<MTSync, ()> {
|
||||
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])
|
||||
Ok(vec![])
|
||||
} else {
|
||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
||||
}
|
||||
}
|
||||
})
|
||||
.outarg::<&str, _>("reply")
|
||||
.inarg::<u8, _>("byte")
|
||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
||||
}
|
||||
|
||||
pub(super) fn dbus_get_fan_mode(config: Arc<Mutex<Config>>) -> Method<MTSync, ()> {
|
||||
@@ -201,18 +197,14 @@ pub(super) fn dbus_set_charge_limit(data: DbusU8Type) -> Method<MTSync, ()> {
|
||||
let mut iter = m.msg.iter_init();
|
||||
let byte: u8 = iter.read()?;
|
||||
*lock = Some(byte);
|
||||
let mret = m
|
||||
.msg
|
||||
.method_return()
|
||||
.append1(format!("Battery charge limit set to {}", byte));
|
||||
Ok(vec![mret])
|
||||
Ok(vec![])
|
||||
} else {
|
||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
||||
}
|
||||
}
|
||||
})
|
||||
.outarg::<&str, _>("reply")
|
||||
.inarg::<u8, _>("byte")
|
||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
@@ -236,7 +228,11 @@ pub(super) fn dbus_create_tree(
|
||||
|
||||
let factory = Factory::new_sync::<()>();
|
||||
|
||||
let effect_cancel_sig = Arc::new(factory.signal("LedCancelEffect", ()));
|
||||
let builtin_mode_sig = Arc::new(
|
||||
factory
|
||||
.signal("KeyBacklightChanged", ())
|
||||
.sarg::<bool, _>("value"),
|
||||
);
|
||||
let fanmode_changed_sig = Arc::new(factory.signal("FanModeChanged", ()).sarg::<u8, _>("value"));
|
||||
let chrg_limit_changed_sig = Arc::new(
|
||||
factory
|
||||
@@ -258,7 +254,7 @@ pub(super) fn dbus_create_tree(
|
||||
.add_m(dbus_set_charge_limit(charge_limit.clone()))
|
||||
.add_m(dbus_get_fan_mode(config.clone()))
|
||||
.add_m(dbus_get_charge_limit(config))
|
||||
.add_s(effect_cancel_sig.clone())
|
||||
.add_s(builtin_mode_sig.clone())
|
||||
.add_s(fanmode_changed_sig.clone())
|
||||
.add_s(chrg_limit_changed_sig.clone()),
|
||||
),
|
||||
@@ -271,7 +267,7 @@ pub(super) fn dbus_create_tree(
|
||||
animatrix_recv,
|
||||
fan_mode,
|
||||
charge_limit,
|
||||
effect_cancel_sig,
|
||||
builtin_mode_sig,
|
||||
fanmode_changed_sig,
|
||||
chrg_limit_changed_sig,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user