Refactor dbus commands and internal data structures

This commit is contained in:
Luke
2020-06-29 15:52:49 +12:00
parent f85c8cbc50
commit 32e9e63809
26 changed files with 720 additions and 653 deletions

View File

@@ -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
View File

@@ -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"

View File

@@ -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)

View File

@@ -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
}
}
}

View File

@@ -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"

View File

@@ -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() {

View File

@@ -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)]

View File

@@ -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()?;

View File

@@ -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()?;

View File

@@ -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()?;

View File

@@ -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()?;

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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))
}
}

View 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"),
}
}
}

View File

@@ -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,
}
}
}

View File

@@ -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
View 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())
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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)]

View File

@@ -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);
}
},
}
}
}

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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(())
}

View File

@@ -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,
)