mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0aac0ce495 | |||
| e24b4858a4 | |||
| cf2b459e48 | |||
| 895179fdad | |||
| fe3e8792eb | |||
| 1916641e2e | |||
| 3ea0737be9 | |||
| c67373a830 | |||
| 41cbf4d353 | |||
| 7a4c14f7b8 | |||
| f52a4d464a | |||
| aa71592a31 | |||
| dc6e8f8dcb | |||
| 1a4836246f | |||
| ab80b0742f | |||
| 6926aeed20 | |||
| f95e42e4b9 | |||
| 82bee6b86e | |||
| bd9bc8bcff | |||
| 8a6d364304 | |||
| 64d99a3e05 | |||
| 59f54b76f6 | |||
| 6f36d91281 | |||
| e9f1fa01fc | |||
| 0d3a5d266b |
+31
-2
@@ -5,9 +5,38 @@ 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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
# [3.5.2] - 2021-05-15
|
||||||
### Changed
|
### Changed
|
||||||
- Split out all aura functionality that isn't dependent on the daemon in to a
|
- Bugfix: prevent the hang on compute/integrated mode change
|
||||||
new crate `rog-aura`
|
|
||||||
|
# [3.5.1] - 2021-04-25
|
||||||
|
### Changed
|
||||||
|
+ Anime:
|
||||||
|
- Fix using multiple configs
|
||||||
|
|
||||||
|
# [3.5.0] - 2021-04-25
|
||||||
|
### Changed
|
||||||
|
+ Keyboard:
|
||||||
|
- Split out all aura functionality that isn't dependent on the daemon in to a
|
||||||
|
new crate `rog-aura` (incomplete)
|
||||||
|
- Keyboard LED control now includes:
|
||||||
|
+ Enable/disable LED's while laptop is awake
|
||||||
|
+ Enable/disable LED animation while laptop is suspended and AC plugged in
|
||||||
|
- Properly reload the last used keyboard mode on boot
|
||||||
|
+ Graphics:
|
||||||
|
- Correctly enable compute mode for nvidia plus no-reboot or logout if switching
|
||||||
|
from vfio/integrated/compute.
|
||||||
|
- Add asusd config option to not save compute/vfio mode switch.
|
||||||
|
+ Anime:
|
||||||
|
- Enable basic multiple user anime configs (asusd-user must still be restarted)
|
||||||
|
+ Profiles:
|
||||||
|
- Enable dbus methods for freq min/max, fan curve, fan preset, CPU turbo enable.
|
||||||
|
These options will apply to the active profile if no profile name is specified.
|
||||||
|
|
||||||
|
# [3.4.1] - 2021-04-11
|
||||||
|
### Changed
|
||||||
|
- Fix anime init sequence
|
||||||
|
|
||||||
# [3.4.0] - 2021-04-11
|
# [3.4.0] - 2021-04-11
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
Generated
+19
-4
@@ -42,13 +42,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asusctl"
|
name = "asusctl"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"daemon",
|
"daemon",
|
||||||
"gif",
|
"gif",
|
||||||
"glam",
|
"glam",
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
"rog_anime",
|
"rog_anime",
|
||||||
|
"rog_aura",
|
||||||
"rog_dbus",
|
"rog_dbus",
|
||||||
"rog_types",
|
"rog_types",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -205,13 +206,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daemon"
|
name = "daemon"
|
||||||
version = "3.4.1"
|
version = "3.5.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"intel-pstate",
|
"intel-pstate",
|
||||||
"log",
|
"log",
|
||||||
"logind-zbus",
|
"logind-zbus",
|
||||||
"rog_anime",
|
"rog_anime",
|
||||||
|
"rog_aura",
|
||||||
"rog_dbus",
|
"rog_dbus",
|
||||||
"rog_fan_curve",
|
"rog_fan_curve",
|
||||||
"rog_types",
|
"rog_types",
|
||||||
@@ -228,7 +230,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daemon-user"
|
name = "daemon-user"
|
||||||
version = "1.0.0"
|
version = "1.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs 3.0.1",
|
"dirs 3.0.1",
|
||||||
"rog_anime",
|
"rog_anime",
|
||||||
@@ -897,7 +899,7 @@ checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rog_anime"
|
name = "rog_anime"
|
||||||
version = "1.0.3"
|
version = "1.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gif",
|
"gif",
|
||||||
"glam",
|
"glam",
|
||||||
@@ -910,11 +912,23 @@ dependencies = [
|
|||||||
"zvariant_derive",
|
"zvariant_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rog_aura"
|
||||||
|
version = "1.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"zbus",
|
||||||
|
"zvariant",
|
||||||
|
"zvariant_derive",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rog_dbus"
|
name = "rog_dbus"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rog_anime",
|
"rog_anime",
|
||||||
|
"rog_aura",
|
||||||
"rog_fan_curve",
|
"rog_fan_curve",
|
||||||
"rog_types",
|
"rog_types",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -937,6 +951,7 @@ name = "rog_types"
|
|||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
|
"rog_aura",
|
||||||
"rog_fan_curve",
|
"rog_fan_curve",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ Requirements are rust >= 1.40 installed from rustup.io if the distro provided ve
|
|||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
Packaging and auto-builds are available [here](https://build.opensuse.org/package/show/home:luke_nukem:asus/asus-nb-ctrl)
|
Packaging and auto-builds are available [here](https://build.opensuse.org/package/show/home:luke_nukem:asus/asusctl)
|
||||||
|
|
||||||
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
|
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
|
||||||
|
|
||||||
@@ -243,6 +243,16 @@ Please file a support request.
|
|||||||
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
|
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
|
||||||
```
|
```
|
||||||
|
|
||||||
# License
|
# License & Trademarks
|
||||||
|
|
||||||
Mozilla Public License 2 (MPL-2.0)
|
Mozilla Public License 2 (MPL-2.0)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
ASUS and ROG Trademark is either a US registered trademark or trademark of ASUSTeK Computer Inc. in the United States and/or other countries.
|
||||||
|
|
||||||
|
Reference to any ASUS products, services, processes, or other information and/or use of ASUS Trademarks does not constitute or imply endorsement, sponsorship, or recommendation thereof by ASUS.
|
||||||
|
|
||||||
|
The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops.
|
||||||
|
|
||||||
|
---
|
||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asusctl"
|
name = "asusctl"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ edition = "2018"
|
|||||||
# serialisation
|
# serialisation
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
rog_anime = { path = "../rog-anime" }
|
rog_anime = { path = "../rog-anime" }
|
||||||
|
rog_aura = { path = "../rog-aura" }
|
||||||
rog_dbus = { path = "../rog-dbus" }
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
rog_types = { path = "../rog-types" }
|
rog_types = { path = "../rog-types" }
|
||||||
daemon = { path = "../daemon" }
|
daemon = { path = "../daemon" }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use rog_aura::{GX502Layout, KeyColourArray, KeyLayout};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (dbus, _) = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (dbus, _) = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
|
use rog_aura::{Key, KeyColourArray};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::aura_perkey::{Key, KeyColourArray};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (dbus, _) = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use rog_aura::{GX502Layout, KeyColourArray, KeyLayout};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (dbus, _) = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use rog_types::error::AuraError;
|
use rog_aura::error::Error;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@@ -8,7 +8,7 @@ pub enum AnimeStatusValue {
|
|||||||
Off,
|
Off,
|
||||||
}
|
}
|
||||||
impl FromStr for AnimeStatusValue {
|
impl FromStr for AnimeStatusValue {
|
||||||
type Err = AuraError;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let s = s.to_lowercase();
|
let s = s.to_lowercase();
|
||||||
@@ -17,7 +17,7 @@ impl FromStr for AnimeStatusValue {
|
|||||||
"off" => Ok(AnimeStatusValue::Off),
|
"off" => Ok(AnimeStatusValue::Off),
|
||||||
_ => {
|
_ => {
|
||||||
print!("Invalid argument, must be one of: on, off");
|
print!("Invalid argument, must be one of: on, off");
|
||||||
Err(AuraError::ParseAnime)
|
Err(Error::ParseAnime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use rog_types::{
|
use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
|
||||||
aura_modes::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed},
|
|
||||||
error::AuraError,
|
|
||||||
};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Options)]
|
#[derive(Options)]
|
||||||
@@ -19,7 +16,7 @@ impl LedBrightness {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FromStr for LedBrightness {
|
impl FromStr for LedBrightness {
|
||||||
type Err = AuraError;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let s = s.to_lowercase();
|
let s = s.to_lowercase();
|
||||||
@@ -30,7 +27,7 @@ impl FromStr for LedBrightness {
|
|||||||
"high" => Ok(LedBrightness { level: Some(0x03) }),
|
"high" => Ok(LedBrightness { level: Some(0x03) }),
|
||||||
_ => {
|
_ => {
|
||||||
print!("Invalid argument, must be one of: off, low, med, high");
|
print!("Invalid argument, must be one of: off, low, med, high");
|
||||||
Err(AuraError::ParseBrightness)
|
Err(Error::ParseBrightness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+68
-12
@@ -5,9 +5,9 @@ use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
|
|||||||
use anime_cli::{AnimeActions, AnimeCommand};
|
use anime_cli::{AnimeActions, AnimeCommand};
|
||||||
use gumdrop::{Opt, Options};
|
use gumdrop::{Opt, Options};
|
||||||
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
|
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
|
||||||
|
use rog_aura::{self, AuraEffect};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::{
|
use rog_types::{
|
||||||
aura_modes::{self, AuraEffect, AuraModeNum},
|
|
||||||
gfx_vendors::GfxVendors,
|
gfx_vendors::GfxVendors,
|
||||||
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
||||||
supported::{
|
supported::{
|
||||||
@@ -62,6 +62,16 @@ struct LedModeCommand {
|
|||||||
next_mode: bool,
|
next_mode: bool,
|
||||||
#[options(help = "switch to previous aura mode")]
|
#[options(help = "switch to previous aura mode")]
|
||||||
prev_mode: bool,
|
prev_mode: bool,
|
||||||
|
#[options(
|
||||||
|
meta = "",
|
||||||
|
help = "set the keyboard LED to enabled while the device is awake"
|
||||||
|
)]
|
||||||
|
awake_enable: Option<bool>,
|
||||||
|
#[options(
|
||||||
|
meta = "",
|
||||||
|
help = "set the keyboard LED suspend animation to enabled while the device is suspended"
|
||||||
|
)]
|
||||||
|
sleep_enable: Option<bool>,
|
||||||
#[options(command)]
|
#[options(command)]
|
||||||
command: Option<SetAuraBuiltin>,
|
command: Option<SetAuraBuiltin>,
|
||||||
}
|
}
|
||||||
@@ -215,7 +225,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Some(level) => dbus
|
Some(level) => dbus
|
||||||
.proxies()
|
.proxies()
|
||||||
.led()
|
.led()
|
||||||
.set_led_brightness(<aura_modes::LedBrightness>::from(level))?,
|
.set_led_brightness(<rog_aura::LedBrightness>::from(level))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +345,12 @@ fn handle_led_mode(
|
|||||||
supported: &LedSupportedFunctions,
|
supported: &LedSupportedFunctions,
|
||||||
mode: &LedModeCommand,
|
mode: &LedModeCommand,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if mode.command.is_none() && !mode.prev_mode && !mode.next_mode {
|
if mode.command.is_none()
|
||||||
|
&& !mode.prev_mode
|
||||||
|
&& !mode.next_mode
|
||||||
|
&& mode.sleep_enable.is_none()
|
||||||
|
&& mode.awake_enable.is_none()
|
||||||
|
{
|
||||||
if !mode.help {
|
if !mode.help {
|
||||||
println!("Missing arg or command\n");
|
println!("Missing arg or command\n");
|
||||||
}
|
}
|
||||||
@@ -347,9 +362,13 @@ fn handle_led_mode(
|
|||||||
.lines()
|
.lines()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
for command in commands.iter().filter(|mode| {
|
for command in commands.iter().filter(|command| {
|
||||||
if let Some(modes) = supported.stock_led_modes.as_ref() {
|
if let Some(modes) = supported.stock_led_modes.as_ref() {
|
||||||
return modes.contains(&<AuraModeNum>::from(mode.as_str()));
|
for mode in modes {
|
||||||
|
if command.contains(&(<&str>::from(mode)).to_lowercase()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if supported.multizone_led_mode {
|
if supported.multizone_led_mode {
|
||||||
return true;
|
return true;
|
||||||
@@ -389,6 +408,15 @@ fn handle_led_mode(
|
|||||||
.set_led_mode(&<AuraEffect>::from(mode))?,
|
.set_led_mode(&<AuraEffect>::from(mode))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(enable) = mode.awake_enable {
|
||||||
|
dbus.proxies().led().set_awake_enabled(enable)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(enable) = mode.sleep_enable {
|
||||||
|
dbus.proxies().led().set_sleep_enabled(enable)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,18 +426,19 @@ fn handle_profile(
|
|||||||
cmd: &ProfileCommand,
|
cmd: &ProfileCommand,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if !cmd.next
|
if !cmd.next
|
||||||
&& !cmd.create
|
&& !cmd.create // TODO
|
||||||
&& !cmd.list
|
&& !cmd.list
|
||||||
|
&& cmd.profile.is_none()
|
||||||
&& !cmd.active_name
|
&& !cmd.active_name
|
||||||
&& !cmd.active_data
|
&& !cmd.active_data
|
||||||
&& !cmd.profiles_data
|
&& !cmd.profiles_data
|
||||||
&& cmd.remove.is_none()
|
&& cmd.remove.is_none()
|
||||||
&& cmd.curve.is_none()
|
&& cmd.curve.is_none() // TODO
|
||||||
&& cmd.max_percentage.is_none()
|
&& cmd.fan_preset.is_none() // TODO
|
||||||
|
&& cmd.turbo.is_none() // TODO
|
||||||
|
&& cmd.max_percentage.is_none() // TODO
|
||||||
&& cmd.min_percentage.is_none()
|
&& cmd.min_percentage.is_none()
|
||||||
&& cmd.fan_preset.is_none()
|
// TODO
|
||||||
&& cmd.profile.is_none()
|
|
||||||
&& cmd.turbo.is_none()
|
|
||||||
{
|
{
|
||||||
if !cmd.help {
|
if !cmd.help {
|
||||||
println!("Missing arg or command\n");
|
println!("Missing arg or command\n");
|
||||||
@@ -428,6 +457,9 @@ fn handle_profile(
|
|||||||
if let Some(lst) = cmd.self_command_list() {
|
if let Some(lst) = cmd.self_command_list() {
|
||||||
println!("\n{}", lst);
|
println!("\n{}", lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("Note: turbo, frequency, fan preset and fan curve options will apply to");
|
||||||
|
println!(" to the currently active profile unless a profile name is specified");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,10 +492,34 @@ fn handle_profile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This must come before the next block of actions so that changing a specific
|
||||||
|
// profile can be done
|
||||||
if cmd.profile.is_some() {
|
if cmd.profile.is_some() {
|
||||||
dbus.proxies()
|
dbus.proxies()
|
||||||
.profile()
|
.profile()
|
||||||
.write_command(&ProfileEvent::Cli(cmd.clone()))?
|
.write_command(&ProfileEvent::Cli(cmd.clone()))?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(turbo) = cmd.turbo {
|
||||||
|
dbus.proxies().profile().set_turbo(turbo)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(min) = cmd.min_percentage {
|
||||||
|
dbus.proxies().profile().set_min_frequency(min)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(max) = cmd.max_percentage {
|
||||||
|
dbus.proxies().profile().set_max_frequency(max)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref preset) = cmd.fan_preset {
|
||||||
|
dbus.proxies().profile().set_fan_preset(preset.into())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref curve) = cmd.curve {
|
||||||
|
let s = curve.as_config_string();
|
||||||
|
dbus.proxies().profile().set_fan_curve(&s)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "daemon-user"
|
name = "daemon-user"
|
||||||
version = "1.0.0"
|
version = "1.1.1"
|
||||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Usermode daemon for user settings, anime, per-key lighting"
|
description = "Usermode daemon for user settings, anime, per-key lighting"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use zbus::dbus_interface;
|
|||||||
use zvariant::ObjectPath;
|
use zvariant::ObjectPath;
|
||||||
use zvariant_derive::Type;
|
use zvariant_derive::Type;
|
||||||
|
|
||||||
use crate::{error::Error, user_config::UserConfig};
|
use crate::{error::Error, user_config::UserAnimeConfig};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
|
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
|
||||||
pub enum TimeType {
|
pub enum TimeType {
|
||||||
@@ -111,7 +111,7 @@ impl<'a> CtrlAnimeInner<'static> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CtrlAnime<'a> {
|
pub struct CtrlAnime<'a> {
|
||||||
config: Arc<Mutex<UserConfig>>,
|
config: Arc<Mutex<UserAnimeConfig>>,
|
||||||
client: AuraDbusClient<'a>,
|
client: AuraDbusClient<'a>,
|
||||||
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
|
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
|
||||||
/// Must be the same Atomic as in CtrlAnimeInner
|
/// Must be the same Atomic as in CtrlAnimeInner
|
||||||
@@ -120,7 +120,7 @@ pub struct CtrlAnime<'a> {
|
|||||||
|
|
||||||
impl<'a> CtrlAnime<'static> {
|
impl<'a> CtrlAnime<'static> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: Arc<Mutex<UserConfig>>,
|
config: Arc<Mutex<UserAnimeConfig>>,
|
||||||
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
|
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
|
||||||
client: AuraDbusClient<'static>,
|
client: AuraDbusClient<'static>,
|
||||||
inner_early_return: &'static AtomicBool,
|
inner_early_return: &'static AtomicBool,
|
||||||
@@ -147,7 +147,6 @@ impl<'a> CtrlAnime<'static> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The pattern for a zbus method is:
|
// The pattern for a zbus method is:
|
||||||
// - Get config lock if required
|
// - Get config lock if required
|
||||||
// - Set inner_early_return to stop the inner run loop temporarily
|
// - Set inner_early_return to stop the inner run loop temporarily
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ use std::sync::atomic::AtomicBool;
|
|||||||
static ANIME_INNER_EARLY_RETURN: AtomicBool = AtomicBool::new(false);
|
static ANIME_INNER_EARLY_RETURN: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
println!("user daemon v{}", rog_user::VERSION);
|
||||||
|
println!(" rog-anime v{}", rog_anime::VERSION);
|
||||||
|
println!(" rog-dbus v{}", rog_dbus::VERSION);
|
||||||
|
|
||||||
let (client, _) = AuraDbusClient::new().unwrap();
|
let (client, _) = AuraDbusClient::new().unwrap();
|
||||||
let supported = client.proxies().supported().get_supported_functions()?;
|
let supported = client.proxies().supported().get_supported_functions()?;
|
||||||
@@ -24,9 +26,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let mut config = UserConfig::new();
|
let mut config = UserConfig::new();
|
||||||
config.load_config()?;
|
config.load_config()?;
|
||||||
let anime = config.create_anime()?;
|
|
||||||
|
|
||||||
let config = Arc::new(Mutex::new(config));
|
let anime_config = UserAnimeConfig::load_config(config.active_anime)?;
|
||||||
|
let anime = anime_config.create_anime()?;
|
||||||
|
|
||||||
|
let anime_config = Arc::new(Mutex::new(anime_config));
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
let connection = Connection::new_session()?;
|
let connection = Connection::new_session()?;
|
||||||
@@ -44,8 +48,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
)?));
|
)?));
|
||||||
// Need new client object for dbus control part
|
// Need new client object for dbus control part
|
||||||
let (client, _) = AuraDbusClient::new().unwrap();
|
let (client, _) = AuraDbusClient::new().unwrap();
|
||||||
let anime_control =
|
let anime_control = CtrlAnime::new(
|
||||||
CtrlAnime::new(config, inner.clone(), client, &ANIME_INNER_EARLY_RETURN)?;
|
anime_config,
|
||||||
|
inner.clone(),
|
||||||
|
client,
|
||||||
|
&ANIME_INNER_EARLY_RETURN,
|
||||||
|
)?;
|
||||||
anime_control.add_to_server(&mut server);
|
anime_control.add_to_server(&mut server);
|
||||||
// Thread using inner
|
// Thread using inner
|
||||||
let _anime_thread = thread::Builder::new()
|
let _anime_thread = thread::Builder::new()
|
||||||
|
|||||||
@@ -7,3 +7,5 @@ pub mod ctrl_anime;
|
|||||||
pub mod zbus_anime;
|
pub mod zbus_anime;
|
||||||
|
|
||||||
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
||||||
|
|
||||||
|
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
+100
-21
@@ -9,14 +9,88 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct UserConfig {
|
pub struct UserAnimeConfig {
|
||||||
|
pub name: String,
|
||||||
pub anime: Vec<AnimeAction>,
|
pub anime: Vec<AnimeAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserConfig {
|
impl UserAnimeConfig {
|
||||||
pub fn new() -> Self {
|
pub fn create_anime(&self) -> Result<Sequences, Error> {
|
||||||
let x = Self {
|
let mut seq = Sequences::new();
|
||||||
|
|
||||||
|
for (idx, action) in self.anime.iter().enumerate() {
|
||||||
|
seq.insert(idx, action)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self) -> Result<(), Error> {
|
||||||
|
let mut path = if let Some(dir) = dirs::config_dir() {
|
||||||
|
dir
|
||||||
|
} else {
|
||||||
|
return Err(Error::XdgVars);
|
||||||
|
};
|
||||||
|
|
||||||
|
path.push("rog");
|
||||||
|
if !path.exists() {
|
||||||
|
create_dir(path.clone())?;
|
||||||
|
}
|
||||||
|
let name = self.name.clone();
|
||||||
|
path.push(name + ".cfg");
|
||||||
|
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&path)?;
|
||||||
|
|
||||||
|
let json = serde_json::to_string_pretty(&self).unwrap();
|
||||||
|
file.write_all(json.as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config(name: String) -> Result<UserAnimeConfig, Error> {
|
||||||
|
let mut path = if let Some(dir) = dirs::config_dir() {
|
||||||
|
dir
|
||||||
|
} else {
|
||||||
|
return Err(Error::XdgVars);
|
||||||
|
};
|
||||||
|
|
||||||
|
path.push("rog");
|
||||||
|
if !path.exists() {
|
||||||
|
create_dir(path.clone())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.push(name.clone() + ".cfg");
|
||||||
|
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&path)?;
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
|
||||||
|
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||||
|
if read_len == 0 {
|
||||||
|
let default = UserAnimeConfig { name, ..Default::default() };
|
||||||
|
let json = serde_json::to_string_pretty(&default).unwrap();
|
||||||
|
file.write_all(json.as_bytes())?;
|
||||||
|
return Ok(default);
|
||||||
|
} else if let Ok(data) = serde_json::from_str::<UserAnimeConfig>(&buf) {
|
||||||
|
return Ok(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::ConfigLoadFail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UserAnimeConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "default".to_string(),
|
||||||
anime: vec![
|
anime: vec![
|
||||||
AnimeAction::AsusAnimation {
|
AnimeAction::AsusAnimation {
|
||||||
file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(),
|
file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(),
|
||||||
@@ -48,9 +122,21 @@ impl UserConfig {
|
|||||||
time: AnimTime::Cycles(2),
|
time: AnimTime::Cycles(2),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
println!("{}", serde_json::to_string_pretty(&x).unwrap());
|
}
|
||||||
x
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
|
pub struct UserConfig {
|
||||||
|
/// Name of active anime config file in the user config directory
|
||||||
|
pub active_anime: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserConfig {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
active_anime: "anime-default".to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config(&mut self) -> Result<(), Error> {
|
pub fn load_config(&mut self) -> Result<(), Error> {
|
||||||
@@ -80,7 +166,7 @@ impl UserConfig {
|
|||||||
let json = serde_json::to_string_pretty(&self).unwrap();
|
let json = serde_json::to_string_pretty(&self).unwrap();
|
||||||
file.write_all(json.as_bytes())?;
|
file.write_all(json.as_bytes())?;
|
||||||
} else if let Ok(data) = serde_json::from_str::<UserConfig>(&buf) {
|
} else if let Ok(data) = serde_json::from_str::<UserConfig>(&buf) {
|
||||||
self.anime = data.anime;
|
self.active_anime = data.active_anime;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,21 +187,14 @@ impl UserConfig {
|
|||||||
|
|
||||||
path.push("rog-user.cfg");
|
path.push("rog-user.cfg");
|
||||||
|
|
||||||
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(&path)?;
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&path)?;
|
||||||
|
|
||||||
let json = serde_json::to_string_pretty(&self).unwrap();
|
let json = serde_json::to_string_pretty(&self).unwrap();
|
||||||
dbg!(&json);
|
|
||||||
file.write_all(json.as_bytes())?;
|
file.write_all(json.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_anime(&self) -> Result<Sequences, Error> {
|
|
||||||
let mut seq = Sequences::new();
|
|
||||||
|
|
||||||
for (idx, action) in self.anime.iter().enumerate() {
|
|
||||||
seq.insert(idx, action)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(seq)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "daemon"
|
name = "daemon"
|
||||||
version = "3.4.1"
|
version = "3.5.2"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
@@ -19,6 +19,7 @@ path = "src/daemon.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rog_anime = { path = "../rog-anime" }
|
rog_anime = { path = "../rog-anime" }
|
||||||
|
rog_aura = { path = "../rog-aura" }
|
||||||
rog_types = { path = "../rog-types" }
|
rog_types = { path = "../rog-types" }
|
||||||
rog_dbus = { path = "../rog-dbus" }
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
rusb = "^0.8"
|
rusb = "^0.8"
|
||||||
|
|||||||
+9
-15
@@ -14,8 +14,10 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub gfx_mode: GfxVendors,
|
pub gfx_mode: GfxVendors,
|
||||||
|
pub gfx_last_mode: GfxVendors,
|
||||||
pub gfx_managed: bool,
|
pub gfx_managed: bool,
|
||||||
pub gfx_vfio_enable: bool,
|
pub gfx_vfio_enable: bool,
|
||||||
|
pub gfx_save_compute_vfio: bool,
|
||||||
pub active_profile: String,
|
pub active_profile: String,
|
||||||
pub toggle_profiles: Vec<String>,
|
pub toggle_profiles: Vec<String>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
@@ -33,8 +35,10 @@ impl Default for Config {
|
|||||||
|
|
||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
|
gfx_last_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: true,
|
gfx_managed: true,
|
||||||
gfx_vfio_enable: false,
|
gfx_vfio_enable: false,
|
||||||
|
gfx_save_compute_vfio: true,
|
||||||
active_profile: "normal".into(),
|
active_profile: "normal".into(),
|
||||||
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
||||||
curr_fan_mode: 0,
|
curr_fan_mode: 0,
|
||||||
@@ -65,6 +69,11 @@ impl Config {
|
|||||||
} else {
|
} else {
|
||||||
if let Ok(data) = serde_json::from_str(&buf) {
|
if let Ok(data) = serde_json::from_str(&buf) {
|
||||||
return data;
|
return data;
|
||||||
|
} else if let Ok(data) = serde_json::from_str::<ConfigV341>(&buf) {
|
||||||
|
let config = data.into_current();
|
||||||
|
config.write();
|
||||||
|
info!("Updated config version to: {}", VERSION);
|
||||||
|
return config;
|
||||||
} else if let Ok(data) = serde_json::from_str::<ConfigV324>(&buf) {
|
} else if let Ok(data) = serde_json::from_str::<ConfigV324>(&buf) {
|
||||||
let config = data.into_current();
|
let config = data.into_current();
|
||||||
config.write();
|
config.write();
|
||||||
@@ -75,21 +84,6 @@ impl Config {
|
|||||||
config.write();
|
config.write();
|
||||||
info!("Updated config version to: {}", VERSION);
|
info!("Updated config version to: {}", VERSION);
|
||||||
return config;
|
return config;
|
||||||
} else if let Ok(data) = serde_json::from_str::<ConfigV301>(&buf) {
|
|
||||||
let config = data.into_current();
|
|
||||||
config.write();
|
|
||||||
info!("Updated config version to: {}", VERSION);
|
|
||||||
return config;
|
|
||||||
} else if let Ok(data) = serde_json::from_str::<ConfigV222>(&buf) {
|
|
||||||
let config = data.into_current();
|
|
||||||
config.write();
|
|
||||||
info!("Updated config version to: {}", VERSION);
|
|
||||||
return config;
|
|
||||||
} else if let Ok(data) = serde_json::from_str::<ConfigV212>(&buf) {
|
|
||||||
let config = data.into_current();
|
|
||||||
config.write();
|
|
||||||
info!("Updated config version to: {}", VERSION);
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
warn!("Could not deserialise {}", CONFIG_PATH);
|
warn!("Could not deserialise {}", CONFIG_PATH);
|
||||||
panic!("Please remove {} then restart asusd", CONFIG_PATH);
|
panic!("Please remove {} then restart asusd", CONFIG_PATH);
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
use crate::VERSION;
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use rog_anime::{error::AnimeError, ActionData, AnimTime, AnimeAction, Vec2};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub static ANIME_CONFIG_PATH: &str = "/etc/asusd/anime.conf";
|
||||||
|
pub static ANIME_CACHE_PATH: &str = "/etc/asusd/anime-cache.conf";
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct AnimeConfigV341 {
|
||||||
|
pub system: Option<AnimeAction>,
|
||||||
|
pub boot: Option<AnimeAction>,
|
||||||
|
pub suspend: Option<AnimeAction>,
|
||||||
|
pub shutdown: Option<AnimeAction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimeConfigV341 {
|
||||||
|
pub(crate) fn into_current(self) -> AnimeConfig {
|
||||||
|
AnimeConfig {
|
||||||
|
system: if let Some(ani) = self.system {
|
||||||
|
vec![ani]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
|
boot: if let Some(ani) = self.boot {
|
||||||
|
vec![ani]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
|
wake: if let Some(ani) = self.suspend {
|
||||||
|
vec![ani]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
|
shutdown: if let Some(ani) = self.shutdown {
|
||||||
|
vec![ani]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
|
brightness: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Default)]
|
||||||
|
pub struct AnimeConfigCached {
|
||||||
|
pub system: Vec<ActionData>,
|
||||||
|
pub boot: Vec<ActionData>,
|
||||||
|
pub wake: Vec<ActionData>,
|
||||||
|
pub shutdown: Vec<ActionData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimeConfigCached {
|
||||||
|
pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> {
|
||||||
|
let mut sys = Vec::with_capacity(config.system.len());
|
||||||
|
for ani in config.system.iter() {
|
||||||
|
sys.push(ActionData::from_anime_action(ani)?);
|
||||||
|
}
|
||||||
|
self.system = sys;
|
||||||
|
|
||||||
|
let mut boot = Vec::with_capacity(config.boot.len());
|
||||||
|
for ani in config.boot.iter() {
|
||||||
|
boot.push(ActionData::from_anime_action(ani)?);
|
||||||
|
}
|
||||||
|
self.boot = boot;
|
||||||
|
|
||||||
|
let mut wake = Vec::with_capacity(config.wake.len());
|
||||||
|
for ani in config.wake.iter() {
|
||||||
|
wake.push(ActionData::from_anime_action(ani)?);
|
||||||
|
}
|
||||||
|
self.wake = wake;
|
||||||
|
|
||||||
|
let mut shutdown = Vec::with_capacity(config.shutdown.len());
|
||||||
|
for ani in config.shutdown.iter() {
|
||||||
|
shutdown.push(ActionData::from_anime_action(ani)?);
|
||||||
|
}
|
||||||
|
self.shutdown = shutdown;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Config for base system actions for the anime display
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct AnimeConfig {
|
||||||
|
pub system: Vec<AnimeAction>,
|
||||||
|
pub boot: Vec<AnimeAction>,
|
||||||
|
pub wake: Vec<AnimeAction>,
|
||||||
|
pub shutdown: Vec<AnimeAction>,
|
||||||
|
pub brightness: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AnimeConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
AnimeConfig {
|
||||||
|
system: Vec::new(),
|
||||||
|
boot: Vec::new(),
|
||||||
|
wake: Vec::new(),
|
||||||
|
shutdown: Vec::new(),
|
||||||
|
brightness: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimeConfig {
|
||||||
|
/// `load` will attempt to read the config, and panic if the dir is missing
|
||||||
|
pub fn load() -> Self {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&ANIME_CONFIG_PATH)
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
panic!(
|
||||||
|
"The file {} or directory /etc/asusd/ is missing",
|
||||||
|
ANIME_CONFIG_PATH
|
||||||
|
)
|
||||||
|
}); // okay to cause panic here
|
||||||
|
let mut buf = String::new();
|
||||||
|
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||||
|
if read_len == 0 {
|
||||||
|
return AnimeConfig::create_default(&mut file);
|
||||||
|
} else {
|
||||||
|
if let Ok(data) = serde_json::from_str(&buf) {
|
||||||
|
return data;
|
||||||
|
} else if let Ok(data) = serde_json::from_str::<AnimeConfigV341>(&buf) {
|
||||||
|
let config = data.into_current();
|
||||||
|
config.write();
|
||||||
|
info!("Updated config version to: {}", VERSION);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
warn!("Could not deserialise {}", ANIME_CONFIG_PATH);
|
||||||
|
panic!("Please remove {} then restart asusd", ANIME_CONFIG_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimeConfig::create_default(&mut file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_default(file: &mut File) -> Self {
|
||||||
|
// create a default config here
|
||||||
|
let config = AnimeConfig {
|
||||||
|
system: vec![],
|
||||||
|
boot: vec![AnimeAction::ImageAnimation {
|
||||||
|
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
|
||||||
|
scale: 0.9,
|
||||||
|
angle: 0.65,
|
||||||
|
translation: Vec2::default(),
|
||||||
|
brightness: 1.0,
|
||||||
|
time: AnimTime::Time(Duration::from_secs(5)),
|
||||||
|
}],
|
||||||
|
wake: vec![AnimeAction::ImageAnimation {
|
||||||
|
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
|
||||||
|
scale: 0.9,
|
||||||
|
angle: 0.65,
|
||||||
|
translation: Vec2::default(),
|
||||||
|
brightness: 1.0,
|
||||||
|
time: AnimTime::Time(Duration::from_secs(5)),
|
||||||
|
}],
|
||||||
|
shutdown: vec![AnimeAction::ImageAnimation {
|
||||||
|
file: "/usr/share/asusd/anime/custom/sonic-wait.gif".into(),
|
||||||
|
scale: 0.9,
|
||||||
|
angle: 0.0,
|
||||||
|
translation: Vec2::new(3.0, 2.0),
|
||||||
|
brightness: 1.0,
|
||||||
|
time: AnimTime::Infinite,
|
||||||
|
}],
|
||||||
|
brightness: 1.0,
|
||||||
|
};
|
||||||
|
// Should be okay to unwrap this as is since it is a Default
|
||||||
|
let json = serde_json::to_string_pretty(&config).unwrap();
|
||||||
|
file.write_all(json.as_bytes())
|
||||||
|
.unwrap_or_else(|_| panic!("Could not write {}", ANIME_CONFIG_PATH));
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self) {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&ANIME_CONFIG_PATH)
|
||||||
|
.unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err));
|
||||||
|
let mut buf = String::new();
|
||||||
|
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||||
|
if l == 0 {
|
||||||
|
warn!("File is empty {}", ANIME_CONFIG_PATH);
|
||||||
|
} else {
|
||||||
|
let x: AnimeConfig = serde_json::from_str(&buf)
|
||||||
|
.unwrap_or_else(|_| panic!("Could not deserialise {}", ANIME_CONFIG_PATH));
|
||||||
|
*self = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self) {
|
||||||
|
let mut file = File::create(ANIME_CONFIG_PATH).expect("Couldn't overwrite config");
|
||||||
|
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
||||||
|
file.write_all(json.as_bytes())
|
||||||
|
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::laptops::LaptopLedData;
|
use crate::laptops::LaptopLedData;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone, LedBrightness};
|
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
@@ -146,3 +146,90 @@ impl AuraConfig {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct AuraMultiZone {
|
||||||
|
static_: [AuraEffect; 4],
|
||||||
|
breathe: [AuraEffect; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuraMultiZone {
|
||||||
|
pub fn set(&mut self, effect: AuraEffect) {
|
||||||
|
if effect.mode == AuraModeNum::Static {
|
||||||
|
match effect.zone {
|
||||||
|
AuraZone::None => {}
|
||||||
|
AuraZone::One => self.static_[0] = effect,
|
||||||
|
AuraZone::Two => self.static_[1] = effect,
|
||||||
|
AuraZone::Three => self.static_[2] = effect,
|
||||||
|
AuraZone::Four => self.static_[3] = effect,
|
||||||
|
}
|
||||||
|
} else if effect.mode == AuraModeNum::Breathe {
|
||||||
|
match effect.zone {
|
||||||
|
AuraZone::None => {}
|
||||||
|
AuraZone::One => self.breathe[0] = effect,
|
||||||
|
AuraZone::Two => self.breathe[1] = effect,
|
||||||
|
AuraZone::Three => self.breathe[2] = effect,
|
||||||
|
AuraZone::Four => self.breathe[3] = effect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn static_(&self) -> &[AuraEffect; 4] {
|
||||||
|
&self.static_
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn breathe(&self) -> &[AuraEffect; 4] {
|
||||||
|
&self.breathe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AuraMultiZone {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
static_: [
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Static,
|
||||||
|
zone: AuraZone::One,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Static,
|
||||||
|
zone: AuraZone::Two,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Static,
|
||||||
|
zone: AuraZone::Three,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Static,
|
||||||
|
zone: AuraZone::Four,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
],
|
||||||
|
breathe: [
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Breathe,
|
||||||
|
zone: AuraZone::One,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Breathe,
|
||||||
|
zone: AuraZone::Two,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Breathe,
|
||||||
|
zone: AuraZone::Three,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AuraEffect {
|
||||||
|
mode: AuraModeNum::Breathe,
|
||||||
|
zone: AuraZone::Four,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+35
-93
@@ -1,101 +1,9 @@
|
|||||||
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors, profile::Profile};
|
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
/// for parsing old v2.1.2 config
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub(crate) struct ConfigV212 {
|
|
||||||
gfx_managed: bool,
|
|
||||||
bat_charge_limit: u8,
|
|
||||||
active_profile: String,
|
|
||||||
toggle_profiles: Vec<String>,
|
|
||||||
power_profiles: BTreeMap<String, Profile>,
|
|
||||||
power_profile: u8,
|
|
||||||
kbd_led_brightness: u8,
|
|
||||||
kbd_backlight_mode: u8,
|
|
||||||
kbd_backlight_modes: Vec<AuraEffect>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConfigV212 {
|
|
||||||
pub(crate) fn into_current(self) -> Config {
|
|
||||||
Config {
|
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
|
||||||
gfx_managed: self.gfx_managed,
|
|
||||||
active_profile: self.active_profile,
|
|
||||||
gfx_vfio_enable: false,
|
|
||||||
toggle_profiles: self.toggle_profiles,
|
|
||||||
curr_fan_mode: self.power_profile,
|
|
||||||
bat_charge_limit: self.bat_charge_limit,
|
|
||||||
power_profiles: self.power_profiles,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// for parsing old v2.2.2 config
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub(crate) struct ConfigV222 {
|
|
||||||
gfx_managed: bool,
|
|
||||||
bat_charge_limit: u8,
|
|
||||||
active_profile: String,
|
|
||||||
toggle_profiles: Vec<String>,
|
|
||||||
power_profiles: BTreeMap<String, Profile>,
|
|
||||||
power_profile: u8,
|
|
||||||
kbd_led_brightness: u8,
|
|
||||||
kbd_backlight_mode: u8,
|
|
||||||
kbd_backlight_modes: Vec<AuraEffect>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConfigV222 {
|
|
||||||
pub(crate) fn into_current(self) -> Config {
|
|
||||||
Config {
|
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
|
||||||
gfx_managed: self.gfx_managed,
|
|
||||||
gfx_vfio_enable: false,
|
|
||||||
active_profile: self.active_profile,
|
|
||||||
toggle_profiles: self.toggle_profiles,
|
|
||||||
curr_fan_mode: self.power_profile,
|
|
||||||
bat_charge_limit: self.bat_charge_limit,
|
|
||||||
power_profiles: self.power_profiles,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// for parsing old v3.0.1 config
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub(crate) struct ConfigV301 {
|
|
||||||
pub gfx_managed: bool,
|
|
||||||
pub gfx_nv_mode_is_dedicated: bool,
|
|
||||||
pub active_profile: String,
|
|
||||||
pub toggle_profiles: Vec<String>,
|
|
||||||
// TODO: remove power_profile
|
|
||||||
#[serde(skip)]
|
|
||||||
pub curr_fan_mode: u8,
|
|
||||||
pub bat_charge_limit: u8,
|
|
||||||
pub kbd_led_brightness: u8,
|
|
||||||
pub kbd_backlight_mode: u8,
|
|
||||||
pub kbd_backlight_modes: Vec<AuraEffect>,
|
|
||||||
pub power_profiles: BTreeMap<String, Profile>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConfigV301 {
|
|
||||||
pub(crate) fn into_current(self) -> Config {
|
|
||||||
Config {
|
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
|
||||||
gfx_managed: self.gfx_managed,
|
|
||||||
gfx_vfio_enable: false,
|
|
||||||
active_profile: self.active_profile,
|
|
||||||
toggle_profiles: self.toggle_profiles,
|
|
||||||
curr_fan_mode: self.curr_fan_mode,
|
|
||||||
bat_charge_limit: self.bat_charge_limit,
|
|
||||||
power_profiles: self.power_profiles,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// for parsing old v3.1.7 config
|
/// for parsing old v3.1.7 config
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub(crate) struct ConfigV317 {
|
pub(crate) struct ConfigV317 {
|
||||||
@@ -117,8 +25,10 @@ impl ConfigV317 {
|
|||||||
pub(crate) fn into_current(self) -> Config {
|
pub(crate) fn into_current(self) -> Config {
|
||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
|
gfx_last_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: self.gfx_managed,
|
gfx_managed: self.gfx_managed,
|
||||||
gfx_vfio_enable: false,
|
gfx_vfio_enable: false,
|
||||||
|
gfx_save_compute_vfio: false,
|
||||||
active_profile: self.active_profile,
|
active_profile: self.active_profile,
|
||||||
toggle_profiles: self.toggle_profiles,
|
toggle_profiles: self.toggle_profiles,
|
||||||
curr_fan_mode: self.curr_fan_mode,
|
curr_fan_mode: self.curr_fan_mode,
|
||||||
@@ -144,8 +54,40 @@ impl ConfigV324 {
|
|||||||
pub(crate) fn into_current(self) -> Config {
|
pub(crate) fn into_current(self) -> Config {
|
||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
|
gfx_last_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: self.gfx_managed,
|
gfx_managed: self.gfx_managed,
|
||||||
gfx_vfio_enable: false,
|
gfx_vfio_enable: false,
|
||||||
|
gfx_save_compute_vfio: false,
|
||||||
|
active_profile: self.active_profile,
|
||||||
|
toggle_profiles: self.toggle_profiles,
|
||||||
|
curr_fan_mode: self.curr_fan_mode,
|
||||||
|
bat_charge_limit: self.bat_charge_limit,
|
||||||
|
power_profiles: self.power_profiles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct ConfigV341 {
|
||||||
|
pub gfx_mode: GfxVendors,
|
||||||
|
pub gfx_managed: bool,
|
||||||
|
pub gfx_vfio_enable: bool,
|
||||||
|
pub active_profile: String,
|
||||||
|
pub toggle_profiles: Vec<String>,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub curr_fan_mode: u8,
|
||||||
|
pub bat_charge_limit: u8,
|
||||||
|
pub power_profiles: BTreeMap<String, Profile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigV341 {
|
||||||
|
pub(crate) fn into_current(self) -> Config {
|
||||||
|
Config {
|
||||||
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
|
gfx_last_mode: GfxVendors::Hybrid,
|
||||||
|
gfx_managed: self.gfx_managed,
|
||||||
|
gfx_vfio_enable: false,
|
||||||
|
gfx_save_compute_vfio: false,
|
||||||
active_profile: self.active_profile,
|
active_profile: self.active_profile,
|
||||||
toggle_profiles: self.toggle_profiles,
|
toggle_profiles: self.toggle_profiles,
|
||||||
curr_fan_mode: self.curr_fan_mode,
|
curr_fan_mode: self.curr_fan_mode,
|
||||||
|
|||||||
+342
-45
@@ -1,69 +1,56 @@
|
|||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
use logind_zbus::ManagerProxy;
|
||||||
use rog_anime::{
|
use rog_anime::{
|
||||||
usb::{
|
usb::{
|
||||||
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
|
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
|
||||||
VENDOR_ID,
|
VENDOR_ID,
|
||||||
},
|
},
|
||||||
AnimeDataBuffer, AnimePacketType,
|
ActionData, AnimTime, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN,
|
||||||
};
|
};
|
||||||
use rog_types::supported::AnimeSupportedFunctions;
|
use rog_types::supported::AnimeSupportedFunctions;
|
||||||
use rusb::{Device, DeviceHandle};
|
use rusb::{Device, DeviceHandle};
|
||||||
use std::error::Error;
|
use std::{
|
||||||
use std::time::Duration;
|
error::Error,
|
||||||
use zbus::dbus_interface;
|
sync::{Arc, Mutex},
|
||||||
|
thread::sleep,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
use zbus::{dbus_interface, Connection};
|
||||||
use zvariant::ObjectPath;
|
use zvariant::ObjectPath;
|
||||||
|
|
||||||
use crate::GetSupported;
|
use crate::{
|
||||||
|
config_anime::{AnimeConfig, AnimeConfigCached},
|
||||||
|
error::RogError,
|
||||||
|
GetSupported,
|
||||||
|
};
|
||||||
|
|
||||||
impl GetSupported for CtrlAnimeDisplay {
|
impl GetSupported for CtrlAnime {
|
||||||
type A = AnimeSupportedFunctions;
|
type A = AnimeSupportedFunctions;
|
||||||
|
|
||||||
fn get_supported() -> Self::A {
|
fn get_supported() -> Self::A {
|
||||||
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(VENDOR_ID, PROD_ID).is_ok())
|
AnimeSupportedFunctions(CtrlAnime::get_device(VENDOR_ID, PROD_ID).is_ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CtrlAnimeDisplay {
|
pub struct CtrlAnime {
|
||||||
handle: DeviceHandle<rusb::GlobalContext>,
|
handle: DeviceHandle<rusb::GlobalContext>,
|
||||||
|
cache: AnimeConfigCached,
|
||||||
|
config: AnimeConfig,
|
||||||
|
// set to force thread to exit
|
||||||
|
thread_exit: Arc<AtomicBool>,
|
||||||
|
// Set to false when the thread exits
|
||||||
|
thread_running: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ZbusAdd for CtrlAnimeDisplay {
|
impl CtrlAnime {
|
||||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
|
||||||
server
|
|
||||||
.at(
|
|
||||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!("CtrlAnimeDisplay: add_to_server {}", err);
|
|
||||||
err
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
|
||||||
impl CtrlAnimeDisplay {
|
|
||||||
/// Writes a data stream of length
|
|
||||||
fn write(&self, input: AnimeDataBuffer) {
|
|
||||||
self.write_data_buffer(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_on_off(&self, status: bool) {
|
|
||||||
self.write_bytes(&pkt_for_set_on(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_boot_on_off(&self, on: bool) {
|
|
||||||
self.write_bytes(&pkt_for_set_boot(on));
|
|
||||||
self.write_bytes(&pkt_for_apply());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CtrlAnimeDisplay {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Result<CtrlAnimeDisplay, Box<dyn Error>> {
|
pub fn new(config: AnimeConfig) -> Result<CtrlAnime, Box<dyn Error>> {
|
||||||
// We don't expect this ID to ever change
|
// We don't expect this ID to ever change
|
||||||
let device = CtrlAnimeDisplay::get_device(0x0b05, 0x193b)?;
|
let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
|
||||||
|
|
||||||
let mut device = device.open()?;
|
let mut device = device.open()?;
|
||||||
device.reset()?;
|
device.reset()?;
|
||||||
@@ -79,7 +66,16 @@ impl CtrlAnimeDisplay {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("Device has an AniMe Matrix display");
|
info!("Device has an AniMe Matrix display");
|
||||||
let ctrl = CtrlAnimeDisplay { handle: device };
|
let mut cache = AnimeConfigCached::default();
|
||||||
|
cache.init_from_config(&config)?;
|
||||||
|
|
||||||
|
let ctrl = CtrlAnime {
|
||||||
|
handle: device,
|
||||||
|
cache,
|
||||||
|
config,
|
||||||
|
thread_exit: Arc::new(AtomicBool::new(false)),
|
||||||
|
thread_running: Arc::new(AtomicBool::new(false)),
|
||||||
|
};
|
||||||
ctrl.do_initialization();
|
ctrl.do_initialization();
|
||||||
|
|
||||||
Ok(ctrl)
|
Ok(ctrl)
|
||||||
@@ -95,6 +91,117 @@ impl CtrlAnimeDisplay {
|
|||||||
Err(rusb::Error::NoDevice)
|
Err(rusb::Error::NoDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start an action thread. This is classed as a singleton and there should be only
|
||||||
|
/// one running - so the thread uses atomics to signal run/exit.
|
||||||
|
///
|
||||||
|
/// Because this also writes to the usb device, other write tries (display only) *must*
|
||||||
|
/// get the mutex lock and set the thread_exit atomic.
|
||||||
|
fn run_thread(inner: Arc<Mutex<CtrlAnime>>, actions: Vec<ActionData>, mut once: bool) {
|
||||||
|
if actions.is_empty() {
|
||||||
|
warn!("AniMe system actions was empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Loop rules:
|
||||||
|
// - Lock the mutex **only when required**. That is, the lock must be held for the shortest duration possible.
|
||||||
|
// - An AtomicBool used for thread exit should be checked in every loop, including nested
|
||||||
|
|
||||||
|
// The only reason for this outer thread is to prevent blocking while waiting for the
|
||||||
|
// next spawned thread to exit
|
||||||
|
std::thread::Builder::new()
|
||||||
|
.name("AniMe system thread start".into())
|
||||||
|
.spawn(move || {
|
||||||
|
info!("AniMe system thread started");
|
||||||
|
// Getting copies of these Atomics is done *in* the thread to ensure
|
||||||
|
// we don't block other threads/main
|
||||||
|
let thread_exit;
|
||||||
|
let thread_running;
|
||||||
|
// First two loops are to ensure we *do* aquire a lock on the mutex
|
||||||
|
// The reason the loop is required is because the USB writes can block
|
||||||
|
// for up to 10ms. We can't fail to get the atomics.
|
||||||
|
loop {
|
||||||
|
if let Ok(lock) = inner.try_lock() {
|
||||||
|
thread_exit = lock.thread_exit.clone();
|
||||||
|
thread_running = lock.thread_running.clone();
|
||||||
|
// Make any running loop exit first
|
||||||
|
thread_exit.store(true, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// wait for other threads to set not running so we know they exited
|
||||||
|
if !thread_running.load(Ordering::SeqCst) {
|
||||||
|
thread_exit.store(false, Ordering::SeqCst);
|
||||||
|
info!("AniMe forced a thread to exit");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'main: loop {
|
||||||
|
if thread_exit.load(Ordering::SeqCst) {
|
||||||
|
break 'main;
|
||||||
|
}
|
||||||
|
for action in actions.iter() {
|
||||||
|
match action {
|
||||||
|
ActionData::Animation(frames) => {
|
||||||
|
let mut count = 0;
|
||||||
|
let start = Instant::now();
|
||||||
|
'animation: loop {
|
||||||
|
for frame in frames.frames() {
|
||||||
|
if let Ok(lock) = inner.try_lock() {
|
||||||
|
lock.write_data_buffer(frame.frame().clone());
|
||||||
|
}
|
||||||
|
if let AnimTime::Time(time) = frames.duration() {
|
||||||
|
if Instant::now().duration_since(start) > time {
|
||||||
|
break 'animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sleep(frame.delay());
|
||||||
|
// Need to check for early exit condition here or it might run
|
||||||
|
// until end of gif or time
|
||||||
|
if thread_exit.load(Ordering::SeqCst) {
|
||||||
|
break 'main;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let AnimTime::Cycles(times) = frames.duration() {
|
||||||
|
count += 1;
|
||||||
|
if count >= times {
|
||||||
|
break 'animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActionData::Image(image) => {
|
||||||
|
once = false;
|
||||||
|
if let Ok(lock) = inner.try_lock() {
|
||||||
|
lock.write_data_buffer(image.as_ref().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActionData::Pause(duration) => sleep(*duration),
|
||||||
|
ActionData::AudioEq => {}
|
||||||
|
ActionData::SystemInfo => {}
|
||||||
|
ActionData::TimeDate => {}
|
||||||
|
ActionData::Matrix => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if once || actions.is_empty() {
|
||||||
|
break 'main;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clear the display on exit
|
||||||
|
if let Ok(lock) = inner.try_lock() {
|
||||||
|
let data = AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec());
|
||||||
|
lock.write_data_buffer(data);
|
||||||
|
}
|
||||||
|
// Loop ended, set the atmonics
|
||||||
|
thread_exit.store(false, Ordering::SeqCst);
|
||||||
|
thread_running.store(false, Ordering::SeqCst);
|
||||||
|
info!("AniMe system thread exited");
|
||||||
|
})
|
||||||
|
.map(|err| info!("AniMe system thread: {:?}", err))
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
fn write_bytes(&self, message: &[u8]) {
|
fn write_bytes(&self, message: &[u8]) {
|
||||||
match self.handle.write_control(
|
match self.handle.write_control(
|
||||||
0x21, // request_type
|
0x21, // request_type
|
||||||
@@ -112,7 +219,16 @@ impl CtrlAnimeDisplay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_data_buffer(&self, buffer: AnimeDataBuffer) {
|
/// Write only a data packet. This will modify the leds brightness using the
|
||||||
|
/// global brightness set in config.
|
||||||
|
fn write_data_buffer(&self, mut buffer: AnimeDataBuffer) {
|
||||||
|
for led in buffer.get_mut()[7..].iter_mut() {
|
||||||
|
let mut bright = *led as f32 * self.config.brightness;
|
||||||
|
if bright > 254.0 {
|
||||||
|
bright = 254.0;
|
||||||
|
}
|
||||||
|
*led = bright as u8;
|
||||||
|
}
|
||||||
let data = AnimePacketType::from(buffer);
|
let data = AnimePacketType::from(buffer);
|
||||||
for row in data.iter() {
|
for row in data.iter() {
|
||||||
self.write_bytes(row);
|
self.write_bytes(row);
|
||||||
@@ -126,3 +242,184 @@ impl CtrlAnimeDisplay {
|
|||||||
self.write_bytes(&pkts[1]);
|
self.write_bytes(&pkts[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CtrlAnimeTask<'a> {
|
||||||
|
inner: Arc<Mutex<CtrlAnime>>,
|
||||||
|
_c: Connection,
|
||||||
|
manager: ManagerProxy<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CtrlAnimeTask<'a> {
|
||||||
|
pub fn new(inner: Arc<Mutex<CtrlAnime>>) -> Self {
|
||||||
|
let connection = Connection::new_system().unwrap();
|
||||||
|
|
||||||
|
let manager = ManagerProxy::new(&connection).unwrap();
|
||||||
|
|
||||||
|
let c1 = inner.clone();
|
||||||
|
// Run this action when the system starts shutting down
|
||||||
|
manager
|
||||||
|
.connect_prepare_for_shutdown(move |shutdown| {
|
||||||
|
if shutdown {
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(lock) = c1.try_lock() {
|
||||||
|
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||||
|
CtrlAnime::run_thread(c1.clone(), lock.cache.shutdown.clone(), false);
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlAnimeTask: new() {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
let c1 = inner.clone();
|
||||||
|
// Run this action when the system wakes up from sleep
|
||||||
|
manager
|
||||||
|
.connect_prepare_for_sleep(move |sleep| {
|
||||||
|
if !sleep {
|
||||||
|
// wait a fraction for things to wake up properly
|
||||||
|
std::thread::sleep(Duration::from_millis(100));
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(lock) = c1.try_lock() {
|
||||||
|
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||||
|
CtrlAnime::run_thread(c1.clone(), lock.cache.wake.clone(), true);
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlAnimeTask: new() {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
_c: connection,
|
||||||
|
manager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> crate::CtrlTask for CtrlAnimeTask<'a> {
|
||||||
|
fn do_task(&self) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut lock) = self.inner.try_lock() {
|
||||||
|
// Refresh the config and cache incase the user has edited it
|
||||||
|
let config = AnimeConfig::load();
|
||||||
|
lock.cache
|
||||||
|
.init_from_config(&config)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlAnimeTask: do_task {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for signals on each task iteration, this will run the callbacks
|
||||||
|
// if any signal is recieved
|
||||||
|
self.manager.next_signal()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CtrlAnimeReloader(pub Arc<Mutex<CtrlAnime>>);
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlAnimeReloader {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
if let Ok(lock) = self.0.try_lock() {
|
||||||
|
let action = lock.cache.boot.clone();
|
||||||
|
CtrlAnime::run_thread(self.0.clone(), action, true);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
|
||||||
|
|
||||||
|
/// The struct with the main dbus methods requires this trait
|
||||||
|
impl crate::ZbusAdd for CtrlAnimeZbus {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(
|
||||||
|
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlAnimeDisplay: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of these calls can be guarnateed to succeed unless we loop until okay
|
||||||
|
// If the try_lock *does* succeed then any other thread trying to lock will not grab it
|
||||||
|
// until we finish.
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl CtrlAnimeZbus {
|
||||||
|
/// Writes a data stream of length. Will force system thread to exit until it is restarted
|
||||||
|
fn write(&self, input: AnimeDataBuffer) {
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(lock) = self.0.try_lock() {
|
||||||
|
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||||
|
lock.write_data_buffer(input);
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_brightness(&self, bright: f32) {
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(mut lock) = self.0.try_lock() {
|
||||||
|
let mut bright = bright;
|
||||||
|
if bright < 0.0 {
|
||||||
|
bright = 0.0
|
||||||
|
} else if bright > 254.0 {
|
||||||
|
bright = 254.0;
|
||||||
|
}
|
||||||
|
lock.config.brightness = bright;
|
||||||
|
lock.config.write();
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_on_off(&self, status: bool) {
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(lock) = self.0.try_lock() {
|
||||||
|
lock.write_bytes(&pkt_for_set_on(status));
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_boot_on_off(&self, on: bool) {
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(lock) = self.0.try_lock() {
|
||||||
|
lock.write_bytes(&pkt_for_set_boot(on));
|
||||||
|
lock.write_bytes(&pkt_for_apply());
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The main loop is the base system set action if the user isn't running
|
||||||
|
/// the user daemon
|
||||||
|
fn run_main_loop(&self, start: bool) {
|
||||||
|
if start {
|
||||||
|
'outer: loop {
|
||||||
|
if let Ok(lock) = self.0.try_lock() {
|
||||||
|
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||||
|
CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false);
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use ::zbus::Connection;
|
||||||
use ctrl_gfx::error::GfxError;
|
use ctrl_gfx::error::GfxError;
|
||||||
use ctrl_gfx::*;
|
use ctrl_gfx::*;
|
||||||
use ctrl_rog_bios::CtrlRogBios;
|
use ctrl_rog_bios::CtrlRogBios;
|
||||||
@@ -14,8 +15,6 @@ use std::{str::FromStr, sync::mpsc};
|
|||||||
use std::{sync::Arc, sync::Mutex};
|
use std::{sync::Arc, sync::Mutex};
|
||||||
use sysfs_class::{PciDevice, SysClass};
|
use sysfs_class::{PciDevice, SysClass};
|
||||||
use system::{GraphicsDevice, PciBus};
|
use system::{GraphicsDevice, PciBus};
|
||||||
use zbus::{dbus_interface, Connection};
|
|
||||||
use zvariant::ObjectPath;
|
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
@@ -32,62 +31,6 @@ pub struct CtrlGraphics {
|
|||||||
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
|
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dbus {
|
|
||||||
fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
|
|
||||||
fn power(&self) -> zbus::fdo::Result<GfxPower>;
|
|
||||||
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction>;
|
|
||||||
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()>;
|
|
||||||
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
|
||||||
impl Dbus for CtrlGraphics {
|
|
||||||
fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
|
|
||||||
self.get_gfx_mode().map_err(|err| {
|
|
||||||
error!("GFX: {}", err);
|
|
||||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn power(&self) -> zbus::fdo::Result<GfxPower> {
|
|
||||||
Self::get_runtime_status().map_err(|err| {
|
|
||||||
error!("GFX: {}", err);
|
|
||||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
|
|
||||||
info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
|
|
||||||
let msg = self.set_gfx_config(vendor).map_err(|err| {
|
|
||||||
error!("GFX: {}", err);
|
|
||||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
|
||||||
})?;
|
|
||||||
self.notify_gfx(&vendor)
|
|
||||||
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
|
||||||
self.notify_action(&msg)
|
|
||||||
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
|
||||||
Ok(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
|
||||||
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {}
|
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
|
||||||
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZbusAdd for CtrlGraphics {
|
|
||||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
|
||||||
server
|
|
||||||
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!("GFX: CtrlGraphics: add_to_server {}", err);
|
|
||||||
err
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reloadable for CtrlGraphics {
|
impl Reloadable for CtrlGraphics {
|
||||||
fn reload(&mut self) -> Result<(), RogError> {
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
self.auto_power()?;
|
self.auto_power()?;
|
||||||
@@ -168,6 +111,7 @@ impl CtrlGraphics {
|
|||||||
/// Save the selected `Vendor` mode to config
|
/// Save the selected `Vendor` mode to config
|
||||||
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
|
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
|
||||||
if let Ok(mut config) = config.lock() {
|
if let Ok(mut config) = config.lock() {
|
||||||
|
config.gfx_last_mode = config.gfx_mode;
|
||||||
config.gfx_mode = vendor;
|
config.gfx_mode = vendor;
|
||||||
config.write();
|
config.write();
|
||||||
}
|
}
|
||||||
@@ -182,7 +126,7 @@ impl CtrlGraphics {
|
|||||||
Ok(GfxVendors::Hybrid)
|
Ok(GfxVendors::Hybrid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_runtime_status() -> Result<GfxPower, RogError> {
|
pub(super) fn get_runtime_status() -> Result<GfxPower, RogError> {
|
||||||
let path = Path::new("/sys/bus/pci/devices/0000:01:00.0/power/runtime_status");
|
let path = Path::new("/sys/bus/pci/devices/0000:01:00.0/power/runtime_status");
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
let buf = std::fs::read_to_string(path).map_err(|err| {
|
let buf = std::fs::read_to_string(path).map_err(|err| {
|
||||||
@@ -281,10 +225,14 @@ impl CtrlGraphics {
|
|||||||
fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> {
|
fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> {
|
||||||
info!("GFX: Writing {}", MODPROBE_PATH);
|
info!("GFX: Writing {}", MODPROBE_PATH);
|
||||||
let content = match vendor {
|
let content = match vendor {
|
||||||
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => MODPROBE_BASE.to_vec(),
|
GfxVendors::Nvidia | GfxVendors::Hybrid => {
|
||||||
|
let mut base = MODPROBE_BASE.to_vec();
|
||||||
|
base.append(&mut MODPROBE_DRM_MODESET.to_vec());
|
||||||
|
base
|
||||||
|
}
|
||||||
GfxVendors::Vfio => Self::get_vfio_conf(devices),
|
GfxVendors::Vfio => Self::get_vfio_conf(devices),
|
||||||
// GfxVendors::Compute => {}
|
|
||||||
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
|
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
|
||||||
|
GfxVendors::Compute => MODPROBE_BASE.to_vec(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut file = std::fs::OpenOptions::new()
|
let mut file = std::fs::OpenOptions::new()
|
||||||
@@ -418,9 +366,13 @@ impl CtrlGraphics {
|
|||||||
fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
|
fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
|
||||||
if let Ok(config) = self.config.lock() {
|
if let Ok(config) = self.config.lock() {
|
||||||
let current = config.gfx_mode;
|
let current = config.gfx_mode;
|
||||||
if matches!(current, GfxVendors::Integrated | GfxVendors::Vfio)
|
if matches!(
|
||||||
&& matches!(vendor, GfxVendors::Integrated | GfxVendors::Vfio)
|
current,
|
||||||
{
|
GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute
|
||||||
|
) && matches!(
|
||||||
|
vendor,
|
||||||
|
GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute
|
||||||
|
) {
|
||||||
return GfxRequiredUserAction::None;
|
return GfxRequiredUserAction::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -655,6 +607,16 @@ impl CtrlGraphics {
|
|||||||
let bus = self.bus.clone();
|
let bus = self.bus.clone();
|
||||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||||
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
||||||
|
if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio) {
|
||||||
|
loop {
|
||||||
|
if let Ok(config) = self.config.try_lock() {
|
||||||
|
if config.gfx_save_compute_vfio {
|
||||||
|
Self::save_gfx_mode(vendor, self.config.clone());
|
||||||
|
}
|
||||||
|
return Ok(action_required);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: undo if failed? Save last mode, catch errors...
|
// TODO: undo if failed? Save last mode, catch errors...
|
||||||
Ok(action_required)
|
Ok(action_required)
|
||||||
@@ -666,7 +628,7 @@ impl CtrlGraphics {
|
|||||||
let devices = self.nvidia.clone();
|
let devices = self.nvidia.clone();
|
||||||
let bus = self.bus.clone();
|
let bus = self.bus.clone();
|
||||||
|
|
||||||
let vfio_enable = if let Ok(config) = self.config.lock() {
|
let vfio_enable = if let Ok(config) = self.config.try_lock() {
|
||||||
config.gfx_vfio_enable
|
config.gfx_vfio_enable
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub mod gfx;
|
pub mod controller;
|
||||||
|
|
||||||
pub mod system;
|
pub mod system;
|
||||||
|
|
||||||
|
pub mod zbus_gfx;
|
||||||
|
|
||||||
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
|
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
|
||||||
|
|
||||||
const VFIO_DRIVERS: [&str; 5] = [
|
const VFIO_DRIVERS: [&str; 5] = [
|
||||||
@@ -26,6 +28,9 @@ static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
|
|||||||
blacklist nouveau
|
blacklist nouveau
|
||||||
alias nouveau off
|
alias nouveau off
|
||||||
options nvidia NVreg_DynamicPowerManagement=0x02
|
options nvidia NVreg_DynamicPowerManagement=0x02
|
||||||
|
"#;
|
||||||
|
|
||||||
|
static MODPROBE_DRM_MODESET: &[u8] = br#"
|
||||||
options nvidia-drm modeset=1
|
options nvidia-drm modeset=1
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
|
||||||
|
use ::zbus::{dbus_interface};
|
||||||
|
use zvariant::ObjectPath;
|
||||||
|
use log::{error, warn, info};
|
||||||
|
|
||||||
|
use crate::ZbusAdd;
|
||||||
|
|
||||||
|
use super::controller::CtrlGraphics;
|
||||||
|
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl CtrlGraphics {
|
||||||
|
fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
|
||||||
|
self.get_gfx_mode().map_err(|err| {
|
||||||
|
error!("GFX: {}", err);
|
||||||
|
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn power(&self) -> zbus::fdo::Result<GfxPower> {
|
||||||
|
Self::get_runtime_status().map_err(|err| {
|
||||||
|
error!("GFX: {}", err);
|
||||||
|
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
|
||||||
|
info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
|
||||||
|
let msg = self.set_gfx_config(vendor).map_err(|err| {
|
||||||
|
error!("GFX: {}", err);
|
||||||
|
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||||
|
})?;
|
||||||
|
self.notify_gfx(&vendor)
|
||||||
|
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||||
|
self.notify_action(&msg)
|
||||||
|
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZbusAdd for CtrlGraphics {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("GFX: CtrlGraphics: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
-85
@@ -1,7 +1,4 @@
|
|||||||
// Only these two packets must be 17 bytes
|
// Only these two packets must be 17 bytes
|
||||||
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
||||||
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
||||||
|
|
||||||
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
|
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -10,7 +7,11 @@ use crate::{
|
|||||||
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
||||||
};
|
};
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_types::{LED_MSG_LEN, aura_modes::{AuraEffect, AuraModeNum, LedBrightness}, supported::LedSupportedFunctions};
|
use rog_aura::{
|
||||||
|
usb::{LED_APPLY, LED_AWAKE_OFF, LED_AWAKE_ON, LED_SET, LED_SLEEP_OFF, LED_SLEEP_ON},
|
||||||
|
AuraEffect, LedBrightness, LED_MSG_LEN,
|
||||||
|
};
|
||||||
|
use rog_types::supported::LedSupportedFunctions;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -21,7 +22,7 @@ use zvariant::ObjectPath;
|
|||||||
|
|
||||||
use crate::GetSupported;
|
use crate::GetSupported;
|
||||||
|
|
||||||
impl GetSupported for CtrlKbdBacklight {
|
impl GetSupported for CtrlKbdLed {
|
||||||
type A = LedSupportedFunctions;
|
type A = LedSupportedFunctions;
|
||||||
|
|
||||||
fn get_supported() -> Self::A {
|
fn get_supported() -> Self::A {
|
||||||
@@ -36,7 +37,7 @@ impl GetSupported for CtrlKbdBacklight {
|
|||||||
};
|
};
|
||||||
|
|
||||||
LedSupportedFunctions {
|
LedSupportedFunctions {
|
||||||
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_some(),
|
brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(),
|
||||||
stock_led_modes,
|
stock_led_modes,
|
||||||
multizone_led_mode,
|
multizone_led_mode,
|
||||||
per_key_led_mode,
|
per_key_led_mode,
|
||||||
@@ -44,7 +45,7 @@ impl GetSupported for CtrlKbdBacklight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CtrlKbdBacklight {
|
pub struct CtrlKbdLed {
|
||||||
led_node: Option<String>,
|
led_node: Option<String>,
|
||||||
pub bright_node: String,
|
pub bright_node: String,
|
||||||
supported_modes: LaptopLedData,
|
supported_modes: LaptopLedData,
|
||||||
@@ -52,22 +53,67 @@ pub struct CtrlKbdBacklight {
|
|||||||
config: AuraConfig,
|
config: AuraConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DbusKbdBacklight {
|
pub struct CtrlKbdLedTask(pub Arc<Mutex<CtrlKbdLed>>);
|
||||||
inner: Arc<Mutex<CtrlKbdBacklight>>,
|
|
||||||
|
impl crate::CtrlTask for CtrlKbdLedTask {
|
||||||
|
fn do_task(&self) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut lock) = self.0.try_lock() {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&lock.bright_node)
|
||||||
|
.map_err(|err| match err.kind() {
|
||||||
|
std::io::ErrorKind::NotFound => {
|
||||||
|
RogError::MissingLedBrightNode((&lock.bright_node).into(), err)
|
||||||
|
}
|
||||||
|
_ => RogError::Path((&lock.bright_node).into(), err),
|
||||||
|
})?;
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
file.read_exact(&mut buf)
|
||||||
|
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||||
|
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
||||||
|
if lock.config.brightness != num.into() {
|
||||||
|
lock.config.read();
|
||||||
|
lock.config.brightness = num.into();
|
||||||
|
lock.config.write();
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
return Err(RogError::ParseLed);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbusKbdBacklight {
|
pub struct CtrlKbdLedReloader(pub Arc<Mutex<CtrlKbdLed>>);
|
||||||
pub fn new(inner: Arc<Mutex<CtrlKbdBacklight>>) -> Self {
|
|
||||||
|
impl crate::Reloadable for CtrlKbdLedReloader {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut lock) = self.0.try_lock() {
|
||||||
|
let current = lock.config.current_mode;
|
||||||
|
if let Some(mode) = lock.config.builtins.get(¤t).cloned() {
|
||||||
|
lock.do_command(mode).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CtrlKbdLedZbus {
|
||||||
|
inner: Arc<Mutex<CtrlKbdLed>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlKbdLedZbus {
|
||||||
|
pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self {
|
||||||
Self { inner }
|
Self { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ZbusAdd for DbusKbdBacklight {
|
impl crate::ZbusAdd for CtrlKbdLedZbus {
|
||||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
server
|
server
|
||||||
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self)
|
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!("DbusKbdBacklight: add_to_server {}", err);
|
error!("DbusKbdLed: add_to_server {}", err);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
@@ -77,7 +123,8 @@ impl crate::ZbusAdd for DbusKbdBacklight {
|
|||||||
///
|
///
|
||||||
/// LED commands are split between Brightness, Modes, Per-Key
|
/// LED commands are split between Brightness, Modes, Per-Key
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
impl DbusKbdBacklight {
|
impl CtrlKbdLedZbus {
|
||||||
|
/// Set the keyboard brightness level (0-3)
|
||||||
fn set_brightness(&mut self, brightness: LedBrightness) {
|
fn set_brightness(&mut self, brightness: LedBrightness) {
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
ctrl.set_brightness(brightness)
|
ctrl.set_brightness(brightness)
|
||||||
@@ -86,6 +133,24 @@ impl DbusKbdBacklight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the keyboard LED to enabled while the device is awake
|
||||||
|
fn set_awake_enabled(&mut self, enabled: bool) {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
ctrl.set_awake_enable(enabled)
|
||||||
|
.map_err(|err| warn!("{}", err))
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the keyboard LED suspend animation to enabled while the device is suspended
|
||||||
|
fn set_sleep_enabled(&mut self, enabled: bool) {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
ctrl.set_sleep_anim_enable(enabled)
|
||||||
|
.map_err(|err| warn!("{}", err))
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_led_mode(&mut self, effect: AuraEffect) {
|
fn set_led_mode(&mut self, effect: AuraEffect) {
|
||||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
let mode_name = effect.mode_name();
|
let mode_name = effect.mode_name();
|
||||||
@@ -168,74 +233,7 @@ impl DbusKbdBacklight {
|
|||||||
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Reloadable for CtrlKbdBacklight {
|
impl CtrlKbdLed {
|
||||||
fn reload(&mut self) -> Result<(), RogError> {
|
|
||||||
// set current mode (if any)
|
|
||||||
if self.supported_modes.standard.len() > 1 {
|
|
||||||
let current_mode = self.config.current_mode;
|
|
||||||
if self.supported_modes.standard.contains(&(current_mode)) {
|
|
||||||
let mode = self
|
|
||||||
.config
|
|
||||||
.builtins
|
|
||||||
.get(¤t_mode)
|
|
||||||
.ok_or(RogError::NotSupported)?
|
|
||||||
.to_owned();
|
|
||||||
self.write_mode(&mode)?;
|
|
||||||
info!("Reloaded last used mode");
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"An unsupported mode was set: {}, reset to first mode available",
|
|
||||||
<&str>::from(&self.config.current_mode)
|
|
||||||
);
|
|
||||||
self.config.builtins.remove(¤t_mode);
|
|
||||||
self.config.current_mode = AuraModeNum::Static;
|
|
||||||
// TODO: do a recursive call with a boxed dyn future later
|
|
||||||
let mode = self
|
|
||||||
.config
|
|
||||||
.builtins
|
|
||||||
.get(¤t_mode)
|
|
||||||
.ok_or(RogError::NotSupported)?
|
|
||||||
.to_owned();
|
|
||||||
self.write_mode(&mode)?;
|
|
||||||
info!("Reloaded last used mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload brightness
|
|
||||||
let bright = self.config.brightness;
|
|
||||||
self.set_brightness(bright)?;
|
|
||||||
info!("Reloaded last used brightness");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::CtrlTask for CtrlKbdBacklight {
|
|
||||||
fn do_task(&mut self) -> Result<(), RogError> {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.open(&self.bright_node)
|
|
||||||
.map_err(|err| match err.kind() {
|
|
||||||
std::io::ErrorKind::NotFound => {
|
|
||||||
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
|
|
||||||
}
|
|
||||||
_ => RogError::Path((&self.bright_node).into(), err),
|
|
||||||
})?;
|
|
||||||
let mut buf = [0u8; 1];
|
|
||||||
file.read_exact(&mut buf)
|
|
||||||
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
|
||||||
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
|
||||||
if self.config.brightness != num.into() {
|
|
||||||
self.config.read();
|
|
||||||
self.config.brightness = num.into();
|
|
||||||
self.config.write();
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Err(RogError::ParseLed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CtrlKbdBacklight {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
|
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
|
||||||
// TODO: return error if *all* nodes are None
|
// TODO: return error if *all* nodes are None
|
||||||
@@ -265,7 +263,7 @@ impl CtrlKbdBacklight {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctrl = CtrlKbdBacklight {
|
let ctrl = CtrlKbdLed {
|
||||||
led_node,
|
led_node,
|
||||||
bright_node: bright_node.unwrap(), // If was none then we already returned above
|
bright_node: bright_node.unwrap(), // If was none then we already returned above
|
||||||
supported_modes,
|
supported_modes,
|
||||||
@@ -282,7 +280,7 @@ impl CtrlKbdBacklight {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brightness(&self) -> Result<u8, RogError> {
|
fn get_brightness(&self) -> Result<u8, RogError> {
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(&self.bright_node)
|
.open(&self.bright_node)
|
||||||
@@ -298,7 +296,7 @@ impl CtrlKbdBacklight {
|
|||||||
Ok(buf[0])
|
Ok(buf[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
|
fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
|
||||||
let path = Path::new(&self.bright_node);
|
let path = Path::new(&self.bright_node);
|
||||||
let mut file =
|
let mut file =
|
||||||
OpenOptions::new()
|
OpenOptions::new()
|
||||||
@@ -315,6 +313,26 @@ impl CtrlKbdBacklight {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the keyboard LED to active if laptop is awake
|
||||||
|
fn set_awake_enable(&self, enabled: bool) -> Result<(), RogError> {
|
||||||
|
let bytes = if enabled { LED_AWAKE_ON } else { LED_AWAKE_OFF };
|
||||||
|
self.write_bytes(&bytes)?;
|
||||||
|
self.write_bytes(&LED_SET)?;
|
||||||
|
// Changes won't persist unless apply is set
|
||||||
|
self.write_bytes(&LED_APPLY)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the keyboard suspend animation to on if plugged in
|
||||||
|
fn set_sleep_anim_enable(&self, enabled: bool) -> Result<(), RogError> {
|
||||||
|
let bytes = if enabled { LED_SLEEP_ON } else { LED_SLEEP_OFF };
|
||||||
|
self.write_bytes(&bytes)?;
|
||||||
|
self.write_bytes(&LED_SET)?;
|
||||||
|
// Changes won't persist unless apply is set
|
||||||
|
self.write_bytes(&LED_APPLY)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn find_led_node(id_product: &str) -> Result<String, RogError> {
|
fn find_led_node(id_product: &str) -> Result<String, RogError> {
|
||||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
use crate::error::RogError;
|
use crate::error::RogError;
|
||||||
use crate::{config::Config, GetSupported};
|
use crate::{config::Config, GetSupported};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use rog_types::{profile::{FanLevel, Profile, ProfileEvent}, supported::FanCpuSupportedFunctions};
|
use rog_types::{
|
||||||
|
profile::{FanLevel, Profile, ProfileEvent},
|
||||||
|
supported::FanCpuSupportedFunctions,
|
||||||
|
};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use zbus::{dbus_interface, fdo::Error};
|
|
||||||
use zvariant::ObjectPath;
|
|
||||||
|
|
||||||
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
use super::*;
|
||||||
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
|
|
||||||
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
|
|
||||||
|
|
||||||
pub struct CtrlFanAndCpu {
|
pub struct CtrlFanAndCpu {
|
||||||
pub path: &'static str,
|
pub path: &'static str,
|
||||||
config: Arc<Mutex<Config>>,
|
pub config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetSupported for CtrlFanAndCpu {
|
impl GetSupported for CtrlFanAndCpu {
|
||||||
@@ -31,160 +31,6 @@ impl GetSupported for CtrlFanAndCpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DbusFanAndCpu {
|
|
||||||
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DbusFanAndCpu {
|
|
||||||
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
|
|
||||||
Self { inner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
|
||||||
impl DbusFanAndCpu {
|
|
||||||
/// Set profile details
|
|
||||||
fn set_profile(&self, profile: String) {
|
|
||||||
if let Ok(event) = serde_json::from_str(&profile) {
|
|
||||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
ctrl.handle_profile_event(&event, &mut cfg)
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
|
||||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
|
||||||
if let Ok(json) = serde_json::to_string(profile) {
|
|
||||||
self.notify_profile(&json)
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch the active profile name
|
|
||||||
fn next_profile(&mut self) {
|
|
||||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
ctrl.do_next_profile(&mut cfg)
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
|
||||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
|
||||||
if let Ok(json) = serde_json::to_string(profile) {
|
|
||||||
self.notify_profile(&json)
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch the active profile name
|
|
||||||
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
|
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
return Ok(cfg.active_profile.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(Error::Failed(
|
|
||||||
"Failed to get active profile name".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Profile can't implement Type because of Curve
|
|
||||||
/// Fetch the active profile details
|
|
||||||
fn profile(&mut self) -> zbus::fdo::Result<String> {
|
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
|
||||||
if let Ok(json) = serde_json::to_string_pretty(profile) {
|
|
||||||
return Ok(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(Error::Failed(
|
|
||||||
"Failed to get active profile details".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch all profile data
|
|
||||||
fn profiles(&mut self) -> zbus::fdo::Result<String> {
|
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
|
|
||||||
return Ok(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(Error::Failed(
|
|
||||||
"Failed to get all profile details".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
|
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
|
|
||||||
return Ok(profile_names);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::Failed("Failed to get all profile names".to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
|
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
|
||||||
cfg.read();
|
|
||||||
|
|
||||||
if !cfg.power_profiles.contains_key(profile) {
|
|
||||||
return Err(Error::Failed("Invalid profile specified".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.power_profiles.keys().len() == 1 {
|
|
||||||
return Err(Error::Failed("Cannot delete the last profile".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.active_profile == *profile {
|
|
||||||
return Err(Error::Failed(
|
|
||||||
"Cannot delete the active profile".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.power_profiles.remove(profile);
|
|
||||||
cfg.write();
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::Failed("Failed to lock configuration".to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
|
||||||
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::ZbusAdd for DbusFanAndCpu {
|
|
||||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
|
||||||
server
|
|
||||||
.at(
|
|
||||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!("DbusFanAndCpu: add_to_server {}", err);
|
|
||||||
err
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Reloadable for CtrlFanAndCpu {
|
impl crate::Reloadable for CtrlFanAndCpu {
|
||||||
fn reload(&mut self) -> Result<(), RogError> {
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||||
@@ -265,7 +111,7 @@ impl CtrlFanAndCpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_profile_event(
|
pub(super) fn handle_profile_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: &ProfileEvent,
|
event: &ProfileEvent,
|
||||||
config: &mut Config,
|
config: &mut Config,
|
||||||
@@ -318,7 +164,7 @@ impl CtrlFanAndCpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
|
pub(super) fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
|
||||||
let mode_config = config
|
let mode_config = config
|
||||||
.power_profiles
|
.power_profiles
|
||||||
.get(profile)
|
.get(profile)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
pub mod zbus;
|
||||||
|
|
||||||
|
pub mod controller;
|
||||||
|
|
||||||
|
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
||||||
|
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
|
||||||
|
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
use log::warn;
|
||||||
|
use rog_fan_curve::Curve;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use zbus::{dbus_interface, fdo::Error};
|
||||||
|
use zvariant::ObjectPath;
|
||||||
|
|
||||||
|
use super::controller::CtrlFanAndCpu;
|
||||||
|
|
||||||
|
pub struct FanAndCpuZbus {
|
||||||
|
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FanAndCpuZbus {
|
||||||
|
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl FanAndCpuZbus {
|
||||||
|
/// Set profile details
|
||||||
|
fn set_profile(&self, profile: String) {
|
||||||
|
if let Ok(event) = serde_json::from_str(&profile) {
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
ctrl.handle_profile_event(&event, &mut cfg)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||||
|
if let Ok(json) = serde_json::to_string(profile) {
|
||||||
|
self.notify_profile(&json)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the active profile
|
||||||
|
fn set_turbo(&self, enable: bool) -> zbus::fdo::Result<()> {
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
// Update the profile then set it
|
||||||
|
cfg.read();
|
||||||
|
let profile = cfg.active_profile.clone();
|
||||||
|
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||||
|
profile.turbo = enable;
|
||||||
|
}
|
||||||
|
ctrl.set(&profile, &mut cfg)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the active profile
|
||||||
|
fn set_min_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
// Update the profile then set it
|
||||||
|
cfg.read();
|
||||||
|
let profile = cfg.active_profile.clone();
|
||||||
|
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||||
|
profile.min_percentage = percentage;
|
||||||
|
}
|
||||||
|
ctrl.set(&profile, &mut cfg)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the active profile
|
||||||
|
fn set_max_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
// Update the profile then set it
|
||||||
|
cfg.read();
|
||||||
|
let profile = cfg.active_profile.clone();
|
||||||
|
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||||
|
profile.max_percentage = percentage;
|
||||||
|
}
|
||||||
|
ctrl.set(&profile, &mut cfg)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the active profile
|
||||||
|
fn set_fan_preset(&self, preset: u8) -> zbus::fdo::Result<()> {
|
||||||
|
if preset > 2 {
|
||||||
|
return Err(zbus::fdo::Error::InvalidArgs(
|
||||||
|
"Fan preset must be 0, 1, or 2".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
// Update the profile then set it
|
||||||
|
cfg.read();
|
||||||
|
let profile = cfg.active_profile.clone();
|
||||||
|
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||||
|
profile.fan_preset = preset;
|
||||||
|
}
|
||||||
|
ctrl.set(&profile, &mut cfg)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the active profile
|
||||||
|
fn set_fan_curve(&self, curve: String) -> zbus::fdo::Result<()> {
|
||||||
|
let curve = Curve::from_config_str(&curve)
|
||||||
|
.map_err(|err| zbus::fdo::Error::InvalidArgs(format!("Fan curve error: {}", err)))?;
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
// Update the profile then set it
|
||||||
|
cfg.read();
|
||||||
|
let profile = cfg.active_profile.clone();
|
||||||
|
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||||
|
profile.fan_curve = Some(curve);
|
||||||
|
}
|
||||||
|
ctrl.set(&profile, &mut cfg)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the active profile name
|
||||||
|
fn next_profile(&mut self) {
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
ctrl.do_next_profile(&mut cfg)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||||
|
if let Ok(json) = serde_json::to_string(profile) {
|
||||||
|
self.notify_profile(&json)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the active profile name
|
||||||
|
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
return Ok(cfg.active_profile.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::Failed(
|
||||||
|
"Failed to get active profile name".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Profile can't implement Type because of Curve
|
||||||
|
/// Fetch the active profile details
|
||||||
|
fn profile(&mut self) -> zbus::fdo::Result<String> {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||||
|
if let Ok(json) = serde_json::to_string_pretty(profile) {
|
||||||
|
return Ok(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::Failed(
|
||||||
|
"Failed to get active profile details".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch all profile data
|
||||||
|
fn profiles(&mut self) -> zbus::fdo::Result<String> {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
|
||||||
|
return Ok(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::Failed(
|
||||||
|
"Failed to get all profile details".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
|
||||||
|
return Ok(profile_names);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::Failed("Failed to get all profile names".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
|
||||||
|
if !cfg.power_profiles.contains_key(profile) {
|
||||||
|
return Err(Error::Failed("Invalid profile specified".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.power_profiles.keys().len() == 1 {
|
||||||
|
return Err(Error::Failed("Cannot delete the last profile".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.active_profile == *profile {
|
||||||
|
return Err(Error::Failed(
|
||||||
|
"Cannot delete the active profile".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.power_profiles.remove(profile);
|
||||||
|
cfg.write();
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::Failed("Failed to lock configuration".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::ZbusAdd for FanAndCpuZbus {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(
|
||||||
|
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("DbusFanAndCpu: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,7 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use zbus::dbus_interface;
|
use zbus::dbus_interface;
|
||||||
use zvariant::ObjectPath;
|
use zvariant::ObjectPath;
|
||||||
|
|
||||||
use crate::{
|
use crate::{GetSupported, ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::CtrlKbdLed, ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios};
|
||||||
ctrl_anime::CtrlAnimeDisplay, ctrl_charge::CtrlCharge, ctrl_fan_cpu::CtrlFanAndCpu,
|
|
||||||
ctrl_leds::CtrlKbdBacklight, ctrl_rog_bios::CtrlRogBios, GetSupported,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rog_types::supported::{
|
use rog_types::supported::{
|
||||||
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
|
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
|
||||||
@@ -49,8 +46,8 @@ impl GetSupported for SupportedFunctions {
|
|||||||
|
|
||||||
fn get_supported() -> Self::A {
|
fn get_supported() -> Self::A {
|
||||||
SupportedFunctions {
|
SupportedFunctions {
|
||||||
keyboard_led: CtrlKbdBacklight::get_supported(),
|
keyboard_led: CtrlKbdLed::get_supported(),
|
||||||
anime_ctrl: CtrlAnimeDisplay::get_supported(),
|
anime_ctrl: CtrlAnime::get_supported(),
|
||||||
charge_ctrl: CtrlCharge::get_supported(),
|
charge_ctrl: CtrlCharge::get_supported(),
|
||||||
fan_cpu_ctrl: CtrlFanAndCpu::get_supported(),
|
fan_cpu_ctrl: CtrlFanAndCpu::get_supported(),
|
||||||
rog_bios_ctrl: CtrlRogBios::get_supported(),
|
rog_bios_ctrl: CtrlRogBios::get_supported(),
|
||||||
|
|||||||
+77
-51
@@ -1,11 +1,11 @@
|
|||||||
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
|
use daemon::ctrl_leds::{CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus};
|
||||||
use daemon::{
|
use daemon::{
|
||||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||||
};
|
};
|
||||||
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
||||||
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
|
use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics};
|
||||||
use daemon::{
|
use daemon::{
|
||||||
ctrl_fan_cpu::{CtrlFanAndCpu, DbusFanAndCpu},
|
ctrl_profiles::{zbus::FanAndCpuZbus, controller::CtrlFanAndCpu},
|
||||||
laptops::LaptopLedData,
|
laptops::LaptopLedData,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,27 +41,24 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timing is such that:
|
/// The actual main loop for the daemon
|
||||||
// - interrupt write is minimum 1ms (sometimes lower)
|
|
||||||
// - read interrupt must timeout, minimum of 1ms
|
|
||||||
// - for a single usb packet, 2ms total.
|
|
||||||
// - to maintain constant times of 1ms, per-key colours should use
|
|
||||||
// the effect endpoint so that the complete colour block is written
|
|
||||||
// as fast as 1ms per row of the matrix inside it. (10ms total time)
|
|
||||||
fn start_daemon() -> Result<(), Box<dyn Error>> {
|
fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
let supported = SupportedFunctions::get_supported();
|
let supported = SupportedFunctions::get_supported();
|
||||||
print_board_info();
|
print_board_info();
|
||||||
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
|
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
|
||||||
|
|
||||||
let config = Config::load();
|
// Collect tasks for task thread
|
||||||
let enable_gfx_switching = config.gfx_managed;
|
let mut tasks: Vec<Box<dyn CtrlTask + Send>> = Vec::new();
|
||||||
let config = Arc::new(Mutex::new(config));
|
// Start zbus server
|
||||||
|
|
||||||
let connection = Connection::new_system()?;
|
let connection = Connection::new_system()?;
|
||||||
fdo::DBusProxy::new(&connection)?
|
fdo::DBusProxy::new(&connection)?
|
||||||
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
||||||
let mut object_server = zbus::ObjectServer::new(&connection);
|
let mut object_server = zbus::ObjectServer::new(&connection);
|
||||||
|
|
||||||
|
let config = Config::load();
|
||||||
|
let enable_gfx_switching = config.gfx_managed;
|
||||||
|
let config = Arc::new(Mutex::new(config));
|
||||||
|
|
||||||
supported.add_to_server(&mut object_server);
|
supported.add_to_server(&mut object_server);
|
||||||
|
|
||||||
match CtrlRogBios::new(config.clone()) {
|
match CtrlRogBios::new(config.clone()) {
|
||||||
@@ -90,24 +87,68 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match CtrlAnimeDisplay::new() {
|
match CtrlFanAndCpu::new(config.clone()) {
|
||||||
|
Ok(mut ctrl) => {
|
||||||
|
ctrl.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
||||||
|
let tmp = Arc::new(Mutex::new(ctrl));
|
||||||
|
FanAndCpuZbus::new(tmp).add_to_server(&mut object_server);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Profile control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match CtrlAnime::new(AnimeConfig::load()) {
|
||||||
Ok(ctrl) => {
|
Ok(ctrl) => {
|
||||||
ctrl.add_to_server(&mut object_server);
|
let inner = Arc::new(Mutex::new(ctrl));
|
||||||
|
|
||||||
|
let mut reload = CtrlAnimeReloader(inner.clone());
|
||||||
|
reload
|
||||||
|
.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("AniMe: {}", err));
|
||||||
|
|
||||||
|
let zbus = CtrlAnimeZbus(inner.clone());
|
||||||
|
zbus.add_to_server(&mut object_server);
|
||||||
|
|
||||||
|
tasks.push(Box::new(CtrlAnimeTask::new(inner)));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("AniMe control: {}", err);
|
error!("AniMe control: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let laptop = LaptopLedData::get_data();
|
||||||
|
let aura_config = AuraConfig::load(&laptop);
|
||||||
|
match CtrlKbdLed::new(laptop, aura_config) {
|
||||||
|
Ok(ctrl) => {
|
||||||
|
let inner = Arc::new(Mutex::new(ctrl));
|
||||||
|
|
||||||
|
let mut reload = CtrlKbdLedReloader(inner.clone());
|
||||||
|
reload
|
||||||
|
.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("Keyboard LED control: {}", err));
|
||||||
|
|
||||||
|
CtrlKbdLedZbus::new(inner.clone()).add_to_server(&mut object_server);
|
||||||
|
let task = CtrlKbdLedTask(inner);
|
||||||
|
tasks.push(Box::new(task));
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Keyboard control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graphics switching requires some checks on boot specifically for g-sync capable laptops
|
||||||
if enable_gfx_switching {
|
if enable_gfx_switching {
|
||||||
match CtrlGraphics::new(config.clone()) {
|
match CtrlGraphics::new(config.clone()) {
|
||||||
Ok(mut ctrl) => {
|
Ok(mut ctrl) => {
|
||||||
// Need to check if a laptop has the dedicated gfx switch
|
// Need to check if a laptop has the dedicated gfx switch
|
||||||
if CtrlRogBios::has_dedicated_gfx_toggle() {
|
if CtrlRogBios::has_dedicated_gfx_toggle() {
|
||||||
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||||
if let Ok(vendor) = ctrl.get_gfx_mode() {
|
if let Ok(mut config) = config.lock() {
|
||||||
if ded == 1 && vendor != GfxVendors::Nvidia {
|
if ded == 1 {
|
||||||
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||||
|
config.gfx_last_mode = config.gfx_mode;
|
||||||
let devices = ctrl.devices();
|
let devices = ctrl.devices();
|
||||||
let bus = ctrl.bus();
|
let bus = ctrl.bus();
|
||||||
CtrlGraphics::do_vendor_tasks(
|
CtrlGraphics::do_vendor_tasks(
|
||||||
@@ -118,6 +159,14 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
)?;
|
)?;
|
||||||
} else if ded == 0 {
|
} else if ded == 0 {
|
||||||
info!("Dedicated GFX toggle is off");
|
info!("Dedicated GFX toggle is off");
|
||||||
|
let devices = ctrl.devices();
|
||||||
|
let bus = ctrl.bus();
|
||||||
|
CtrlGraphics::do_vendor_tasks(
|
||||||
|
config.gfx_last_mode,
|
||||||
|
false,
|
||||||
|
&devices,
|
||||||
|
&bus,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,48 +181,24 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect tasks for task thread
|
|
||||||
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
|
|
||||||
|
|
||||||
if let Ok(mut ctrl) = CtrlFanAndCpu::new(config).map_err(|err| {
|
|
||||||
error!("Profile control: {}", err);
|
|
||||||
}) {
|
|
||||||
ctrl.reload()
|
|
||||||
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
|
||||||
let tmp = Arc::new(Mutex::new(ctrl));
|
|
||||||
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
|
|
||||||
};
|
|
||||||
|
|
||||||
let laptop = LaptopLedData::get_data();
|
|
||||||
let aura_config = AuraConfig::load(&laptop);
|
|
||||||
if let Ok(ctrl) = CtrlKbdBacklight::new(laptop, aura_config).map_err(|err| {
|
|
||||||
error!("Keyboard control: {}", err);
|
|
||||||
err
|
|
||||||
}) {
|
|
||||||
let tmp = Arc::new(Mutex::new(ctrl));
|
|
||||||
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
|
||||||
tasks.push(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement messaging between threads to check fails
|
// TODO: implement messaging between threads to check fails
|
||||||
// These tasks generally read a sys path or file to check for a
|
|
||||||
// change
|
// Run tasks
|
||||||
let handle = std::thread::Builder::new()
|
let handle = std::thread::Builder::new()
|
||||||
.name("asusd watch".to_string())
|
.name("asusd watch".to_string())
|
||||||
.spawn(move || loop {
|
.spawn(move || loop {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
|
||||||
for ctrl in tasks.iter() {
|
for ctrl in tasks.iter() {
|
||||||
if let Ok(mut lock) = ctrl.try_lock() {
|
ctrl.do_task()
|
||||||
lock.do_task()
|
.map_err(|err| {
|
||||||
.map_err(|err| {
|
warn!("do_task error: {}", err);
|
||||||
warn!("do_task error: {}", err);
|
})
|
||||||
})
|
.ok();
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Run zbus server
|
||||||
object_server
|
object_server
|
||||||
.with(
|
.with(
|
||||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"),
|
&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"),
|
||||||
@@ -187,6 +212,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
|
// Loop to check errors and iterate zbus server
|
||||||
loop {
|
loop {
|
||||||
if let Err(err) = &handle {
|
if let Err(err) = &handle {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
|
|||||||
@@ -96,3 +96,10 @@ impl From<std::io::Error> for RogError {
|
|||||||
RogError::Io(err)
|
RogError::Io(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<RogError> for zbus::fdo::Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(err: RogError) -> Self {
|
||||||
|
zbus::fdo::Error::Failed(format!("{}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use rog_types::aura_modes::AuraModeNum;
|
use rog_aura::AuraModeNum;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|||||||
+7
-6
@@ -1,12 +1,17 @@
|
|||||||
#![deny(unused_must_use)]
|
#![deny(unused_must_use)]
|
||||||
/// Configuration loading, saving
|
/// Configuration loading, saving
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod config_anime;
|
||||||
pub mod config_aura;
|
pub mod config_aura;
|
||||||
pub(crate) mod config_old;
|
pub(crate) mod config_old;
|
||||||
/// Control of AniMe matrix display
|
/// Control of AniMe matrix display
|
||||||
pub mod ctrl_anime;
|
pub mod ctrl_anime;
|
||||||
/// Control of battery charge level
|
/// Control of battery charge level
|
||||||
pub mod ctrl_charge;
|
pub mod ctrl_charge;
|
||||||
|
/// GPU switching and power
|
||||||
|
pub mod ctrl_gfx;
|
||||||
|
/// Keyboard LED brightness control, RGB, and LED display modes
|
||||||
|
pub mod ctrl_leds;
|
||||||
/// Control CPU min/max freq and turbo, fan mode, fan curves
|
/// Control CPU min/max freq and turbo, fan mode, fan curves
|
||||||
///
|
///
|
||||||
/// Intel machines can control:
|
/// Intel machines can control:
|
||||||
@@ -18,11 +23,7 @@ pub mod ctrl_charge;
|
|||||||
/// - CPU turbo enable/disable
|
/// - CPU turbo enable/disable
|
||||||
/// - Fan mode (normal, boost, silent)
|
/// - Fan mode (normal, boost, silent)
|
||||||
/// - Fan min/max RPM curve
|
/// - Fan min/max RPM curve
|
||||||
pub mod ctrl_fan_cpu;
|
pub mod ctrl_profiles;
|
||||||
/// GPU switching and power
|
|
||||||
pub mod ctrl_gfx;
|
|
||||||
/// Keyboard LED brightness control, RGB, and LED display modes
|
|
||||||
pub mod ctrl_leds;
|
|
||||||
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
|
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
|
||||||
pub mod ctrl_rog_bios;
|
pub mod ctrl_rog_bios;
|
||||||
/// Laptop matching to determine capabilities
|
/// Laptop matching to determine capabilities
|
||||||
@@ -48,7 +49,7 @@ pub trait ZbusAdd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait CtrlTask {
|
pub trait CtrlTask {
|
||||||
fn do_task(&mut self) -> Result<(), RogError>;
|
fn do_task(&self) -> Result<(), RogError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CtrlTaskComplex {
|
pub trait CtrlTaskComplex {
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
@@ -11,3 +11,5 @@ Restart=always
|
|||||||
RestartSec=1
|
RestartSec=1
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.asuslinux.Daemon
|
BusName=org.asuslinux.Daemon
|
||||||
|
SELinuxContext=system_u:system_r:unconfined_t:s0
|
||||||
|
#SELinuxContext=system_u:object_r:modules_object_t:s0
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# Daemon
|
||||||
|
|
||||||
|
## Controller pattern
|
||||||
|
|
||||||
|
There are a series of traits in the daemon for use with controller objects. Not all traits are required:
|
||||||
|
|
||||||
|
- `Reloadable`, for controllers that need the ability to reload (typically on start)
|
||||||
|
- `ZbusAdd`, for controllers that have zbus derive. These need to run on the zbus server.
|
||||||
|
- `CtrlTask`, for controllers that need to run tasks every loop.
|
||||||
|
- `GetSupported`, see if the hardware/functions this controller requires are supported.
|
||||||
|
|
||||||
|
The first 3 trait objects get owned by the daemon methods that required them, which is why an `Arc<Mutex<T>>` is required.
|
||||||
|
|
||||||
|
Generally the actual controller object will need to live in its own world as its own struct.
|
||||||
|
Then for each trait that is required a new struct is required that can have the trait implemented, and that struct would have a reference to the main controller via `Arc<Mutex<T>>`.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Main controller:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct CtrlAnime {
|
||||||
|
<things the controller requires>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlAnime {
|
||||||
|
<functions the controller exposes>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The task trait:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct CtrlAnimeTask(Arc<Mutex<CtrlAnime>>);
|
||||||
|
|
||||||
|
impl crate::CtrlTask for CtrlAnimeTask {
|
||||||
|
fn do_task(&self) -> Result<(), RogError> {
|
||||||
|
if let Ok(lock) = self.inner.try_lock() {
|
||||||
|
<some action>
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The reloader trait
|
||||||
|
```rust
|
||||||
|
pub struct CtrlAnimeReloader(Arc<Mutex<CtrlAnime>>);
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlAnimeReloader {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
if let Ok(lock) = self.inner.try_lock() {
|
||||||
|
<some action>
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The Zbus requirements:
|
||||||
|
```rust
|
||||||
|
pub struct CtrlAnimeZbus(Arc<Mutex<CtrlAnime>>);
|
||||||
|
|
||||||
|
impl crate::ZbusAdd for CtrlAnimeZbus {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(
|
||||||
|
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlAnimeDisplay: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl CtrlAnimeZbus {
|
||||||
|
fn <zbus method>() {
|
||||||
|
if let Ok(lock) = self.inner.try_lock() {
|
||||||
|
<some action>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The controller can then be added to the daemon parts as required.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rog_anime"
|
name = "rog_anime"
|
||||||
version = "1.0.3"
|
version = "1.0.4"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub enum AnimeError {
|
|||||||
/// The input was incorrect size, expected size is `IncorrectSize(width, height)`
|
/// The input was incorrect size, expected size is `IncorrectSize(width, height)`
|
||||||
IncorrectSize(u32, u32),
|
IncorrectSize(u32, u32),
|
||||||
#[cfg(feature = "dbus")]
|
#[cfg(feature = "dbus")]
|
||||||
Zbus(fdo::Error)
|
Zbus(fdo::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for AnimeError {
|
impl fmt::Display for AnimeError {
|
||||||
|
|||||||
@@ -31,3 +31,5 @@ pub mod error;
|
|||||||
|
|
||||||
/// Provides const methods to create the USB HID control packets
|
/// Provides const methods to create the USB HID control packets
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
|
|
||||||
|
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
@@ -6,7 +6,7 @@ use std::{
|
|||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{error::AnimeError, AnimeDataBuffer, AnimeGif, AnimeImage, AnimTime};
|
use crate::{error::AnimeError, AnimTime, AnimeDataBuffer, AnimeGif, AnimeImage};
|
||||||
|
|
||||||
/// All the possible AniMe actions that can be used. This enum is intended to be
|
/// All the possible AniMe actions that can be used. This enum is intended to be
|
||||||
/// a helper for loading up `ActionData`.
|
/// a helper for loading up `ActionData`.
|
||||||
@@ -40,7 +40,7 @@ pub enum AnimeAction {
|
|||||||
|
|
||||||
/// All the possible AniMe actions that can be used. The enum is intended to be
|
/// All the possible AniMe actions that can be used. The enum is intended to be
|
||||||
/// used in a array allowing the user to cycle through a series of actions.
|
/// used in a array allowing the user to cycle through a series of actions.
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub enum ActionData {
|
pub enum ActionData {
|
||||||
/// Full gif sequence. Immutable.
|
/// Full gif sequence. Immutable.
|
||||||
Animation(AnimeGif),
|
Animation(AnimeGif),
|
||||||
@@ -58,6 +58,50 @@ pub enum ActionData {
|
|||||||
Matrix,
|
Matrix,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ActionData {
|
||||||
|
pub fn from_anime_action(action: &AnimeAction) -> Result<ActionData, AnimeError> {
|
||||||
|
let a = match action {
|
||||||
|
AnimeAction::AsusAnimation {
|
||||||
|
file,
|
||||||
|
time: duration,
|
||||||
|
brightness,
|
||||||
|
} => ActionData::Animation(AnimeGif::create_diagonal_gif(
|
||||||
|
&file,
|
||||||
|
*duration,
|
||||||
|
*brightness,
|
||||||
|
)?),
|
||||||
|
AnimeAction::ImageAnimation {
|
||||||
|
file,
|
||||||
|
scale,
|
||||||
|
angle,
|
||||||
|
translation,
|
||||||
|
time: duration,
|
||||||
|
brightness,
|
||||||
|
} => ActionData::Animation(AnimeGif::create_png_gif(
|
||||||
|
&file,
|
||||||
|
*scale,
|
||||||
|
*angle,
|
||||||
|
*translation,
|
||||||
|
*duration,
|
||||||
|
*brightness,
|
||||||
|
)?),
|
||||||
|
AnimeAction::Image {
|
||||||
|
file,
|
||||||
|
scale,
|
||||||
|
angle,
|
||||||
|
translation,
|
||||||
|
brightness,
|
||||||
|
} => {
|
||||||
|
let image = AnimeImage::from_png(&file, *scale, *angle, *translation, *brightness)?;
|
||||||
|
let data = <AnimeDataBuffer>::from(&image);
|
||||||
|
ActionData::Image(Box::new(data))
|
||||||
|
}
|
||||||
|
AnimeAction::Pause(duration) => ActionData::Pause(*duration),
|
||||||
|
};
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An optimised precomputed set of actions that the user can cycle through
|
/// An optimised precomputed set of actions that the user can cycle through
|
||||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||||
pub struct Sequences(Vec<ActionData>);
|
pub struct Sequences(Vec<ActionData>);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pub const fn pkts_for_init() -> [[u8; PACKET_SIZE]; 2] {
|
|||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
while count < INIT_STR.len() {
|
while count < INIT_STR.len() {
|
||||||
packets[0][count] = INIT_STR[count];
|
packets[0][count] = INIT_STR[count];
|
||||||
count +=1;
|
count += 1;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
packets[1][0] = DEV_PAGE; // write it to be sure?
|
packets[1][0] = DEV_PAGE; // write it to be sure?
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "rog_aura"
|
||||||
|
version = "1.0.1"
|
||||||
|
license = "MPL-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
repository = "https://gitlab.com/asus-linux/asusctl"
|
||||||
|
homepage = "https://gitlab.com/asus-linux/asusctl"
|
||||||
|
documentation = "https://docs.rs/rog-anime"
|
||||||
|
description = "Types useful for fancy keyboards on ASUS ROG laptops"
|
||||||
|
keywords = ["ROG", "ASUS", "Aura"]
|
||||||
|
edition = "2018"
|
||||||
|
exclude = ["data"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["dbus"]
|
||||||
|
dbus = ["zbus", "zvariant", "zvariant_derive"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "^1.0"
|
||||||
|
serde_derive = "^1.0"
|
||||||
|
|
||||||
|
zbus = { version = "^1.9.1", optional = true }
|
||||||
|
zvariant = { version = "^2.6", optional = true }
|
||||||
|
zvariant_derive = { version = "^2.6", optional = true }
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||||
// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||||
// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
// static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||||
// static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
|
|
||||||
use crate::error::AuraError;
|
|
||||||
use crate::LED_MSG_LEN;
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
#[cfg(feature = "dbus")]
|
||||||
use zvariant_derive::Type;
|
use zvariant_derive::Type;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
|
use crate::{error::Error, LED_MSG_LEN};
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum LedBrightness {
|
pub enum LedBrightness {
|
||||||
Off,
|
Off,
|
||||||
Low,
|
Low,
|
||||||
@@ -36,7 +38,8 @@ impl From<u32> for LedBrightness {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy, Deserialize, Serialize, Type)]
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Copy, Deserialize, Serialize)]
|
||||||
pub struct Colour(pub u8, pub u8, pub u8);
|
pub struct Colour(pub u8, pub u8, pub u8);
|
||||||
|
|
||||||
impl Default for Colour {
|
impl Default for Colour {
|
||||||
@@ -46,20 +49,21 @@ impl Default for Colour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Colour {
|
impl FromStr for Colour {
|
||||||
type Err = AuraError;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
if s.len() < 6 {
|
if s.len() < 6 {
|
||||||
return Err(AuraError::ParseColour);
|
return Err(Error::ParseColour);
|
||||||
}
|
}
|
||||||
let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?;
|
let r = u8::from_str_radix(&s[0..2], 16).or(Err(Error::ParseColour))?;
|
||||||
let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?;
|
let g = u8::from_str_radix(&s[2..4], 16).or(Err(Error::ParseColour))?;
|
||||||
let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?;
|
let b = u8::from_str_radix(&s[4..6], 16).or(Err(Error::ParseColour))?;
|
||||||
Ok(Colour(r, g, b))
|
Ok(Colour(r, g, b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum Speed {
|
pub enum Speed {
|
||||||
Low = 0xe1,
|
Low = 0xe1,
|
||||||
Med = 0xeb,
|
Med = 0xeb,
|
||||||
@@ -71,7 +75,7 @@ impl Default for Speed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FromStr for Speed {
|
impl FromStr for Speed {
|
||||||
type Err = AuraError;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let s = s.to_lowercase();
|
let s = s.to_lowercase();
|
||||||
@@ -79,7 +83,7 @@ impl FromStr for Speed {
|
|||||||
"low" => Ok(Speed::Low),
|
"low" => Ok(Speed::Low),
|
||||||
"med" => Ok(Speed::Med),
|
"med" => Ok(Speed::Med),
|
||||||
"high" => Ok(Speed::High),
|
"high" => Ok(Speed::High),
|
||||||
_ => Err(AuraError::ParseSpeed),
|
_ => Err(Error::ParseSpeed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +91,8 @@ impl FromStr for Speed {
|
|||||||
/// Used for Rainbow mode.
|
/// Used for Rainbow mode.
|
||||||
///
|
///
|
||||||
/// Enum corresponds to the required integer value
|
/// Enum corresponds to the required integer value
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Right,
|
Right,
|
||||||
Left,
|
Left,
|
||||||
@@ -100,7 +105,7 @@ impl Default for Direction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FromStr for Direction {
|
impl FromStr for Direction {
|
||||||
type Err = AuraError;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let s = s.to_lowercase();
|
let s = s.to_lowercase();
|
||||||
@@ -109,21 +114,14 @@ impl FromStr for Direction {
|
|||||||
"up" => Ok(Direction::Up),
|
"up" => Ok(Direction::Up),
|
||||||
"down" => Ok(Direction::Down),
|
"down" => Ok(Direction::Down),
|
||||||
"left" => Ok(Direction::Left),
|
"left" => Ok(Direction::Left),
|
||||||
_ => Err(AuraError::ParseDirection),
|
_ => Err(Error::ParseDirection),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes out the correct byte string for brightness
|
/// Enum of modes that convert to the actual number required by a USB HID packet
|
||||||
pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
[
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Deserialize, Serialize)]
|
||||||
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(
|
|
||||||
Debug, Type, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Deserialize, Serialize,
|
|
||||||
)]
|
|
||||||
pub enum AuraModeNum {
|
pub enum AuraModeNum {
|
||||||
Static = 0,
|
Static = 0,
|
||||||
Breathe = 1,
|
Breathe = 1,
|
||||||
@@ -197,95 +195,9 @@ impl From<u8> for AuraModeNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct AuraMultiZone {
|
|
||||||
static_: [AuraEffect; 4],
|
|
||||||
breathe: [AuraEffect; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuraMultiZone {
|
|
||||||
pub fn set(&mut self, effect: AuraEffect) {
|
|
||||||
if effect.mode == AuraModeNum::Static {
|
|
||||||
match effect.zone {
|
|
||||||
AuraZone::None => {}
|
|
||||||
AuraZone::One => self.static_[0] = effect,
|
|
||||||
AuraZone::Two => self.static_[1] = effect,
|
|
||||||
AuraZone::Three => self.static_[2] = effect,
|
|
||||||
AuraZone::Four => self.static_[3] = effect,
|
|
||||||
}
|
|
||||||
} else if effect.mode == AuraModeNum::Breathe {
|
|
||||||
match effect.zone {
|
|
||||||
AuraZone::None => {}
|
|
||||||
AuraZone::One => self.breathe[0] = effect,
|
|
||||||
AuraZone::Two => self.breathe[1] = effect,
|
|
||||||
AuraZone::Three => self.breathe[2] = effect,
|
|
||||||
AuraZone::Four => self.breathe[3] = effect,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn static_(&self) -> &[AuraEffect; 4] {
|
|
||||||
&self.static_
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breathe(&self) -> &[AuraEffect; 4] {
|
|
||||||
&self.breathe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AuraMultiZone {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
static_: [
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Static,
|
|
||||||
zone: AuraZone::One,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Static,
|
|
||||||
zone: AuraZone::Two,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Static,
|
|
||||||
zone: AuraZone::Three,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Static,
|
|
||||||
zone: AuraZone::Four,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
],
|
|
||||||
breathe: [
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Breathe,
|
|
||||||
zone: AuraZone::One,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Breathe,
|
|
||||||
zone: AuraZone::Two,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Breathe,
|
|
||||||
zone: AuraZone::Three,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AuraEffect {
|
|
||||||
mode: AuraModeNum::Breathe,
|
|
||||||
zone: AuraZone::Four,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Base effects have no zoning, while multizone is 1-4
|
/// Base effects have no zoning, while multizone is 1-4
|
||||||
#[derive(Debug, Type, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum AuraZone {
|
pub enum AuraZone {
|
||||||
None,
|
None,
|
||||||
One,
|
One,
|
||||||
@@ -294,8 +206,12 @@ pub enum AuraZone {
|
|||||||
Four,
|
Four,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default factory modes structure
|
/// Default factory modes structure. This easily converts to an USB HID packet with:
|
||||||
#[derive(Debug, Type, Clone, Deserialize, Serialize)]
|
/// ```rust
|
||||||
|
/// let bytes: [u8; LED_MSG_LEN] = mode.into();
|
||||||
|
/// ```
|
||||||
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct AuraEffect {
|
pub struct AuraEffect {
|
||||||
/// The effect type
|
/// The effect type
|
||||||
pub mode: AuraModeNum,
|
pub mode: AuraModeNum,
|
||||||
@@ -351,11 +267,11 @@ impl Default for AuraEffect {
|
|||||||
|
|
||||||
/// Parses `AuraEffect` in to packet data for writing to the USB interface
|
/// Parses `AuraEffect` in to packet data for writing to the USB interface
|
||||||
///
|
///
|
||||||
/// Byte structure:
|
/// Byte structure where colour is RGB, one byte per R, G, B:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
|
/// | 0 | 1 | 2 | 3 | 4, 5, 6 | 7 | 8 | 9 | 10, 11, 12|
|
||||||
/// |---|---|---|---|---|---|---|---|---|---|---|---|---|
|
/// |---|---|-----|-----|---------|------|----------|---|-----------|
|
||||||
/// |5d |b3 |00 |03 |ff |00 |00 |00 |00 |00 |00 |ff |00 |
|
/// |5d |b3 |Zone |Mode |Colour 1 |Speed |Direction |00 |Colour 2 |
|
||||||
/// ```
|
/// ```
|
||||||
impl From<&AuraEffect> for [u8; LED_MSG_LEN] {
|
impl From<&AuraEffect> for [u8; LED_MSG_LEN] {
|
||||||
fn from(aura: &AuraEffect) -> Self {
|
fn from(aura: &AuraEffect) -> Self {
|
||||||
@@ -372,7 +288,6 @@ impl From<&AuraEffect> for [u8; LED_MSG_LEN] {
|
|||||||
msg[10] = aura.colour2.0;
|
msg[10] = aura.colour2.0;
|
||||||
msg[11] = aura.colour2.1;
|
msg[11] = aura.colour2.1;
|
||||||
msg[12] = aura.colour2.2;
|
msg[12] = aura.colour2.2;
|
||||||
|
|
||||||
msg
|
msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
use std::error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
ParseColour,
|
||||||
|
ParseSpeed,
|
||||||
|
ParseDirection,
|
||||||
|
ParseBrightness,
|
||||||
|
ParseAnime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
// This trait requires `fmt` with this exact signature.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::ParseColour => write!(f, "Could not parse colour"),
|
||||||
|
Error::ParseSpeed => write!(f, "Could not parse speed"),
|
||||||
|
Error::ParseDirection => write!(f, "Could not parse direction"),
|
||||||
|
Error::ParseBrightness => write!(f, "Could not parse brightness"),
|
||||||
|
Error::ParseAnime => write!(f, "Could not parse anime"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/// A container of images/grids/gifs/pauses which can be iterated over to generate
|
||||||
|
/// cool effects
|
||||||
|
mod sequencer;
|
||||||
|
pub use sequencer::*;
|
||||||
|
|
||||||
|
mod builtin_modes;
|
||||||
|
pub use builtin_modes::*;
|
||||||
|
|
||||||
|
mod per_key_rgb;
|
||||||
|
pub use per_key_rgb::*;
|
||||||
|
|
||||||
|
pub mod usb;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
|
||||||
|
pub const LED_MSG_LEN: usize = 17;
|
||||||
@@ -33,7 +33,8 @@ impl KeyColourArray {
|
|||||||
KeyColourArray(set)
|
KeyColourArray(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialise and clear the keyboard for custom effects
|
/// Initialise and clear the keyboard for custom effects, this must be done for
|
||||||
|
/// every time mode switches from builtin to custom
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn get_init_msg() -> [u8; 64] {
|
pub const fn get_init_msg() -> [u8; 64] {
|
||||||
let mut init = [0u8; 64];
|
let mut init = [0u8; 64];
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
|
/// All the possible AniMe actions that can be used. The enum is intended to be
|
||||||
|
/// used in a array allowing the user to cycle through a series of actions.
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum ActionData {
|
||||||
|
Static,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An optimised precomputed set of actions that the user can cycle through
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||||
|
pub struct Sequences(Vec<ActionData>);
|
||||||
|
|
||||||
|
impl Sequences {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use a base `AnimeAction` to generate the precomputed data and insert in to
|
||||||
|
/// the run buffer
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, _index: usize) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an item at this position from the run buffer. If the `index` supplied
|
||||||
|
/// is not in range then `None` is returned, otherwise the `ActionData` at that location
|
||||||
|
/// is yeeted and returned.
|
||||||
|
#[inline]
|
||||||
|
pub fn remove_item(&mut self, index: usize) -> Option<ActionData> {
|
||||||
|
if index < self.0.len() {
|
||||||
|
return Some(self.0.remove(index));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> ActionIterator {
|
||||||
|
ActionIterator {
|
||||||
|
actions: &self,
|
||||||
|
next_idx: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iteractor helper for iterating over all the actions in `Sequences`
|
||||||
|
pub struct ActionIterator<'a> {
|
||||||
|
actions: &'a Sequences,
|
||||||
|
next_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ActionIterator<'a> {
|
||||||
|
type Item = &'a ActionData;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<&'a ActionData> {
|
||||||
|
if self.next_idx == self.actions.0.len() {
|
||||||
|
self.next_idx = 0;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = self.next_idx;
|
||||||
|
self.next_idx += 1;
|
||||||
|
|
||||||
|
Some(&self.actions.0[current])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||||
|
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||||
|
pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
|
pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||||
|
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
|
|
||||||
|
// Only these two packets must be 17 bytes
|
||||||
|
pub const LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
pub const LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
/// Writes out the correct byte string for brightness
|
||||||
|
pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
||||||
|
[
|
||||||
|
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable the keyboard when laptop is awake
|
||||||
|
pub const LED_AWAKE_ON: [u8; 17] = [
|
||||||
|
0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Disable the keyboard when laptop is awake
|
||||||
|
pub const LED_AWAKE_OFF: [u8; 17] = [
|
||||||
|
0x5d, 0xbd, 0x01, 0xc3, 0x13, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Enable animations when the laptop is suspended while plugged in
|
||||||
|
pub const LED_SLEEP_ON: [u8; 17] = [
|
||||||
|
0x5d, 0xbd, 0x01, 0xff, 0x1f, 0x0f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Disable animations when the laptop is suspended while plugged in
|
||||||
|
pub const LED_SLEEP_OFF: [u8; 17] = [
|
||||||
|
0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
@@ -12,6 +12,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
rog_anime = { path = "../rog-anime" }
|
rog_anime = { path = "../rog-anime" }
|
||||||
|
rog_aura = { path = "../rog-aura" }
|
||||||
rog_types = { path = "../rog-types" }
|
rog_types = { path = "../rog-types" }
|
||||||
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
||||||
zbus = "^1.8"
|
zbus = "^1.8"
|
||||||
|
|||||||
+2
-5
@@ -1,7 +1,6 @@
|
|||||||
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
||||||
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
|
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
|
||||||
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
||||||
pub const LED_MSG_LEN: usize = 17;
|
|
||||||
|
|
||||||
pub mod zbus_anime;
|
pub mod zbus_anime;
|
||||||
pub mod zbus_charge;
|
pub mod zbus_charge;
|
||||||
@@ -11,10 +10,8 @@ pub mod zbus_profile;
|
|||||||
pub mod zbus_rogbios;
|
pub mod zbus_rogbios;
|
||||||
pub mod zbus_supported;
|
pub mod zbus_supported;
|
||||||
|
|
||||||
use rog_types::{
|
use rog_aura::AuraEffect;
|
||||||
aura_modes::AuraEffect,
|
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
|
||||||
gfx_vendors::{GfxRequiredUserAction, GfxVendors},
|
|
||||||
};
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use zbus::{Connection, Result, SignalReceiver};
|
use zbus::{Connection, Result, SignalReceiver};
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
use zbus::{dbus_proxy, Connection, Result};
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
use rog_types::{
|
use rog_aura::{AuraEffect, KeyColourArray, LedBrightness};
|
||||||
aura_modes::{AuraEffect, LedBrightness},
|
|
||||||
aura_perkey::KeyColourArray,
|
|
||||||
};
|
|
||||||
|
|
||||||
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
|
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
|
||||||
|
|
||||||
@@ -47,7 +44,12 @@ trait Daemon {
|
|||||||
/// SetLedMode method
|
/// SetLedMode method
|
||||||
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
|
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// NotifyLed signal
|
/// SetAwakeEnabled method
|
||||||
|
fn set_awake_enabled(&self, enabled: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetSleepEnabled method
|
||||||
|
fn set_sleep_enabled(&self, enabled: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// NotifyLed signal
|
/// NotifyLed signal
|
||||||
#[dbus_proxy(signal)]
|
#[dbus_proxy(signal)]
|
||||||
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
||||||
@@ -88,6 +90,20 @@ impl<'a> LedProxy<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the keyboard LED to enabled while the device is awake
|
||||||
|
#[inline]
|
||||||
|
pub fn set_awake_enabled(&self, enabled: bool) -> Result<()> {
|
||||||
|
self.0.set_awake_enabled(enabled)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the keyboard LED suspend animation to enabled while the device is suspended
|
||||||
|
#[inline]
|
||||||
|
pub fn set_sleep_enabled(&self, enabled: bool) -> Result<()> {
|
||||||
|
self.0.set_sleep_enabled(enabled)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn next_led_mode(&self) -> Result<()> {
|
pub fn next_led_mode(&self) -> Result<()> {
|
||||||
self.0.next_led_mode()
|
self.0.next_led_mode()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ trait Daemon {
|
|||||||
/// NextProfile method
|
/// NextProfile method
|
||||||
fn next_profile(&self) -> zbus::Result<()>;
|
fn next_profile(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// Profile method
|
/// Profile, get the active profile
|
||||||
fn profile(&self) -> zbus::Result<String>;
|
fn profile(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
/// Profiles method
|
/// Profiles method
|
||||||
@@ -50,6 +50,21 @@ trait Daemon {
|
|||||||
/// SetProfile method
|
/// SetProfile method
|
||||||
fn set_profile(&self, profile: &str) -> zbus::Result<()>;
|
fn set_profile(&self, profile: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetFanCurve method
|
||||||
|
fn set_fan_curve(&self, curve: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetFanPreset method
|
||||||
|
fn set_fan_preset(&self, preset: u8) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetMaxFrequency method
|
||||||
|
fn set_max_frequency(&self, percentage: u8) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetMinFrequency method
|
||||||
|
fn set_min_frequency(&self, percentage: u8) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetTurbo method
|
||||||
|
fn set_turbo(&self, enable: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// NotifyProfile signal
|
/// NotifyProfile signal
|
||||||
#[dbus_proxy(signal)]
|
#[dbus_proxy(signal)]
|
||||||
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
|
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
|
||||||
@@ -87,12 +102,44 @@ impl<'a> ProfileProxy<'a> {
|
|||||||
self.0.next_profile()
|
self.0.next_profile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SetFanCurve, set fan curve for active profile
|
||||||
|
#[inline]
|
||||||
|
pub fn set_fan_curve(&self, curve: &str) -> zbus::Result<()> {
|
||||||
|
self.0.set_fan_curve(curve)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SetFanPreset, set fan preset for active profile
|
||||||
|
#[inline]
|
||||||
|
pub fn set_fan_preset(&self, preset: u8) -> zbus::Result<()> {
|
||||||
|
self.0.set_fan_preset(preset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SetMaxFrequency, set max percentage of frequency for active profile
|
||||||
|
#[inline]
|
||||||
|
pub fn set_max_frequency(&self, percentage: u8) -> zbus::Result<()> {
|
||||||
|
self.0.set_max_frequency(percentage)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SetMinFrequency, set min percentage of frequency for active profile
|
||||||
|
#[inline]
|
||||||
|
pub fn set_min_frequency(&self, percentage: u8) -> zbus::Result<()> {
|
||||||
|
self.0.set_min_frequency(percentage)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SetTurbo, set turbo enable for active profile
|
||||||
|
#[inline]
|
||||||
|
pub fn set_turbo(&self, enable: bool) -> zbus::Result<()> {
|
||||||
|
self.0.set_turbo(enable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn write_fan_mode(&self, level: u8) -> Result<()> {
|
pub fn write_fan_mode(&self, level: u8) -> Result<()> {
|
||||||
self.0
|
self.0
|
||||||
.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level)).unwrap())
|
.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level)).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn write_command(&self, cmd: &ProfileEvent) -> Result<()> {
|
pub fn write_command(&self, cmd: &ProfileEvent) -> Result<()> {
|
||||||
self.0.set_profile(&serde_json::to_string(cmd).unwrap())
|
self.0.set_profile(&serde_json::to_string(cmd).unwrap())
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gumdrop = "^0.8"
|
gumdrop = "^0.8"
|
||||||
|
rog_aura = { path = "../rog-aura" }
|
||||||
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
||||||
serde = "^1.0"
|
serde = "^1.0"
|
||||||
serde_derive = "^1.0"
|
serde_derive = "^1.0"
|
||||||
|
|||||||
@@ -1,30 +1,6 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AuraError {
|
|
||||||
ParseColour,
|
|
||||||
ParseSpeed,
|
|
||||||
ParseDirection,
|
|
||||||
ParseBrightness,
|
|
||||||
ParseAnime,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for AuraError {
|
|
||||||
// This trait requires `fmt` with this exact signature.
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
AuraError::ParseColour => write!(f, "Could not parse colour"),
|
|
||||||
AuraError::ParseSpeed => write!(f, "Could not parse speed"),
|
|
||||||
AuraError::ParseDirection => write!(f, "Could not parse direction"),
|
|
||||||
AuraError::ParseBrightness => write!(f, "Could not parse brightness"),
|
|
||||||
AuraError::ParseAnime => write!(f, "Could not parse anime"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for AuraError {}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum GraphicsError {
|
pub enum GraphicsError {
|
||||||
ParseVendor,
|
ParseVendor,
|
||||||
@@ -42,27 +18,3 @@ impl fmt::Display for GraphicsError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Error for GraphicsError {}
|
impl Error for GraphicsError {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AnimeError {
|
|
||||||
InvalidBitmap,
|
|
||||||
Io(std::io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for AnimeError {
|
|
||||||
// This trait requires `fmt` with this exact signature.
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
AnimeError::InvalidBitmap => write!(f, "Bitmap is invalid"),
|
|
||||||
AnimeError::Io(e) => write!(f, "Could not open: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for AnimeError {}
|
|
||||||
|
|
||||||
impl From<std::io::Error> for AnimeError {
|
|
||||||
fn from(err: std::io::Error) -> Self {
|
|
||||||
AnimeError::Io(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,15 +5,9 @@
|
|||||||
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
||||||
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
|
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
|
||||||
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
||||||
pub const LED_MSG_LEN: usize = 17;
|
|
||||||
|
|
||||||
pub mod aura_modes;
|
|
||||||
|
|
||||||
pub mod profile;
|
pub mod profile;
|
||||||
|
|
||||||
/// Enables you to create fancy RGB effects
|
|
||||||
pub mod aura_perkey;
|
|
||||||
|
|
||||||
pub mod gfx_vendors;
|
pub mod gfx_vendors;
|
||||||
|
|
||||||
pub mod supported;
|
pub mod supported;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
use rog_aura::AuraModeNum;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::aura_modes::AuraModeNum;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SupportedFunctions {
|
pub struct SupportedFunctions {
|
||||||
pub anime_ctrl: AnimeSupportedFunctions,
|
pub anime_ctrl: AnimeSupportedFunctions,
|
||||||
|
|||||||
Reference in New Issue
Block a user