Compare commits
173 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bee5508099 | ||
|
|
c741204200 | ||
|
|
858c9841a7 | ||
|
|
fdc7d88a70 | ||
|
|
da3017bb89 | ||
|
|
641e762e80 | ||
|
|
25ecfda095 | ||
|
|
31af8f9511 | ||
|
|
8db783d9b4 | ||
|
|
45a354880a | ||
|
|
ca1c67e803 | ||
|
|
c819fa458a | ||
|
|
869ab90299 | ||
|
|
c40029f5e7 | ||
|
|
e864dfb0e7 | ||
|
|
476b394add | ||
|
|
4ea5480e66 | ||
|
|
cfc46a2b70 | ||
|
|
235763a615 | ||
|
|
6e19c16e70 | ||
|
|
6ea550b6ff | ||
|
|
dd30c8092b | ||
|
|
2bd751f841 | ||
|
|
7a6aafded7 | ||
|
|
940b93a75f | ||
|
|
5c70fec29a | ||
|
|
8ac505e0dd | ||
|
|
3bdb03b1d8 | ||
|
|
4ac4909881 | ||
|
|
ec5e6d2e7c | ||
|
|
5600c51ba0 | ||
|
|
cb5856c4dc | ||
|
|
aad6f6350b | ||
|
|
1ec45a6449 | ||
|
|
bb612283fe | ||
|
|
bcba11d4ec | ||
|
|
7eab94bc7f | ||
|
|
e73bbedb41 | ||
|
|
a83ccbd33d | ||
|
|
b5b7799018 | ||
|
|
24ecb92621 | ||
|
|
a811417f5d | ||
|
|
b012a01cad | ||
|
|
e6a9c88695 | ||
|
|
048a7afa55 | ||
|
|
53b854ef6d | ||
|
|
fac635d07d | ||
|
|
9cc62d63c9 | ||
|
|
ab3007d53d | ||
|
|
00839aaa6f | ||
|
|
5133d398eb | ||
|
|
90b711c7b9 | ||
|
|
ea5e5db490 | ||
|
|
ef6ca9e51e | ||
|
|
022a144705 | ||
|
|
8011ba3009 | ||
|
|
d93b870726 | ||
|
|
e4f79a3e6f | ||
|
|
54273cfb60 | ||
|
|
0dd4b2d6b5 | ||
|
|
a2d850bbcb | ||
|
|
19f82493de | ||
|
|
cbce854d1b | ||
|
|
ee0600d50d | ||
|
|
3d145ab9bd | ||
|
|
1cbffedaeb | ||
|
|
e3ecaa92bd | ||
|
|
067738b94f | ||
|
|
29b22cd18e | ||
|
|
c2aa81bfe3 | ||
|
|
5e9c612269 | ||
|
|
8dcb209026 | ||
|
|
bdb6c5b2ff | ||
|
|
a318fbceec | ||
|
|
8feacf863a | ||
|
|
0c62582515 | ||
|
|
3c575e4d2a | ||
|
|
dbfd73da5e | ||
|
|
b1ee449b97 | ||
|
|
245c035dc9 | ||
|
|
07daa0df61 | ||
|
|
c7893b16f9 | ||
|
|
8e8681c190 | ||
|
|
b26c6a55f0 | ||
|
|
93d472fe74 | ||
|
|
5469c73f11 | ||
|
|
ad95765954 | ||
|
|
e42a5bc3e9 | ||
|
|
28347e87eb | ||
|
|
b34cb672c3 | ||
|
|
559ddc9a22 | ||
|
|
a8c014881f | ||
|
|
f417032ed9 | ||
|
|
616fb3aea6 | ||
|
|
6e6e057995 | ||
|
|
085e63ebab | ||
|
|
fdadffcdde | ||
|
|
5f51527dd7 | ||
|
|
39525980a0 | ||
|
|
83a0b570e0 | ||
|
|
2bfbce36b0 | ||
|
|
2705b08dca | ||
|
|
2fca7a09c4 | ||
|
|
ef0da62c55 | ||
|
|
9dab120bcf | ||
|
|
14bf07ba79 | ||
|
|
e76d01eaed | ||
|
|
072a066f28 | ||
|
|
165c6f8ab3 | ||
|
|
5728a9af62 | ||
|
|
17a880b2c5 | ||
|
|
6ba9b9d75d | ||
|
|
eb1f6c83ce | ||
|
|
af653ea405 | ||
|
|
bc13891cdf | ||
|
|
aad4dc909e | ||
|
|
ad79adcbfa | ||
|
|
73b1a7050a | ||
|
|
762bfea102 | ||
|
|
b41fdf5cfe | ||
|
|
bf13ebebd3 | ||
|
|
3a73e3a526 | ||
|
|
1211400d7b | ||
|
|
ff9edb9876 | ||
|
|
20f8251dd3 | ||
|
|
902dfed67c | ||
|
|
5e08b4416d | ||
|
|
44c3ab7294 | ||
|
|
be40474f79 | ||
|
|
3654da2ff8 | ||
|
|
60bbad4ab6 | ||
|
|
0a59d5c041 | ||
|
|
1506fc44d3 | ||
|
|
aad31610f2 | ||
|
|
a6fe7645e9 | ||
|
|
4f8745ae19 | ||
|
|
5f4e950819 | ||
|
|
efc752cce6 | ||
|
|
37553a5fdd | ||
|
|
cd5a85a843 | ||
|
|
7385844a9b | ||
|
|
0b71104833 | ||
|
|
688e3a7358 | ||
|
|
58ff566d65 | ||
|
|
1332ac803c | ||
|
|
ba1d3f045d | ||
|
|
e0ed52092a | ||
|
|
921637f979 | ||
|
|
f6498337fe | ||
|
|
3a640a3269 | ||
|
|
e938f1f9ec | ||
|
|
600d0ae3d9 | ||
|
|
8569edf684 | ||
|
|
52af4ad2b2 | ||
|
|
cde1b4f252 | ||
|
|
2a4754cfc4 | ||
|
|
51c97fa350 | ||
|
|
c968dce009 | ||
|
|
b2b6707f2e | ||
|
|
7939b00aa3 | ||
|
|
30550aaa91 | ||
|
|
7ea1f41286 | ||
|
|
9608d190b9 | ||
|
|
3b9cf474a7 | ||
|
|
283cb7e589 | ||
|
|
5d87747d96 | ||
|
|
56285916cd | ||
|
|
a44a1bfa89 | ||
|
|
0c97cf710d | ||
|
|
62c7338b2d | ||
|
|
af24623178 | ||
|
|
facb7f7f49 | ||
|
|
e38ab624e9 |
12
.cargo-husky/hooks/pre-commit
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
echo '+cargo +nightly fmt --all -- --check'
|
||||
cargo +nightly fmt --all -- --check
|
||||
echo '+cargo clippy --all -- -D warnings'
|
||||
cargo clippy --all -- -D warnings
|
||||
echo '+cargo test --all'
|
||||
cargo test --all
|
||||
echo '+cargo cranky'
|
||||
cargo cranky
|
||||
10
.cargo-husky/hooks/pre-push
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
echo '+cargo +nightly fmt --all -- --check'
|
||||
cargo +nightly fmt --all -- --check
|
||||
echo '+cargo clippy --all -- -D warnings'
|
||||
cargo clippy --all -- -D warnings
|
||||
echo '+cargo cranky'
|
||||
cargo cranky
|
||||
23
.editorconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.rs]
|
||||
indent_size = 4
|
||||
|
||||
[tests/**/*.rs]
|
||||
charset = utf-8
|
||||
end_of_line = unset
|
||||
indent_size = unset
|
||||
indent_style = unset
|
||||
trim_trailing_whitespace = unset
|
||||
insert_final_newline = unset
|
||||
5
.gitignore
vendored
@@ -2,7 +2,10 @@
|
||||
vendor.tar.xz
|
||||
cargo-config
|
||||
.idea
|
||||
vendor
|
||||
vendor-*
|
||||
vendor_*
|
||||
.vscode-ctags
|
||||
.vscode
|
||||
.vscode
|
||||
.~lock.*
|
||||
*.ods#
|
||||
@@ -1,27 +1,84 @@
|
||||
image: rustdocker/rust:stable
|
||||
image: rust:latest
|
||||
|
||||
.rust_cache: &rust_cache
|
||||
cache:
|
||||
# key: $CI_COMMIT_REF_SLUG
|
||||
paths:
|
||||
# Don't include `incremental` to save space
|
||||
# Debug
|
||||
- target/debug/build/
|
||||
- target/debug/deps/
|
||||
- target/debug/.fingerprint/
|
||||
- target/debug/.cargo-lock
|
||||
# Release
|
||||
- target/release/build/
|
||||
- target/release/deps/
|
||||
- target/release/.fingerprint/
|
||||
- target/release/.cargo-lock
|
||||
|
||||
before_script:
|
||||
- apt-get update -qq && apt-get install -y -qq libdbus-1-dev libclang-dev libudev-dev
|
||||
- apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev grep llvm clang libclang-dev
|
||||
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
- format
|
||||
- check
|
||||
- test
|
||||
- release
|
||||
- deploy
|
||||
|
||||
format:
|
||||
except:
|
||||
- tags
|
||||
<<: *rust_cache
|
||||
script:
|
||||
- echo "nightly" > rust-toolchain
|
||||
- rustup component add rustfmt
|
||||
- cargo fmt --check
|
||||
|
||||
check:
|
||||
except:
|
||||
- tags
|
||||
<<: *rust_cache
|
||||
script:
|
||||
- rustup component add clippy
|
||||
- cargo check
|
||||
# deny currently catches too much
|
||||
#- cargo install cargo-deny && cargo deny
|
||||
- cargo install cargo-cranky && cargo cranky
|
||||
|
||||
test:
|
||||
except:
|
||||
- tags
|
||||
<<: *rust_cache
|
||||
script:
|
||||
- cargo check #+nightly check --features "clippy"
|
||||
- mkdir -p .git/hooks > /dev/null
|
||||
- cargo test
|
||||
|
||||
build:
|
||||
release:
|
||||
only:
|
||||
- main
|
||||
- tags
|
||||
<<: *rust_cache
|
||||
script:
|
||||
- make && make vendor
|
||||
artifacts:
|
||||
paths:
|
||||
- vendor_asus-nb-ctrl_*.tar.xz
|
||||
- vendor_asusctl_*.tar.xz
|
||||
- cargo-config
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
only:
|
||||
- tags
|
||||
<<: *rust_cache
|
||||
script:
|
||||
- cargo doc --document-private-items --no-deps --workspace
|
||||
- rm -rf public
|
||||
- mkdir public
|
||||
- cp -R target/doc/* public
|
||||
- cp misc/index.html public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: normal
|
||||
|
||||
|
||||
159
CHANGELOG.md
@@ -4,7 +4,160 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased ]
|
||||
## [Unreleased]
|
||||
## [v4.6.1]
|
||||
### Added
|
||||
- Support for G733Z LED modes
|
||||
- Support for GU604V LED modes
|
||||
- Support for GX650P LED modes
|
||||
- Support for GV604I LED modes
|
||||
- Support for FX516P LED modes (this laptop still has further issues, will require a patched kernel when patch is ready)
|
||||
- Add device code for the Z13 ACRNM keyboard (requires kernel patch, in progress)
|
||||
- Support for GV301VIC LED modes
|
||||
- Add device code for the plain Z13 keyboard (requires kernel patch, in progress)
|
||||
- Support for GV301V LED modes
|
||||
### Changed
|
||||
- Adjustments to Anime system events thread
|
||||
- Add "sleep" animetion config options to anime config
|
||||
- rog-control-center dark/light mode persistency
|
||||
- Adjustments to keyboard detection
|
||||
- Better support of using supergfxctl when available (tray icon and menu)
|
||||
- Check supergfx version before enabling use in tray (require 5.1.0+)
|
||||
- Update allowed Aura modes on asusd restart if changed
|
||||
- Set tray icon for dgpu to "On" if in Vfio mode to prevent confusion
|
||||
- Add support for Logout/Reboot in notification for KDE
|
||||
|
||||
## [v4.6.0]
|
||||
### Added
|
||||
- Support for GL703GE keyboard layout
|
||||
- Support for G533Z modes and keyboard layout
|
||||
### Changed
|
||||
- Better handling of `/etc/asusd` not existing
|
||||
- Better handling of non-existant config files
|
||||
- Move all config handling to generic traits for better consistency
|
||||
- Re-parse all configs to RON format
|
||||
- Move fan-curve config to own config file
|
||||
- Added option to set `disable_nvidia_powerd_on_battery`
|
||||
- Add short log entry to throttle_thermal_policy change detection
|
||||
- ROGCC: Don't notify user if changing to same mux mode
|
||||
- ROGCC: Add CLI opt for loading a keyboard layout for testing, with live-reload on file change
|
||||
- ROGCC: Add CLI opt for viewing all layout files + filenames to help find a layout matching your laptop
|
||||
+ Both of these options would hopefully be temporary and replaced with a "wizard" GUI helper
|
||||
- Fix profile controller not detecting if platform_profile is changed
|
||||
- Fix remove the leftover initial config writes on `new()` for some controllers to prevent resetting settings on startup
|
||||
+ refactor the loading of systemd curve defaults and config file
|
||||
### BREAKING
|
||||
- Rename aura dbus method from `per_key_raw` to `direct_addressing_raw` and add doc comment
|
||||
- Changes to aura.conf:
|
||||
- Changes to asusd-ledmodes.toml:
|
||||
+ Rename `standard` to `basic_modes`
|
||||
+ Rename `multizone` to `basic_zones`
|
||||
+ Raname `per_key` to `advanced` and change type from `bool` to `AdvancedAuraType`
|
||||
+ Removed `prod_family`
|
||||
+ Split all entries to `board_name` (separating `board_names`) (now a huge file)
|
||||
+ removed `asusd-ledmodes.toml` in favour of `aura_support.ron` due to an unsupported type in toml
|
||||
- Rename and adjust `LedSupportedFunctions` to closely match the above
|
||||
|
||||
## [v4.5.8]
|
||||
### Changed
|
||||
- Fix incorrect stop/start order of nvidia-powerd on AC plug/unplug
|
||||
|
||||
## [v4.5.7]
|
||||
### Changed
|
||||
- ROGCC: Don't notify user if changing to same mux mode
|
||||
-
|
||||
|
||||
## [v4.5.7]
|
||||
### Changed
|
||||
- ROGCC: Don't notify user if changing to same mux mode
|
||||
- asusd: don't block on systemd-unit change: removes all shoddy external command calls in favour of async dbus calls
|
||||
|
||||
## [v4.5.6]
|
||||
### Changed
|
||||
- Fix tasks not always running correctly on boot/sleep/wake/shutdown by finishing the move to async
|
||||
- Change how the profile/fan change task monitors changes due to TUF laptops behaving slightly different
|
||||
- ROGCC: Better handle the use of GPU MUX without supergfxd
|
||||
- ROGCC: Track if reboot required when not using supergfxd
|
||||
- Add env var for logging levels to daemon and gui (`RUST_LOG=<error|warn|info|debug|trace>`)
|
||||
- ROGCC: Very basic support for running a command on AC/Battery switching, this is in config at `~/.config/rog/rog-control-center.cfg`, and for now must be edited by hand and ROGCC restarted (run ROGCC in BG to use effectively)
|
||||
+ Run ROGCC from terminal to see errors of the AC/Battery command
|
||||
+ Support for editing via ROGCC GUI will come in future
|
||||
+ This is ideal for userspace tasks
|
||||
- asusd: Very basic support for running a command on AC/Battery switching, this is in config at `/etc/asusd/asusd.conf`. A restart of asusd is not required if edited.
|
||||
+ This is ideal for tasks that require root access (BE SAFE!)
|
||||
- The above AC/Battery commands are probably best set to run a script for more complex tasks
|
||||
- asusd: check if nvidia-powerd enabled before toggling
|
||||
|
||||
## [v4.5.5]
|
||||
### Changed
|
||||
- remove an unwrap() causing panic on main ROGCC thread
|
||||
|
||||
## [v4.5.4]
|
||||
### Changed
|
||||
- ROGCC:: Allow ROGCC to run without supergfxd
|
||||
- ROGCC: Tray/notifs now reads dGPU status directly via supergfx crate (supergfxd not required)
|
||||
- Add rust-toolchain to force minimum rust version
|
||||
|
||||
## [v4.5.3]
|
||||
### Changed
|
||||
- Adjust how fan graph in ROGCC works, deny incorrect graphs
|
||||
- Fix to apply the fan curve change in ROGCC to the correct profile
|
||||
- Support for G713RS LED modes (Author: Peter Ivanov)
|
||||
- Support for G713RM LED modes (Author: maxbachmann)
|
||||
- Fix VivoBook detection
|
||||
- Update dependencies to get latest winit crate (fixes various small issues)
|
||||
|
||||
## [v4.5.2]
|
||||
### Changed
|
||||
- Update dependencies and bump version
|
||||
|
||||
## [v4.5.1]
|
||||
### Added
|
||||
- Support for FA506IE LED modes (Author: Herohtar)
|
||||
### Changed
|
||||
- Add a basic system tray with dGPU status and gpu mode switch actions
|
||||
- Fixup some notifications in ROGCC
|
||||
- Add config options for notifications for ROGCC
|
||||
- Share states with tray process in ROGCC
|
||||
- Share tates with tray process in ROGCC
|
||||
|
||||
## [v4.5.0]
|
||||
### Added
|
||||
- intofy watches on:
|
||||
- `charge_control_end_threshold`
|
||||
- `panel_od`
|
||||
- `gpu_mux_mode`
|
||||
- `platform_profile`
|
||||
- keyboard brightness
|
||||
- These allow for updating any associated config and sending dbus notifications.
|
||||
- New dbus methods
|
||||
- `DgpuDisable`
|
||||
- `SetDgpuDisable`
|
||||
- `NotifyDgpuDisable`
|
||||
- `EgpuEnable`
|
||||
- `SetEgpuEnable`
|
||||
- `NotifyEgpuEnable`
|
||||
- `MainsOnline` (This is AC, check if plugged in or not)
|
||||
- `NotifyMainsOnline`
|
||||
- `nvidia-powerd.service` will now enable or disable depending on the AC power state
|
||||
and on resume/boot (hybrid boot). It has been proven that this nvidia daemon can be
|
||||
problematic when on battery, not allowing the dgpu to suspend within decent time and
|
||||
sometimes blocking it completely.
|
||||
- Notification to rog-control-center of dGPU state change
|
||||
### Changed
|
||||
- Use loops to ensure that mutex is gained for LED changes.
|
||||
- asusctl now uses tokio for async runtime. This helps simplify some code.
|
||||
- Properly fix notifs used in rog-control-center
|
||||
### Breaking
|
||||
- DBUS: all charge control methods renamed to:
|
||||
- `ChargeControlEndThreshold`
|
||||
- `SetChargeControlEndThreshold`
|
||||
- `NotifyChargeControlEndThreshold`
|
||||
- DBUS: all panel overdrive methods renamed to:
|
||||
- `PanelOd` (from PanelOverdrive)
|
||||
- `SetPanelOd`
|
||||
- `NotifyPanelOd`
|
||||
- Path `/org/asuslinux/Charge` changed to `/org/asuslinux/Power`
|
||||
|
||||
## [v4.4.0] - 2022-08-29
|
||||
### Added
|
||||
@@ -477,6 +630,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Fix small deadlock with awaits
|
||||
|
||||
## [1.0.0] - 2020-08-13
|
||||
|
||||
- Major fork and refactor to use asus-hid patch for ASUS N-Key device
|
||||
## [1.0.0]
|
||||
2730
Cargo.lock
generated
47
Cargo.toml
@@ -1,5 +1,43 @@
|
||||
[workspace]
|
||||
members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"]
|
||||
members = ["asusctl", "config-traits", "daemon", "daemon-user", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"]
|
||||
|
||||
[workspace.package]
|
||||
version = "4.6.1"
|
||||
|
||||
[workspace.dependencies]
|
||||
async-trait = "^0.1"
|
||||
tokio = { version = "^1.23.0", features = ["macros", "rt-multi-thread", "time", "sync"]}
|
||||
concat-idents = "^1.1"
|
||||
dirs = "^4.0"
|
||||
smol = "^1.3"
|
||||
|
||||
zbus = "^3.6"
|
||||
logind-zbus = { version = "^3.1.0" } #, default-features = false, features = ["non_blocking"] }
|
||||
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
serde_json = "^1.0"
|
||||
toml = "^0.5.10"
|
||||
ron = "*"
|
||||
|
||||
log = "^0.4"
|
||||
env_logger = "^0.10.0"
|
||||
|
||||
glam = { version = "^0.22", features = ["serde"] }
|
||||
gumdrop = "^0.8"
|
||||
udev = "^0.7"
|
||||
rusb = "^0.9"
|
||||
sysfs-class = "^0.1.3"
|
||||
inotify = "^0.10.0"
|
||||
|
||||
png_pong = "^0.8"
|
||||
pix = "^0.13"
|
||||
tinybmp = "^0.4.0"
|
||||
gif = "^0.12.0"
|
||||
|
||||
versions = "4.1"
|
||||
|
||||
notify-rust = { git = "https://github.com/flukejones/notify-rust.git", default-features = false, features = ["z"] }
|
||||
|
||||
[profile.release]
|
||||
# thin = 57s, asusd = 9.0M
|
||||
@@ -10,9 +48,14 @@ opt-level = 3
|
||||
panic = "abort"
|
||||
|
||||
[profile.dev]
|
||||
debug = false
|
||||
debug = true
|
||||
opt-level = 1
|
||||
|
||||
[profile.bench]
|
||||
debug = false
|
||||
opt-level = 3
|
||||
|
||||
[workspace.dependencies.cargo-husky]
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = ["user-hooks"]
|
||||
121
Cranky.toml
Normal file
@@ -0,0 +1,121 @@
|
||||
# https://github.com/ericseppanen/cargo-cranky
|
||||
# cargo install cargo-cranky && cargo cranky
|
||||
|
||||
error = [
|
||||
"clippy::all",
|
||||
"clippy::await_holding_lock",
|
||||
"clippy::bool_to_int_with_if",
|
||||
"clippy::char_lit_as_u8",
|
||||
"clippy::checked_conversions",
|
||||
"clippy::dbg_macro",
|
||||
"clippy::debug_assert_with_mut_call",
|
||||
"clippy::disallowed_methods",
|
||||
"clippy::disallowed_script_idents",
|
||||
"clippy::doc_link_with_quotes",
|
||||
"clippy::doc_markdown",
|
||||
"clippy::empty_enum",
|
||||
"clippy::enum_glob_use",
|
||||
"clippy::equatable_if_let",
|
||||
"clippy::exit",
|
||||
"clippy::expl_impl_clone_on_copy",
|
||||
"clippy::explicit_deref_methods",
|
||||
"clippy::explicit_into_iter_loop",
|
||||
"clippy::explicit_iter_loop",
|
||||
"clippy::fallible_impl_from",
|
||||
"clippy::filter_map_next",
|
||||
"clippy::flat_map_option",
|
||||
"clippy::float_cmp_const",
|
||||
"clippy::fn_params_excessive_bools",
|
||||
"clippy::fn_to_numeric_cast_any",
|
||||
"clippy::from_iter_instead_of_collect",
|
||||
"clippy::if_let_mutex",
|
||||
"clippy::implicit_clone",
|
||||
"clippy::imprecise_flops",
|
||||
"clippy::index_refutable_slice",
|
||||
"clippy::inefficient_to_string",
|
||||
"clippy::invalid_upcast_comparisons",
|
||||
"clippy::iter_not_returning_iterator",
|
||||
"clippy::iter_on_empty_collections",
|
||||
"clippy::iter_on_single_items",
|
||||
"clippy::large_digit_groups",
|
||||
"clippy::large_stack_arrays",
|
||||
"clippy::large_types_passed_by_value",
|
||||
"clippy::let_unit_value",
|
||||
"clippy::linkedlist",
|
||||
"clippy::lossy_float_literal",
|
||||
"clippy::macro_use_imports",
|
||||
"clippy::manual_assert",
|
||||
"clippy::manual_instant_elapsed",
|
||||
"clippy::manual_ok_or",
|
||||
"clippy::manual_string_new",
|
||||
"clippy::map_err_ignore",
|
||||
"clippy::map_flatten",
|
||||
"clippy::map_unwrap_or",
|
||||
"clippy::match_on_vec_items",
|
||||
"clippy::match_same_arms",
|
||||
"clippy::match_wild_err_arm",
|
||||
"clippy::match_wildcard_for_single_variants",
|
||||
"clippy::mem_forget",
|
||||
"clippy::mismatched_target_os",
|
||||
"clippy::mismatching_type_param_order",
|
||||
"clippy::missing_enforced_import_renames",
|
||||
# "clippy::missing_errors_doc",
|
||||
"clippy::missing_safety_doc",
|
||||
"clippy::mut_mut",
|
||||
"clippy::mutex_integer",
|
||||
"clippy::needless_borrow",
|
||||
"clippy::needless_continue",
|
||||
"clippy::needless_for_each",
|
||||
"clippy::needless_pass_by_value",
|
||||
"clippy::negative_feature_names",
|
||||
"clippy::nonstandard_macro_braces",
|
||||
"clippy::option_option",
|
||||
"clippy::path_buf_push_overwrite",
|
||||
"clippy::ptr_as_ptr",
|
||||
"clippy::rc_mutex",
|
||||
"clippy::ref_option_ref",
|
||||
"clippy::rest_pat_in_fully_bound_structs",
|
||||
"clippy::same_functions_in_if_condition",
|
||||
"clippy::semicolon_if_nothing_returned",
|
||||
"clippy::single_match_else",
|
||||
"clippy::str_to_string",
|
||||
"clippy::string_add_assign",
|
||||
"clippy::string_add",
|
||||
"clippy::string_lit_as_bytes",
|
||||
"clippy::string_to_string",
|
||||
"clippy::todo",
|
||||
"clippy::trailing_empty_array",
|
||||
"clippy::trait_duplication_in_bounds",
|
||||
"clippy::unimplemented",
|
||||
"clippy::unnecessary_wraps",
|
||||
"clippy::unnested_or_patterns",
|
||||
"clippy::unused_peekable",
|
||||
"clippy::unused_rounding",
|
||||
# "clippy::unused_self",
|
||||
"clippy::useless_transmute",
|
||||
"clippy::verbose_file_reads",
|
||||
"clippy::zero_sized_map_values",
|
||||
"elided_lifetimes_in_paths",
|
||||
"future_incompatible",
|
||||
"nonstandard_style",
|
||||
"rust_2018_idioms",
|
||||
"rust_2021_prelude_collisions",
|
||||
"rustdoc::missing_crate_level_docs",
|
||||
"semicolon_in_expressions_from_macros",
|
||||
"trivial_numeric_casts",
|
||||
"unused_extern_crates",
|
||||
"unused_import_braces",
|
||||
"unused_lifetimes",
|
||||
]
|
||||
|
||||
allow = [
|
||||
# TODO(emilk): enable more lints
|
||||
"clippy::cloned_instead_of_copied",
|
||||
"clippy::derive_partial_eq_without_eq",
|
||||
"clippy::type_complexity",
|
||||
"clippy::undocumented_unsafe_blocks",
|
||||
"trivial_casts",
|
||||
"unsafe_op_in_unsafe_fn", # `unsafe_op_in_unsafe_fn` may become the default in future Rust versions: https://github.com/rust-lang/rust/issues/71668
|
||||
"unused_qualifications",
|
||||
]
|
||||
|
||||
191
MANUAL.md
@@ -47,35 +47,7 @@ The LED controller (e.g, aura) enables setting many of the factory modes availab
|
||||
|
||||
#### Supported laptops
|
||||
|
||||
Models GA401, GA502, GU502 support LED brightness change only (no RGB). However the GA401Q model can actually use three modes; static, breathe, and pulse, plus also use red to control the LED brightness intensity.
|
||||
|
||||
All models that have any form of LED mode control need to be enabled via the config file at `/etc/asusd/asusd-ledmodes.toml`. Unfortunately ASUS doesn't provide any easy way to find all the supported modes for all laptops (not even through Armory Crate and its various files, that progrma downloads only the required settings for the laptop it runs on) so each model must be added as needed.
|
||||
|
||||
#### Config options
|
||||
|
||||
The defaults are located at `/etc/asusd/asusd-ledmodes.toml`, and on `asusd` start it creates `/etc/asusd/aura.conf` whcih stores the per-mode settings. If you edit the defaults file you must remove `/etc/asusd/aura.conf` and restart `asusd.service` with `systemctl restart asusd`.
|
||||
|
||||
##### /etc/asusd/asusd-ledmodes.toml
|
||||
|
||||
Example:
|
||||
```toml
|
||||
[[led_data]]
|
||||
prod_family = "Strix"
|
||||
board_names = ["GL504G"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4", "Logo", "BarLeft", "BarRight"]
|
||||
per_key = false
|
||||
```
|
||||
|
||||
1. `prod_family`: you can find this in `journalctl -b -u asusd`, or `cat /sys/class/dmi/id/product_name`. It should be copied as written. There can be multiple `led-data` groups of the same `prod_family` with differing `board_names`.
|
||||
2. `board_names`: is an array of board names in this product family. Find this in the journal as above or by `cat /sys/class/dmi/id/board_name`.
|
||||
3. `standard` are the factory preset modes, the names should corrospond to Armory Crate names
|
||||
4. `multizone`: some models have 4 to 7 zones of LED control as shown in the example. If the laptop has no zones then an empty array will suffice.
|
||||
5. `per_key`: enable per-key RGB effects. The keyboard must support this or it has no effect.
|
||||
|
||||
##### /etc/asusd/aura.conf
|
||||
|
||||
This file can be manually edited if desired, but the `asusctl` CLI tool, or dbus methods are the preferred method. Any manual changes to this file mean that the `asusd.service` will need to be restarted, or you need to cycle between modes to force a reload.
|
||||
There are over 60 supported laptops as of 01-01-2023. Please see [the rog-aura crate readme for further details](/rog-aura/README.md).
|
||||
|
||||
### Charge control
|
||||
|
||||
@@ -145,87 +117,100 @@ I'm unsure of how many laptops this works on, so please try it.
|
||||
|
||||
An Aura config itself is a file with contents:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "aura-default",
|
||||
"aura": [
|
||||
{
|
||||
"Breathe": {
|
||||
"led_type": {
|
||||
"Key": "W"
|
||||
},
|
||||
"start_colour1": [
|
||||
255,
|
||||
0,
|
||||
20
|
||||
```ron
|
||||
(
|
||||
name: "aura-default",
|
||||
aura: (
|
||||
effects: [
|
||||
Breathe((
|
||||
led: W,
|
||||
start_colour1: (255, 0, 20),
|
||||
start_colour2: (20, 255, 0),
|
||||
speed: Low,
|
||||
)),
|
||||
Breathe((
|
||||
led: A,
|
||||
start_colour1: (255, 0, 20),
|
||||
start_colour2: (20, 255, 0),
|
||||
speed: Low,
|
||||
)),
|
||||
Breathe((
|
||||
led: S,
|
||||
start_colour1: (255, 0, 20),
|
||||
start_colour2: (20, 255, 0),
|
||||
speed: Low,
|
||||
)),
|
||||
Breathe((
|
||||
led: D,
|
||||
start_colour1: (255, 0, 20),
|
||||
start_colour2: (20, 255, 0),
|
||||
speed: Low,
|
||||
)),
|
||||
Breathe((
|
||||
led: F,
|
||||
start_colour1: (255, 0, 0),
|
||||
start_colour2: (255, 0, 0),
|
||||
speed: High,
|
||||
)),
|
||||
Static((
|
||||
led: RCtrl,
|
||||
colour: (0, 0, 255),
|
||||
)),
|
||||
Static((
|
||||
led: LCtrl,
|
||||
colour: (0, 0, 255),
|
||||
)),
|
||||
Static((
|
||||
led: Esc,
|
||||
colour: (0, 0, 255),
|
||||
)),
|
||||
DoomFlicker((
|
||||
led: N9,
|
||||
start_colour: (0, 0, 255),
|
||||
max_percentage: 80,
|
||||
min_percentage: 40,
|
||||
)),
|
||||
],
|
||||
"start_colour2": [
|
||||
20,
|
||||
255,
|
||||
0
|
||||
],
|
||||
"speed": "Low"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Static": {
|
||||
"led_type": {
|
||||
"Key": "Esc"
|
||||
},
|
||||
"colour": [
|
||||
0,
|
||||
0,
|
||||
255
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Flicker": {
|
||||
"led_type": {
|
||||
"Key": "N9"
|
||||
},
|
||||
"start_colour": [
|
||||
0,
|
||||
0,
|
||||
255
|
||||
],
|
||||
"max_percentage": 80,
|
||||
"min_percentage": 40
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
zoned: false,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
If your laptop supports multizone, `"led_type"` can also be `"Zone": <one of the following>`
|
||||
- `"None"`
|
||||
- `"KeyboardLeft"`
|
||||
- `"KeyboardCenterLeft"`
|
||||
- `"KeyboardCenterRight"`
|
||||
- `"KeyboardRight"`
|
||||
- `"LightbarRight"`
|
||||
- `"LightbarRightCorner"`
|
||||
- `"LightbarRightBottom"`
|
||||
- `"LightbarLeftBottom"`
|
||||
- `"LightbarLeftCorner"`
|
||||
- `"LightbarLeft"`
|
||||
If your laptop supports multizone, `"led"` can also be `"Zone": <one of the following>`
|
||||
- `SingleZone` // Keyboards with only one zone
|
||||
- `ZonedKbLeft` // keyboard left
|
||||
- `ZonedKbLeftMid` // keyboard left-middle
|
||||
- `ZonedKbRightMid` // etc
|
||||
- `ZonedKbRight`
|
||||
- `LightbarRight`
|
||||
- `LightbarRightCorner`
|
||||
- `LightbarRightBottom`
|
||||
- `LightbarLeftBottom`
|
||||
- `LightbarLeftCorner`
|
||||
- `LightbarLeft`
|
||||
|
||||
Single zone example:
|
||||
|
||||
```ron
|
||||
(
|
||||
name: "aura-default",
|
||||
aura: (
|
||||
effects: [
|
||||
DoomFlicker((
|
||||
led: SingleZone,
|
||||
start_colour: (200, 40, 5),
|
||||
max_percentage: 80,
|
||||
min_percentage: 40,
|
||||
)),
|
||||
],
|
||||
zoned: true,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
At the moment there are only three effects available as shown in the example. More will come in the future
|
||||
but this may take me some time.
|
||||
|
||||
**Aura layouts**: `asusd-user` does its best to find a suitable layout to use based on `/sys/class/dmi/id/board_name`.
|
||||
It looks at each of the files in `/usr/share/rog-gui/layouts/` and matches against the toml block looking like:
|
||||
```toml
|
||||
matches = [
|
||||
'GX502',
|
||||
'GU502',
|
||||
]
|
||||
```
|
||||
|
||||
My laptop is a `GX502GW`, so `GX502` is a match. Note that these layouts are the physical representation of
|
||||
the keyboard and are used in the GUI also. The config that tells if per-key is supported is located in
|
||||
`/etc/asusd/asusd-ledmodes.toml`
|
||||
|
||||
#### Config options: AniMe
|
||||
|
||||
`~/.config/rog/rog-user.cfg` contains a setting `"active_anime": "<FILENAME>"` where `<FILENAME>` is the name of the AniMe config to use, located in the same directory and without the file postfix, e.g, `"active_anime": "anime-doom"`
|
||||
|
||||
30
Makefile
@@ -1,4 +1,4 @@
|
||||
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' daemon/Cargo.toml | cut -d'"' -f2)
|
||||
VERSION := $(shell /usr/bin/grep -Pm1 'version = "(\d.\d.\d)"' Cargo.toml | cut -d'"' -f2)
|
||||
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = ${INSTALL} -D -m 0755
|
||||
@@ -15,8 +15,7 @@ BIN_ROG := rog-control-center
|
||||
BIN_C := asusctl
|
||||
BIN_D := asusd
|
||||
BIN_U := asusd-user
|
||||
BIN_N := asus-notify
|
||||
LEDCFG := asusd-ledmodes.toml
|
||||
LEDCFG := aura_support.ron
|
||||
|
||||
SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
|
||||
|
||||
@@ -39,28 +38,31 @@ clean:
|
||||
distclean:
|
||||
rm -rf .cargo vendor vendor.tar.xz
|
||||
|
||||
install:
|
||||
install-program:
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_ROG)" "$(DESTDIR)$(bindir)/$(BIN_ROG)"
|
||||
$(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).desktop" "$(DESTDIR)$(datarootdir)/applications/$(BIN_ROG).desktop"
|
||||
$(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/$(BIN_ROG).png"
|
||||
cd rog-aura/data/layouts && find . -type f -name "*.toml" -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/rog-gui/layouts/{}" \;
|
||||
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)"
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||
|
||||
install-data:
|
||||
$(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).desktop" "$(DESTDIR)$(datarootdir)/applications/$(BIN_ROG).desktop"
|
||||
$(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/$(BIN_ROG).png"
|
||||
cd rog-aura/data/layouts && find . -type f -name "*.ron" -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/rog-gui/layouts/{}" \;
|
||||
|
||||
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
|
||||
$(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)"
|
||||
$(INSTALL_DATA) "./rog-aura/data/$(LEDCFG)" "$(DESTDIR)$(datarootdir)/asusd/$(LEDCFG)"
|
||||
$(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
|
||||
|
||||
$(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
|
||||
$(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
|
||||
$(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
|
||||
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_blue.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_blue.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_orange.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_orange.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_white.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_white.png"
|
||||
|
||||
$(INSTALL_DATA) "./data/icons/scalable/gpu-compute.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg"
|
||||
$(INSTALL_DATA) "./data/icons/scalable/gpu-hybrid.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg"
|
||||
@@ -71,6 +73,8 @@ install:
|
||||
|
||||
cd rog-anime/data && find "./anime" -type f -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \;
|
||||
|
||||
install: install-program install-data
|
||||
|
||||
uninstall:
|
||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_ROG)"
|
||||
rm -r "$(DESTDIR)$(datarootdir)/applications/$(BIN_ROG).desktop"
|
||||
@@ -78,12 +82,10 @@ uninstall:
|
||||
|
||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
|
||||
rm -f "$(DESTDIR)/etc/asusd/$(LEDCFG)"
|
||||
rm -f "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
|
||||
rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
|
||||
rm -r "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
|
||||
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
|
||||
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
|
||||
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||
@@ -114,5 +116,9 @@ ifeq ($(VENDORED),1)
|
||||
tar pxf vendor_asusctl_$(VERSION).tar.xz
|
||||
endif
|
||||
cargo build $(ARGS)
|
||||
strip -s ./target/release/$(BIN_C)
|
||||
strip -s ./target/release/$(BIN_D)
|
||||
strip -s ./target/release/$(BIN_U)
|
||||
strip -s ./target/release/$(BIN_ROG)
|
||||
|
||||
.PHONY: all clean distclean install uninstall update build
|
||||
|
||||
33
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/)
|
||||
|
||||
**WARNING:** Do not run the main branch of this repo unless you have all the asus-wmi kernel patches. You should use stable kernels + tagged releases.
|
||||
**WARNING:** Many features are developed in tandem with kernel patches. If you see a feature is missing you either need a patched kernel, or v6.1 which has all my work merged upstream.
|
||||
|
||||
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
|
||||
but can also be used with non-asus laptops with reduced features.
|
||||
@@ -13,6 +13,8 @@ Now includes a GUI, `rog-control-center`.
|
||||
|
||||
**The minimum supported kernel version is 5.17**
|
||||
|
||||
**For TUF laptops, the minimum supported kernel version is 6.1**
|
||||
|
||||
## Goals
|
||||
|
||||
1. To provide an interface for rootless control of some system functions most users wish to control such as fan speeds, keyboard LEDs, graphics modes.
|
||||
@@ -43,8 +45,6 @@ Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
||||
then it may work without tweaks. Technically all other functions except the LED
|
||||
and AniMe parts should work regardless of your latop make.
|
||||
|
||||
**TUF Laptops**: now supported provided the kernel is patched. These patches are submitted upstream and will be in version 6.1.x of the kernel (or thereabouts). See the blog on asus-linux.org for more info.
|
||||
|
||||
## Implemented
|
||||
|
||||
- [X] System daemon
|
||||
@@ -74,14 +74,33 @@ Requirements are rust >= 1.57 installed from rustup.io if the distro provided ve
|
||||
|
||||
**Ubuntu (unsuported):**
|
||||
|
||||
apt install libclang-dev libudev-dev
|
||||
apt install libgtk-3-dev libpango1.0-dev libgdk-pixbuf-2.0-dev libglib2.0-dev cmake libclang-dev libudev-dev libayatana-appindicator3-1
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source "$HOME/.cargo/env"
|
||||
make
|
||||
sudo make install
|
||||
|
||||
**popos (unsuported):**
|
||||
|
||||
sudo apt install cmake libclang-dev libudev-dev libgtk-3-dev libclang-dev libglib2.0-dev libatkmm-1.6-dev libpangomm-1.4-dev librust-gdk-pixbuf-dev
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source "$HOME/.cargo/env"
|
||||
make
|
||||
sudo make install
|
||||
|
||||
|
||||
**fedora:**
|
||||
|
||||
dnf install clang-devel systemd-devel cargo
|
||||
dnf install cmake clang-devel systemd-devel glib2-devel cairo-devel atkmm-devel pangomm-devel gdk-pixbuf2-devel gtk3-devel libappindicator-gtk3
|
||||
make
|
||||
sudo make install
|
||||
|
||||
**openSUSE:**
|
||||
|
||||
Works with KDE Plasma (without GTK packages)
|
||||
|
||||
zypper in -t pattern devel_basis
|
||||
zypper in rustup make cmake systemd-devel clang-devel llvm-devel gdk-pixbuf-devel cairo-devel pango-devel freetype-devel gtk3-devel libexpat-devel libayatana-indicator3-7
|
||||
make
|
||||
sudo make install
|
||||
|
||||
@@ -107,6 +126,10 @@ You may also need to activate the service for debian install. If running Pop!_OS
|
||||
|
||||
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
|
||||
|
||||
# Contributing
|
||||
|
||||
See `CONTRIBUTING.md`. Additionally, also do `cargo clean` and `cargo test` on first checkout to ensure the commit hooks are used (via `cargo-husky`).
|
||||
|
||||
# OTHER
|
||||
|
||||
## Supporting more laptops
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
[package]
|
||||
name = "asus-notify"
|
||||
version = "3.1.0"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
zbus = "^2.2"
|
||||
# serialisation
|
||||
serde_json = "^1.0"
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_aura = { path = "../rog-aura" }
|
||||
rog_platform = { path = "../rog-platform" }
|
||||
rog_profiles = { path = "../rog-profiles" }
|
||||
smol = "^1.2"
|
||||
|
||||
[dependencies.notify-rust]
|
||||
version = "^4.3"
|
||||
default-features = false
|
||||
features = ["z"]
|
||||
@@ -1,166 +0,0 @@
|
||||
use notify_rust::{Hint, Notification, NotificationHandle};
|
||||
use rog_aura::AuraEffect;
|
||||
use rog_dbus::{
|
||||
zbus_charge::ChargeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy,
|
||||
zbus_profile::ProfileProxy,
|
||||
};
|
||||
use rog_profiles::Profile;
|
||||
use smol::{future, Executor};
|
||||
use std::{
|
||||
error::Error,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use zbus::export::futures_util::StreamExt;
|
||||
|
||||
const NOTIF_HEADER: &str = "ROG Control";
|
||||
|
||||
macro_rules! notify {
|
||||
($notifier:ident, $last_notif:ident, $data:expr) => {
|
||||
if let Some(notif) = $last_notif.take() {
|
||||
notif.close();
|
||||
}
|
||||
if let Ok(x) = $notifier($data) {
|
||||
$last_notif.replace(x);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! base_notification {
|
||||
($body:expr) => {
|
||||
Notification::new()
|
||||
.summary(NOTIF_HEADER)
|
||||
.body($body)
|
||||
.timeout(2000)
|
||||
.show()
|
||||
};
|
||||
}
|
||||
|
||||
type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("asus-notify version {}", env!("CARGO_PKG_VERSION"));
|
||||
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||
|
||||
let last_notification: SharedHandle = Arc::new(Mutex::new(None));
|
||||
|
||||
let executor = Executor::new();
|
||||
// BIOS notif
|
||||
let x = last_notification.clone();
|
||||
executor
|
||||
.spawn(async move {
|
||||
let conn = zbus::Connection::system().await.unwrap();
|
||||
let proxy = RogBiosProxy::new(&conn).await.unwrap();
|
||||
if let Ok(p) = proxy.receive_notify_post_boot_sound().await {
|
||||
p.for_each(|e| {
|
||||
if let Ok(out) = e.args() {
|
||||
if let Ok(ref mut lock) = x.try_lock() {
|
||||
notify!(do_post_sound_notif, lock, &out.sound());
|
||||
}
|
||||
}
|
||||
future::ready(())
|
||||
})
|
||||
.await;
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
|
||||
// Charge notif
|
||||
let x = last_notification.clone();
|
||||
executor
|
||||
.spawn(async move {
|
||||
let conn = zbus::Connection::system().await.unwrap();
|
||||
let proxy = ChargeProxy::new(&conn).await.unwrap();
|
||||
if let Ok(p) = proxy.receive_notify_charge().await {
|
||||
p.for_each(|e| {
|
||||
if let Ok(out) = e.args() {
|
||||
if let Ok(ref mut lock) = x.try_lock() {
|
||||
notify!(do_charge_notif, lock, &out.limit);
|
||||
}
|
||||
}
|
||||
future::ready(())
|
||||
})
|
||||
.await;
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
|
||||
// Profile notif
|
||||
let x = last_notification.clone();
|
||||
executor
|
||||
.spawn(async move {
|
||||
let conn = zbus::Connection::system().await.unwrap();
|
||||
let proxy = ProfileProxy::new(&conn).await.unwrap();
|
||||
if let Ok(p) = proxy.receive_notify_profile().await {
|
||||
p.for_each(|e| {
|
||||
if let Ok(out) = e.args() {
|
||||
if let Ok(ref mut lock) = x.try_lock() {
|
||||
notify!(do_thermal_notif, lock, &out.profile);
|
||||
}
|
||||
}
|
||||
future::ready(())
|
||||
})
|
||||
.await;
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
|
||||
// LED notif
|
||||
executor
|
||||
.spawn(async move {
|
||||
let conn = zbus::Connection::system().await.unwrap();
|
||||
let proxy = LedProxy::new(&conn).await.unwrap();
|
||||
if let Ok(p) = proxy.receive_notify_led().await {
|
||||
p.for_each(|e| {
|
||||
if let Ok(out) = e.args() {
|
||||
if let Ok(ref mut lock) = last_notification.try_lock() {
|
||||
notify!(do_led_notif, lock, &out.data);
|
||||
}
|
||||
}
|
||||
future::ready(())
|
||||
})
|
||||
.await;
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
|
||||
loop {
|
||||
smol::block_on(executor.tick());
|
||||
}
|
||||
}
|
||||
|
||||
fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> {
|
||||
let icon = match profile {
|
||||
Profile::Balanced => "asus_notif_yellow",
|
||||
Profile::Performance => "asus_notif_red",
|
||||
Profile::Quiet => "asus_notif_green",
|
||||
};
|
||||
let profile: &str = (*profile).into();
|
||||
let x = Notification::new()
|
||||
.summary("ASUS ROG")
|
||||
.body(&format!(
|
||||
"Thermal profile changed to {}",
|
||||
profile.to_uppercase(),
|
||||
))
|
||||
.hint(Hint::Resident(true))
|
||||
.timeout(2000)
|
||||
.hint(Hint::Category("device".into()))
|
||||
//.hint(Hint::Transient(true))
|
||||
.icon(icon)
|
||||
.show()?;
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
fn do_led_notif(ledmode: &AuraEffect) -> Result<NotificationHandle, notify_rust::error::Error> {
|
||||
base_notification!(&format!(
|
||||
"Keyboard LED mode changed to {}",
|
||||
ledmode.mode_name()
|
||||
))
|
||||
}
|
||||
|
||||
fn do_charge_notif(limit: &u8) -> Result<NotificationHandle, notify_rust::error::Error> {
|
||||
base_notification!(&format!("Battery charge limit changed to {}", limit))
|
||||
}
|
||||
|
||||
fn do_post_sound_notif(on: &bool) -> Result<NotificationHandle, notify_rust::error::Error> {
|
||||
base_notification!(&format!("BIOS Post sound {}", on))
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
[package]
|
||||
name = "asusctl"
|
||||
version = "4.3.3"
|
||||
license = "MPL-2.0"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
zbus = "^2.2"
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_aura = { path = "../rog-aura" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_profiles = { path = "../rog-profiles" }
|
||||
rog_platform = { path = "../rog-platform" }
|
||||
daemon = { path = "../daemon" }
|
||||
gumdrop = "^0.8"
|
||||
toml = "^0.5.8"
|
||||
|
||||
sysfs-class = "^0.1.2"
|
||||
gumdrop.workspace = true
|
||||
toml.workspace = true
|
||||
sysfs-class.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tinybmp = "^0.3.3"
|
||||
glam = "^0.21.2"
|
||||
gif.workspace = true
|
||||
tinybmp.workspace = true
|
||||
glam.workspace = true
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
gif = "^0.11.2"
|
||||
|
||||
cargo-husky.workspace = true
|
||||
@@ -1,6 +1,10 @@
|
||||
use std::{env, error::Error, path::Path, process::exit};
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
|
||||
use rog_anime::{usb::get_anime_type, AnimeDiagonal, AnimeType};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimeDiagonal, AnimeType};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::{thread::sleep, time::Duration};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use rog_anime::{usb::get_anime_type, AnimeDiagonal, AnimeType};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimeDiagonal, AnimeType};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
// In usable data:
|
||||
@@ -20,7 +22,7 @@ fn main() {
|
||||
}
|
||||
|
||||
for c in (0..35).into_iter().step_by(step) {
|
||||
for i in matrix.get_mut()[c].iter_mut() {
|
||||
for i in &mut matrix.get_mut()[c] {
|
||||
*i = 50;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use std::{env, path::Path, thread::sleep};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::thread::sleep;
|
||||
|
||||
use rog_anime::{usb::get_anime_type, ActionData, ActionLoader, Sequences};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{ActionData, ActionLoader, Sequences};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use rog_anime::{usb::get_anime_type, AnimeDataBuffer, AnimeGrid};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimeDataBuffer, AnimeGrid};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
// In usable data:
|
||||
// Top row start at 1, ends at 32
|
||||
|
||||
@@ -17,7 +19,6 @@ fn main() {
|
||||
for (y, row) in tmp.iter_mut().enumerate() {
|
||||
if y % 2 == 0 && i + 1 != row.len() - 1 {
|
||||
i += 1;
|
||||
dbg!(i);
|
||||
}
|
||||
row[row.len() - i] = 0x22;
|
||||
if i > 5 {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use rog_anime::{usb::get_anime_type, AnimeDataBuffer};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::AnimeDataBuffer;
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
// In usable data:
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::{env, error::Error, path::Path, process::exit};
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
|
||||
use rog_anime::{
|
||||
usb::get_anime_type,
|
||||
AnimeDataBuffer, {AnimeImage, Vec2},
|
||||
};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::{
|
||||
env, error::Error, f32::consts::PI, path::Path, process::exit, thread::sleep, time::Duration,
|
||||
};
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::f32::consts::PI;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use rog_anime::{
|
||||
usb::get_anime_type,
|
||||
AnimeDataBuffer, {AnimeImage, Vec2},
|
||||
};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
@@ -35,7 +37,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
matrix.angle += 0.05;
|
||||
if matrix.angle > PI * 2.0 {
|
||||
matrix.angle = 0.0
|
||||
matrix.angle = 0.0;
|
||||
}
|
||||
matrix.update();
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ use rog_aura::{
|
||||
KeyColourArray,
|
||||
};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
use std::collections::LinkedList;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Ball {
|
||||
position: (f32, f32),
|
||||
direction: (f32, f32),
|
||||
trail: LinkedList<(f32, f32)>,
|
||||
trail: VecDeque<(f32, f32)>,
|
||||
}
|
||||
impl Ball {
|
||||
fn new(x: f32, y: f32, trail_len: u32) -> Self {
|
||||
let mut trail = LinkedList::new();
|
||||
let mut trail = VecDeque::new();
|
||||
for _ in 1..=trail_len {
|
||||
trail.push_back((x, y));
|
||||
}
|
||||
@@ -106,7 +106,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
c[2] = 255;
|
||||
};
|
||||
}
|
||||
dbus.proxies().led().per_key_raw(colours.get())?;
|
||||
dbus.proxies().led().direct_addressing_raw(colours.get())?;
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(150));
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
//! Using a combination of key-colour array plus a key layout to generate outputs.
|
||||
|
||||
use rog_aura::{keys::Key, layouts::KeyLayout, Breathe, Colour, Effect, LedType, Sequences, Speed};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let layout = KeyLayout::gx502_layout();
|
||||
|
||||
let (client, _) = RogDbusClientBlocking::new().unwrap();
|
||||
|
||||
let mut seq = Sequences::new();
|
||||
let mut key = Effect::Breathe(Breathe::new(
|
||||
LedType::Key(Key::W),
|
||||
Colour(255, 127, 0),
|
||||
Colour(127, 0, 255),
|
||||
Speed::Med,
|
||||
));
|
||||
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::A));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::S));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::D));
|
||||
seq.push(key.clone());
|
||||
|
||||
let mut key = Effect::Breathe(Breathe::new(
|
||||
LedType::Key(Key::Q),
|
||||
Colour(127, 127, 127),
|
||||
Colour(127, 255, 255),
|
||||
Speed::Low,
|
||||
));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::E));
|
||||
seq.push(key.clone());
|
||||
|
||||
let mut key = Effect::Breathe(Breathe::new(
|
||||
LedType::Key(Key::N1),
|
||||
Colour(166, 127, 166),
|
||||
Colour(127, 155, 20),
|
||||
Speed::High,
|
||||
));
|
||||
key.set_led_type(LedType::Key(Key::Tilde));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::N2));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::N3));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::N4));
|
||||
seq.push(key.clone());
|
||||
|
||||
loop {
|
||||
seq.next_state(&layout);
|
||||
let packets = seq.create_packets();
|
||||
|
||||
client.proxies().led().per_key_raw(packets)?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(60));
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//! Using a combination of key-colour array plus a key layout to generate outputs.
|
||||
|
||||
use rog_aura::{layouts::KeyLayout, KeyColourArray};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (client, _) = RogDbusClientBlocking::new().unwrap();
|
||||
let layout = KeyLayout::gx502_layout();
|
||||
loop {
|
||||
let mut key_colours = KeyColourArray::new();
|
||||
for row in layout.rows() {
|
||||
for (k, key) in row.row().enumerate() {
|
||||
if k != 0 {
|
||||
if let Some(prev) = row.row().nth(k - 1) {
|
||||
if let Some(c) = key_colours.rgb_for_key(*prev) {
|
||||
c[0] = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if key.is_placeholder() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(c) = key_colours.rgb_for_key(*key) {
|
||||
c[0] = 255;
|
||||
};
|
||||
|
||||
client.proxies().led().per_key_raw(key_colours.get())?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,64 @@
|
||||
//! Using a combination of key-colour array plus a key layout to generate outputs.
|
||||
//! Using a combination of key-colour array plus a key layout to generate
|
||||
//! outputs.
|
||||
|
||||
use rog_aura::{layouts::KeyLayout, Breathe, Colour, Effect, LedType, PerZone, Sequences, Speed};
|
||||
use rog_aura::advanced::LedCode;
|
||||
use rog_aura::effects::{AdvancedEffects, Effect};
|
||||
use rog_aura::layouts::KeyLayout;
|
||||
use rog_aura::Colour;
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let layout = KeyLayout::gx502_layout();
|
||||
let layout = KeyLayout::default_layout();
|
||||
|
||||
let (client, _) = RogDbusClientBlocking::new().unwrap();
|
||||
|
||||
let mut seq = Sequences::new();
|
||||
let mut seq = AdvancedEffects::new(true);
|
||||
|
||||
let zone = Effect::Breathe(Breathe::new(
|
||||
LedType::Zone(PerZone::KeyboardLeft),
|
||||
Colour(166, 127, 166),
|
||||
Colour(127, 155, 20),
|
||||
Speed::High,
|
||||
// let zone = Effect::Breathe(rog_aura::effects::Breathe::new(
|
||||
// RgbAddress::Single,
|
||||
// Colour(166, 127, 166),
|
||||
// Colour(127, 155, 20),
|
||||
// rog_aura::Speed::High,
|
||||
// ));
|
||||
// seq.push(zone);
|
||||
|
||||
// let zone = Effect::DoomLightFlash(rog_aura::effects::DoomLightFlash::new(
|
||||
// RgbAddress::Single,
|
||||
// Colour(200, 0, 0),
|
||||
// 80,
|
||||
// 10,
|
||||
// ));
|
||||
// seq.push(zone);
|
||||
|
||||
let zone = Effect::DoomFlicker(rog_aura::effects::DoomFlicker::new(
|
||||
LedCode::SingleZone,
|
||||
Colour(200, 110, 0),
|
||||
100,
|
||||
10,
|
||||
));
|
||||
seq.push(zone);
|
||||
|
||||
let zone = Effect::Breathe(Breathe::new(
|
||||
LedType::Zone(PerZone::KeyboardCenterLeft),
|
||||
Colour(16, 127, 255),
|
||||
Colour(127, 15, 20),
|
||||
Speed::Low,
|
||||
));
|
||||
seq.push(zone);
|
||||
// let zone = Effect::Breathe(rog_aura::effects::Breathe::new(
|
||||
// RgbAddress::KeyboardCenterLeft,
|
||||
// Colour(16, 127, 255),
|
||||
// Colour(127, 15, 20),
|
||||
// rog_aura::Speed::Low,
|
||||
// ));
|
||||
// seq.push(zone);
|
||||
|
||||
let zone = Effect::Breathe(Breathe::new(
|
||||
LedType::Zone(PerZone::LightbarRightCorner),
|
||||
Colour(0, 255, 255),
|
||||
Colour(255, 0, 255),
|
||||
Speed::Med,
|
||||
));
|
||||
seq.push(zone);
|
||||
// let zone = Effect::Breathe(rog_aura::effects::Breathe::new(
|
||||
// RgbAddress::LightbarRightCorner,
|
||||
// Colour(0, 255, 255),
|
||||
// Colour(255, 0, 255),
|
||||
// rog_aura::Speed::Med,
|
||||
// ));
|
||||
// seq.push(zone);
|
||||
|
||||
loop {
|
||||
seq.next_state(&layout);
|
||||
let packets = seq.create_packets();
|
||||
|
||||
client.proxies().led().per_key_raw(packets)?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(60));
|
||||
client.proxies().led().direct_addressing_raw(packets)?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(33));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use gumdrop::Options;
|
||||
use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
|
||||
use std::str::FromStr;
|
||||
|
||||
use gumdrop::Options;
|
||||
use rog_aura::error::Error;
|
||||
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
|
||||
|
||||
#[derive(Options)]
|
||||
pub struct LedPowerCommand1 {
|
||||
#[options(help = "print help message")]
|
||||
@@ -105,7 +107,7 @@ impl ToString for LedBrightness {
|
||||
Some(0x02) => "high",
|
||||
_ => "unknown",
|
||||
};
|
||||
s.to_string()
|
||||
s.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +222,6 @@ pub struct MultiColourSpeed {
|
||||
/// Byte value for setting the built-in mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
///
|
||||
// NOTE: The option names here must match those in rog-aura crate
|
||||
#[derive(Options)]
|
||||
pub enum SetAuraBuiltin {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use crate::{
|
||||
anime_cli::AnimeCommand,
|
||||
aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin},
|
||||
profiles_cli::{FanCurveCommand, ProfileCommand},
|
||||
};
|
||||
use gumdrop::Options;
|
||||
|
||||
use crate::anime_cli::AnimeCommand;
|
||||
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
|
||||
use crate::profiles_cli::{FanCurveCommand, ProfileCommand};
|
||||
|
||||
#[derive(Default, Options)]
|
||||
pub struct CliStart {
|
||||
#[options(help_flag, help = "print help message")]
|
||||
@@ -71,7 +70,7 @@ pub struct BiosCommand {
|
||||
meta = "",
|
||||
short = "S",
|
||||
no_long,
|
||||
help = "set bios POST sound: asusctl -p <true/false>"
|
||||
help = "set bios POST sound: asusctl -S <true/false>"
|
||||
)]
|
||||
pub post_sound_set: Option<bool>,
|
||||
#[options(no_long, short = "s", help = "read bios POST sound")]
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::env::args;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::thread::sleep;
|
||||
use std::{env::args, path::Path};
|
||||
|
||||
use aura_cli::{LedPowerCommand1, LedPowerCommand2};
|
||||
use gumdrop::{Opt, Options};
|
||||
|
||||
use anime_cli::{AnimeActions, AnimeCommand};
|
||||
use aura_cli::{LedPowerCommand1, LedPowerCommand2};
|
||||
use gumdrop::{Opt, Options};
|
||||
use profiles_cli::{FanCurveCommand, ProfileCommand};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2};
|
||||
|
||||
use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev};
|
||||
use rog_aura::usb::{AuraDevRog1, AuraDevRog2, AuraDevTuf, AuraDevice, AuraPowerDev};
|
||||
use rog_aura::{self, AuraEffect};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
use rog_platform::platform::GpuMode;
|
||||
@@ -26,31 +25,25 @@ mod aura_cli;
|
||||
mod cli_opts;
|
||||
mod profiles_cli;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn main() {
|
||||
let args: Vec<String> = args().skip(1).collect();
|
||||
|
||||
let parsed: CliStart;
|
||||
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
|
||||
match CliStart::parse_args_default(&args) {
|
||||
Ok(p) => {
|
||||
parsed = p;
|
||||
}
|
||||
Err(err) if err.to_string() == missing_argument_k.to_string() => {
|
||||
parsed = CliStart {
|
||||
kbd_bright: Some(LedBrightness::new(None)),
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
let parsed = match CliStart::parse_args_default(&args) {
|
||||
Ok(p) => p,
|
||||
Err(err) if err.to_string() == missing_argument_k.to_string() => CliStart {
|
||||
kbd_bright: Some(LedBrightness::new(None)),
|
||||
..Default::default()
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("source {}", err);
|
||||
std::process::exit(2);
|
||||
panic!("source {}", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let (dbus, _) = RogDbusClientBlocking::new()
|
||||
.map_err(|e| {
|
||||
print_error_help(Box::new(e), None);
|
||||
std::process::exit(3);
|
||||
print_error_help(&e, None);
|
||||
panic!("Could not start dbus client");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -59,8 +52,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.supported()
|
||||
.supported_functions()
|
||||
.map_err(|e| {
|
||||
print_error_help(Box::new(e), None);
|
||||
std::process::exit(4);
|
||||
print_error_help(&e, None);
|
||||
panic!("Could not start dbus proxy");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -68,17 +61,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
print_versions();
|
||||
println!();
|
||||
print_laptop_info();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(err) = do_parsed(&parsed, &supported, &dbus) {
|
||||
print_error_help(err, Some(&supported));
|
||||
print_error_help(&*err, Some(&supported));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_error_help(err: Box<dyn std::error::Error>, supported: Option<&SupportedFunctions>) {
|
||||
fn print_error_help(err: &dyn std::error::Error, supported: Option<&SupportedFunctions>) {
|
||||
check_service("asusd");
|
||||
println!("\nError: {}\n", err);
|
||||
print_versions();
|
||||
@@ -131,7 +121,7 @@ fn check_service(name: &str) -> bool {
|
||||
fn do_parsed(
|
||||
parsed: &CliStart,
|
||||
supported: &SupportedFunctions,
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match &parsed.command {
|
||||
Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?,
|
||||
@@ -139,9 +129,9 @@ fn do_parsed(
|
||||
Some(CliCommand::LedPow2(pow)) => handle_led_power2(dbus, &supported.keyboard_led, pow)?,
|
||||
Some(CliCommand::Profile(cmd)) => handle_profile(dbus, &supported.platform_profile, cmd)?,
|
||||
Some(CliCommand::FanCurve(cmd)) => {
|
||||
handle_fan_curve(dbus, &supported.platform_profile, cmd)?
|
||||
handle_fan_curve(dbus, &supported.platform_profile, cmd)?;
|
||||
}
|
||||
Some(CliCommand::Graphics(_)) => do_gfx()?,
|
||||
Some(CliCommand::Graphics(_)) => do_gfx(),
|
||||
Some(CliCommand::Anime(cmd)) => handle_anime(dbus, &supported.anime_ctrl, cmd)?,
|
||||
Some(CliCommand::Bios(cmd)) => handle_bios_option(dbus, &supported.rog_bios_ctrl, cmd)?,
|
||||
None => {
|
||||
@@ -155,10 +145,10 @@ fn do_parsed(
|
||||
println!("{}", CliStart::usage());
|
||||
println!();
|
||||
if let Some(cmdlist) = CliStart::command_list() {
|
||||
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect();
|
||||
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
|
||||
for command in commands.iter().filter(|command| {
|
||||
if !matches!(
|
||||
supported.keyboard_led.prod_id,
|
||||
supported.keyboard_led.dev_id,
|
||||
AuraDevice::X1854
|
||||
| AuraDevice::X1869
|
||||
| AuraDevice::X1866
|
||||
@@ -167,7 +157,7 @@ fn do_parsed(
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if supported.keyboard_led.prod_id != AuraDevice::X19B6
|
||||
if supported.keyboard_led.dev_id != AuraDevice::X19b6
|
||||
&& command.trim().starts_with("led-pow-2")
|
||||
{
|
||||
return false;
|
||||
@@ -211,20 +201,24 @@ fn do_parsed(
|
||||
}
|
||||
|
||||
if let Some(chg_limit) = parsed.chg_limit {
|
||||
dbus.proxies().charge().set_limit(chg_limit)?;
|
||||
dbus.proxies()
|
||||
.charge()
|
||||
.set_charge_control_end_threshold(chg_limit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_gfx() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Please use supergfxctl for graphics switching. supergfxctl is the result of making asusctl graphics switching generic so all laptops can use it");
|
||||
fn do_gfx() {
|
||||
println!(
|
||||
"Please use supergfxctl for graphics switching. supergfxctl is the result of making \
|
||||
asusctl graphics switching generic so all laptops can use it"
|
||||
);
|
||||
println!("This command will be removed in future");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_anime(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
_supported: &AnimeSupportedFunctions,
|
||||
cmd: &AnimeCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -240,14 +234,14 @@ fn handle_anime(
|
||||
}
|
||||
}
|
||||
if let Some(anime_turn) = cmd.enable {
|
||||
dbus.proxies().anime().set_on_off(anime_turn)?
|
||||
dbus.proxies().anime().set_on_off(anime_turn)?;
|
||||
}
|
||||
if let Some(anime_boot) = cmd.boot_enable {
|
||||
dbus.proxies().anime().set_boot_on_off(anime_boot)?
|
||||
dbus.proxies().anime().set_boot_on_off(anime_boot)?;
|
||||
}
|
||||
if let Some(bright) = cmd.brightness {
|
||||
verify_brightness(bright);
|
||||
dbus.proxies().anime().set_brightness(bright)?
|
||||
dbus.proxies().anime().set_brightness(bright)?;
|
||||
}
|
||||
if cmd.clear {
|
||||
let anime_type = get_anime_type()?;
|
||||
@@ -265,7 +259,7 @@ fn handle_anime(
|
||||
if let Some(lst) = image.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
return Ok(());
|
||||
}
|
||||
verify_brightness(image.bright);
|
||||
|
||||
@@ -288,7 +282,7 @@ fn handle_anime(
|
||||
if let Some(lst) = image.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
return Ok(());
|
||||
}
|
||||
verify_brightness(image.bright);
|
||||
|
||||
@@ -309,7 +303,7 @@ fn handle_anime(
|
||||
if let Some(lst) = gif.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
return Ok(());
|
||||
}
|
||||
verify_brightness(gif.bright);
|
||||
|
||||
@@ -343,7 +337,7 @@ fn handle_anime(
|
||||
if let Some(lst) = gif.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
return Ok(());
|
||||
}
|
||||
verify_brightness(gif.bright);
|
||||
|
||||
@@ -374,17 +368,16 @@ fn handle_anime(
|
||||
}
|
||||
|
||||
fn verify_brightness(brightness: f32) {
|
||||
if brightness < 0.0 || brightness > 1.0 {
|
||||
if !(0.0..=1.0).contains(&brightness) {
|
||||
println!(
|
||||
"Image and global brightness must be between 0.0 and 1.0 (inclusive), was {}",
|
||||
brightness
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_led_mode(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
supported: &LedSupportedFunctions,
|
||||
mode: &LedModeCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -396,9 +389,9 @@ fn handle_led_mode(
|
||||
println!("Commands available");
|
||||
|
||||
if let Some(cmdlist) = LedModeCommand::command_list() {
|
||||
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect();
|
||||
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
|
||||
for command in commands.iter().filter(|command| {
|
||||
for mode in &supported.stock_led_modes {
|
||||
for mode in &supported.basic_modes {
|
||||
if command
|
||||
.trim()
|
||||
.starts_with(&<&str>::from(mode).to_lowercase())
|
||||
@@ -406,7 +399,7 @@ fn handle_led_mode(
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if !supported.multizone_led_mode.is_empty() && command.trim().starts_with("multi") {
|
||||
if !supported.basic_zones.is_empty() && command.trim().starts_with("multi") {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
@@ -441,7 +434,7 @@ fn handle_led_mode(
|
||||
}
|
||||
|
||||
fn handle_led_power1(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
supported: &LedSupportedFunctions,
|
||||
power: &LedPowerCommand1,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -459,30 +452,30 @@ fn handle_led_power1(
|
||||
}
|
||||
|
||||
if matches!(
|
||||
supported.prod_id,
|
||||
supported.dev_id,
|
||||
AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866
|
||||
) {
|
||||
handle_led_power_1_do_1866(dbus, power)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if matches!(supported.prod_id, AuraDevice::Tuf) {
|
||||
if matches!(supported.dev_id, AuraDevice::Tuf) {
|
||||
handle_led_power_1_do_tuf(dbus, power)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("These options are for keyboards of product ID 0x1866 or TUF only");
|
||||
return Ok(());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_led_power_1_do_1866(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
power: &LedPowerCommand1,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut enabled: Vec<AuraDev1866> = Vec::new();
|
||||
let mut disabled: Vec<AuraDev1866> = Vec::new();
|
||||
let mut enabled: Vec<AuraDevRog1> = Vec::new();
|
||||
let mut disabled: Vec<AuraDevRog1> = Vec::new();
|
||||
|
||||
let mut check = |e: Option<bool>, a: AuraDev1866| {
|
||||
let mut check = |e: Option<bool>, a: AuraDevRog1| {
|
||||
if let Some(arg) = e {
|
||||
if arg {
|
||||
enabled.push(a);
|
||||
@@ -492,11 +485,11 @@ fn handle_led_power_1_do_1866(
|
||||
}
|
||||
};
|
||||
|
||||
check(power.awake, AuraDev1866::Awake);
|
||||
check(power.boot, AuraDev1866::Boot);
|
||||
check(power.sleep, AuraDev1866::Sleep);
|
||||
check(power.keyboard, AuraDev1866::Keyboard);
|
||||
check(power.lightbar, AuraDev1866::Lightbar);
|
||||
check(power.awake, AuraDevRog1::Awake);
|
||||
check(power.boot, AuraDevRog1::Boot);
|
||||
check(power.sleep, AuraDevRog1::Sleep);
|
||||
check(power.keyboard, AuraDevRog1::Keyboard);
|
||||
check(power.lightbar, AuraDevRog1::Lightbar);
|
||||
|
||||
let data = AuraPowerDev {
|
||||
x1866: enabled,
|
||||
@@ -516,7 +509,7 @@ fn handle_led_power_1_do_1866(
|
||||
}
|
||||
|
||||
fn handle_led_power_1_do_tuf(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
power: &LedPowerCommand1,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut enabled: Vec<AuraDevTuf> = Vec::new();
|
||||
@@ -542,7 +535,6 @@ fn handle_led_power_1_do_tuf(
|
||||
x19b6: vec![],
|
||||
tuf: enabled,
|
||||
};
|
||||
dbg!(&data);
|
||||
dbus.proxies().led().set_leds_power(data, true)?;
|
||||
|
||||
let data = AuraPowerDev {
|
||||
@@ -556,7 +548,7 @@ fn handle_led_power_1_do_tuf(
|
||||
}
|
||||
|
||||
fn handle_led_power2(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
supported: &LedSupportedFunctions,
|
||||
power: &LedPowerCommand2,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -568,8 +560,8 @@ fn handle_led_power2(
|
||||
println!("Commands available");
|
||||
|
||||
if let Some(cmdlist) = LedPowerCommand2::command_list() {
|
||||
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect();
|
||||
for command in commands.iter() {
|
||||
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
|
||||
for command in &commands {
|
||||
println!("{}", command);
|
||||
}
|
||||
}
|
||||
@@ -584,13 +576,13 @@ fn handle_led_power2(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if supported.prod_id != AuraDevice::X19B6 {
|
||||
println!("This option applies only to keyboards with product ID 0x19b6")
|
||||
if supported.dev_id != AuraDevice::X19b6 {
|
||||
println!("This option applies only to keyboards with product ID 0x19b6");
|
||||
}
|
||||
|
||||
let mut enabled: Vec<AuraDev19b6> = Vec::new();
|
||||
let mut disabled: Vec<AuraDev19b6> = Vec::new();
|
||||
let mut check = |e: Option<bool>, a: AuraDev19b6| {
|
||||
let mut enabled: Vec<AuraDevRog2> = Vec::new();
|
||||
let mut disabled: Vec<AuraDevRog2> = Vec::new();
|
||||
let mut check = |e: Option<bool>, a: AuraDevRog2| {
|
||||
if let Some(arg) = e {
|
||||
if arg {
|
||||
enabled.push(a);
|
||||
@@ -602,28 +594,28 @@ fn handle_led_power2(
|
||||
|
||||
match pow {
|
||||
aura_cli::SetAuraEnabled::Boot(arg) => {
|
||||
check(arg.keyboard, AuraDev19b6::BootKeyb);
|
||||
check(arg.logo, AuraDev19b6::BootLogo);
|
||||
check(arg.lightbar, AuraDev19b6::BootBar);
|
||||
check(arg.lid, AuraDev19b6::AwakeLid);
|
||||
check(arg.keyboard, AuraDevRog2::BootKeyb);
|
||||
check(arg.logo, AuraDevRog2::BootLogo);
|
||||
check(arg.lightbar, AuraDevRog2::BootBar);
|
||||
check(arg.lid, AuraDevRog2::AwakeLid);
|
||||
}
|
||||
aura_cli::SetAuraEnabled::Sleep(arg) => {
|
||||
check(arg.keyboard, AuraDev19b6::SleepKeyb);
|
||||
check(arg.logo, AuraDev19b6::SleepLogo);
|
||||
check(arg.lightbar, AuraDev19b6::SleepBar);
|
||||
check(arg.lid, AuraDev19b6::SleepLid);
|
||||
check(arg.keyboard, AuraDevRog2::SleepKeyb);
|
||||
check(arg.logo, AuraDevRog2::SleepLogo);
|
||||
check(arg.lightbar, AuraDevRog2::SleepBar);
|
||||
check(arg.lid, AuraDevRog2::SleepLid);
|
||||
}
|
||||
aura_cli::SetAuraEnabled::Awake(arg) => {
|
||||
check(arg.keyboard, AuraDev19b6::AwakeKeyb);
|
||||
check(arg.logo, AuraDev19b6::AwakeLogo);
|
||||
check(arg.lightbar, AuraDev19b6::AwakeBar);
|
||||
check(arg.lid, AuraDev19b6::AwakeLid);
|
||||
check(arg.keyboard, AuraDevRog2::AwakeKeyb);
|
||||
check(arg.logo, AuraDevRog2::AwakeLogo);
|
||||
check(arg.lightbar, AuraDevRog2::AwakeBar);
|
||||
check(arg.lid, AuraDevRog2::AwakeLid);
|
||||
}
|
||||
aura_cli::SetAuraEnabled::Shutdown(arg) => {
|
||||
check(arg.keyboard, AuraDev19b6::ShutdownKeyb);
|
||||
check(arg.logo, AuraDev19b6::ShutdownLogo);
|
||||
check(arg.lightbar, AuraDev19b6::ShutdownBar);
|
||||
check(arg.lid, AuraDev19b6::ShutdownBar);
|
||||
check(arg.keyboard, AuraDevRog2::ShutdownKeyb);
|
||||
check(arg.logo, AuraDevRog2::ShutdownLogo);
|
||||
check(arg.lightbar, AuraDevRog2::ShutdownBar);
|
||||
check(arg.lid, AuraDevRog2::ShutdownBar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +642,7 @@ fn handle_led_power2(
|
||||
}
|
||||
|
||||
fn handle_profile(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
supported: &PlatformProfileFunctions,
|
||||
cmd: &ProfileCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -668,7 +660,7 @@ fn handle_profile(
|
||||
if let Some(lst) = cmd.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if cmd.next {
|
||||
@@ -679,7 +671,9 @@ fn handle_profile(
|
||||
|
||||
if cmd.list {
|
||||
let res = dbus.proxies().profile().profiles()?;
|
||||
res.iter().for_each(|p| println!("{:?}", p));
|
||||
for p in &res {
|
||||
println!("{:?}", p);
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.profile_get {
|
||||
@@ -691,7 +685,7 @@ fn handle_profile(
|
||||
}
|
||||
|
||||
fn handle_fan_curve(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
supported: &PlatformProfileFunctions,
|
||||
cmd: &FanCurveCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -710,14 +704,14 @@ fn handle_fan_curve(
|
||||
if let Some(lst) = cmd.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if (cmd.enabled.is_some() || cmd.fan.is_some() || cmd.data.is_some())
|
||||
&& cmd.mod_profile.is_none()
|
||||
{
|
||||
println!("--enabled, --fan, and --data options require --mod-profile");
|
||||
std::process::exit(666);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if cmd.get_enabled {
|
||||
@@ -753,7 +747,7 @@ fn handle_fan_curve(
|
||||
}
|
||||
|
||||
fn handle_bios_option(
|
||||
dbus: &RogDbusClientBlocking,
|
||||
dbus: &RogDbusClientBlocking<'_>,
|
||||
supported: &RogBiosSupportedFunctions,
|
||||
cmd: &BiosCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -768,10 +762,7 @@ fn handle_bios_option(
|
||||
{
|
||||
println!("Missing arg or command\n");
|
||||
|
||||
let usage: Vec<String> = BiosCommand::usage()
|
||||
.lines()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let usage: Vec<String> = BiosCommand::usage().lines().map(|s| s.to_owned()).collect();
|
||||
|
||||
for line in usage.iter().filter(|line| {
|
||||
line.contains("sound") && supported.post_sound
|
||||
@@ -795,7 +786,10 @@ fn handle_bios_option(
|
||||
dbus.proxies()
|
||||
.rog_bios()
|
||||
.set_gpu_mux_mode(GpuMode::from_mux(opt))?;
|
||||
println!("The mode change is not active until you reboot, on boot the bios will make the required change");
|
||||
println!(
|
||||
"The mode change is not active until you reboot, on boot the bios will make the \
|
||||
required change"
|
||||
);
|
||||
}
|
||||
if cmd.gpu_mux_mode_get {
|
||||
let res = dbus.proxies().rog_bios().gpu_mux_mode()?;
|
||||
@@ -803,10 +797,10 @@ fn handle_bios_option(
|
||||
}
|
||||
|
||||
if let Some(opt) = cmd.panel_overdrive_set {
|
||||
dbus.proxies().rog_bios().set_panel_overdrive(opt)?;
|
||||
dbus.proxies().rog_bios().set_panel_od(opt)?;
|
||||
}
|
||||
if cmd.panel_overdrive_get {
|
||||
let res = dbus.proxies().rog_bios().panel_overdrive()?;
|
||||
let res = dbus.proxies().rog_bios().panel_od()?;
|
||||
println!("Panel overdrive on: {}", res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use gumdrop::Options;
|
||||
use rog_profiles::{fan_curve_set::CurveData, FanCurvePU, Profile};
|
||||
use rog_profiles::fan_curve_set::CurveData;
|
||||
use rog_profiles::{FanCurvePU, Profile};
|
||||
|
||||
#[derive(Debug, Clone, Options)]
|
||||
pub struct ProfileCommand {
|
||||
|
||||
18
config-traits/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "config-traits"
|
||||
license = "MPL-2.0"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
serde_json.workspace = true
|
||||
toml.workspace = true
|
||||
ron.workspace = true
|
||||
|
||||
log.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
cargo-husky.workspace = true
|
||||
10
config-traits/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# config-traits
|
||||
|
||||
`config_traits` is a crate that broke out from the requirement to manage various
|
||||
different config files, including parsing from different formats and updating
|
||||
them from previous versions where fields or names are changed in some way.
|
||||
|
||||
The end canonical file format is `.ron` as this supports rust types well, and includes
|
||||
the ability to add commenting, and is less verbose than `json`. Currently the crate will
|
||||
also try to parse from `json` and `toml` if the `ron` parsing fails, then update to `ron`
|
||||
format.
|
||||
328
config-traits/src/lib.rs
Normal file
@@ -0,0 +1,328 @@
|
||||
//! `config_traits` is a crate that broke out from the requirement to manage
|
||||
//! various different config files, including parsing from different formats and
|
||||
//! updating them from previous versions where fields or names are changed in
|
||||
//! some way.
|
||||
//!
|
||||
//! The end canonical file format is `.ron` as this supports rust types well,
|
||||
//! and includes the ability to add commenting, and is less verbose than `json`.
|
||||
//! Currently the crate will also try to parse from `json` and `toml` if the
|
||||
//! `ron` parsing fails, then update to `ron` format.
|
||||
|
||||
use std::fs::{self, create_dir, File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use log::{error, warn};
|
||||
pub use ron;
|
||||
use ron::ser::PrettyConfig;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
/// Config file helper traits. Only `new()` and `file_name()` are required to be
|
||||
/// implemented, the rest are intended to be free methods.
|
||||
pub trait StdConfig
|
||||
where
|
||||
Self: Serialize + DeserializeOwned,
|
||||
{
|
||||
/// Taking over the standard `new()` to ensure things can be generic
|
||||
fn new() -> Self;
|
||||
|
||||
/// Return the config files names, such as `wibble.cfg`
|
||||
fn file_name(&self) -> String;
|
||||
|
||||
/// Return the full path to the directory the config file resides in
|
||||
fn config_dir() -> PathBuf;
|
||||
|
||||
/// Return the full path to the config file
|
||||
fn file_path(&self) -> PathBuf {
|
||||
let mut config = Self::config_dir();
|
||||
if !config.exists() {
|
||||
create_dir(config.as_path())
|
||||
.unwrap_or_else(|e| panic!("Could not create {:?} {e}", Self::config_dir()));
|
||||
}
|
||||
config.push(self.file_name());
|
||||
let mut do_rename = !config.exists();
|
||||
let mut cfg_old = config.clone();
|
||||
// Migrating all configs to .ron format, so we do need to check for older ones
|
||||
if do_rename {
|
||||
warn!("Config {cfg_old:?} does not exist, looking for .cfg next");
|
||||
cfg_old.pop();
|
||||
let tmp = self.file_name();
|
||||
let parts: Vec<_> = tmp.split('.').collect();
|
||||
cfg_old.push(format!("{}.cfg", parts[0]));
|
||||
}
|
||||
if do_rename && cfg_old.exists() {
|
||||
// Now we gotta rename it
|
||||
warn!("Renaming {cfg_old:?} to {config:?}");
|
||||
std::fs::rename(&cfg_old, &config).unwrap_or_else(|err| {
|
||||
error!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
self.file_name(),
|
||||
err
|
||||
);
|
||||
});
|
||||
do_rename = false;
|
||||
}
|
||||
if do_rename && !cfg_old.exists() {
|
||||
warn!("Config {cfg_old:?} does not exist, looking for .conf next");
|
||||
cfg_old.pop();
|
||||
let tmp = self.file_name();
|
||||
let parts: Vec<_> = tmp.split('.').collect();
|
||||
cfg_old.push(format!("{}.conf", parts[0]));
|
||||
}
|
||||
if do_rename && cfg_old.exists() {
|
||||
// Now we gotta rename it
|
||||
warn!("Renaming {cfg_old:?} to {config:?}");
|
||||
std::fs::rename(&cfg_old, &config).unwrap_or_else(|err| {
|
||||
error!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
self.file_name(),
|
||||
err
|
||||
);
|
||||
});
|
||||
}
|
||||
config
|
||||
}
|
||||
|
||||
/// Directly open the config file for read and write. If the config file
|
||||
/// does not exist it is created, including the directories the file
|
||||
/// resides in.
|
||||
fn file_open(&self) -> File {
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(self.file_path())
|
||||
.unwrap_or_else(|e| panic!("Could not open {:?} {e}", self.file_path()))
|
||||
}
|
||||
|
||||
/// Open and parse the config file to self from ron format
|
||||
fn read(&mut self) {
|
||||
if let Ok(data) = fs::read_to_string(self.file_path()) {
|
||||
if data.is_empty() {
|
||||
warn!("File is empty {:?}", self.file_path());
|
||||
} else if let Ok(data) = ron::from_str(&data) {
|
||||
*self = data;
|
||||
} else {
|
||||
warn!("Could not deserialise {:?}", self.file_path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the config file data to pretty ron format
|
||||
fn write(&self) {
|
||||
let mut file = match File::create(self.file_path()) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Couldn't overwrite config {:?}, error: {e}",
|
||||
self.file_path()
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let ron = match ron::ser::to_string_pretty(&self, PrettyConfig::new().depth_limit(4)) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
error!("Parse {:?} to RON failed, error: {e}", self.file_path());
|
||||
return;
|
||||
}
|
||||
};
|
||||
file.write_all(ron.as_bytes())
|
||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||
}
|
||||
|
||||
/// Renames the existing file to `<file>-old`
|
||||
fn rename_file_old(&self) {
|
||||
warn!(
|
||||
"Renaming {} to {}-old and recreating config",
|
||||
self.file_name(),
|
||||
self.file_name()
|
||||
);
|
||||
let mut cfg_old = self.file_path().to_string_lossy().to_string();
|
||||
cfg_old.push_str("-old");
|
||||
std::fs::rename(self.file_path(), cfg_old).unwrap_or_else(|err| {
|
||||
error!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
self.file_name(),
|
||||
err
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! std_config_load {
|
||||
($trait_name:ident: $($generic:ident),*) => {
|
||||
/// Base trait for loading/parsing. This is intended to be used to help update
|
||||
/// configs to new versions
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use std::path::PathBuf;
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use config_traits::{StdConfig, StdConfigLoad2};
|
||||
///
|
||||
/// #[derive(Deserialize, Serialize, Debug)]
|
||||
/// struct FanCurveConfigOld {}
|
||||
///
|
||||
/// #[derive(Deserialize, Serialize, Debug)]
|
||||
/// struct FanCurveConfigOlder {}
|
||||
///
|
||||
/// #[derive(Deserialize, Serialize, Debug)]
|
||||
/// struct FanCurveConfig {}
|
||||
///
|
||||
/// impl From<FanCurveConfigOld> for FanCurveConfig {
|
||||
/// fn from(_: FanCurveConfigOld) -> Self { Self {} }
|
||||
/// }
|
||||
///
|
||||
/// impl From<FanCurveConfigOlder> for FanCurveConfig {
|
||||
/// fn from(_: FanCurveConfigOlder) -> Self { Self {} }
|
||||
/// }
|
||||
///
|
||||
/// impl StdConfig for FanCurveConfig {
|
||||
/// fn new() -> Self { Self {} }
|
||||
///
|
||||
/// fn file_name(&self) -> std::string::String { "test_name.conf".to_owned() }
|
||||
///
|
||||
/// fn config_dir() -> PathBuf { PathBuf::from("/tmp") }
|
||||
/// }
|
||||
///
|
||||
/// impl StdConfigLoad2<FanCurveConfigOld, FanCurveConfigOlder> for FanCurveConfig {}
|
||||
/// ```
|
||||
///
|
||||
/// If all of the generics fails to parse, then the old config is renamed and a
|
||||
/// new one created
|
||||
pub trait $trait_name<$($generic),*>
|
||||
where
|
||||
Self: $crate::StdConfig +std::fmt::Debug + DeserializeOwned + Serialize,
|
||||
$($generic: DeserializeOwned + Into<Self>),*
|
||||
{
|
||||
fn load(mut self) -> Self {
|
||||
let mut file = self.file_open();
|
||||
let mut buf = String::new();
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len != 0 {
|
||||
if let Ok(data) = ron::from_str(&buf) {
|
||||
self = data;
|
||||
log::info!("Parsed RON for {:?}", std::any::type_name::<Self>());
|
||||
} else if let Ok(data) = serde_json::from_str(&buf) {
|
||||
self = data;
|
||||
log::info!("Parsed JSON for {:?}", std::any::type_name::<Self>());
|
||||
} else if let Ok(data) = toml::from_str(&buf) {
|
||||
self = data;
|
||||
log::info!("Parsed TOML for {:?}", std::any::type_name::<Self>());
|
||||
} $(else if let Ok(data) = ron::from_str::<$generic>(&buf) {
|
||||
self = data.into();
|
||||
log::info!("New version failed, trying previous: Parsed RON for {:?}", std::any::type_name::<$generic>());
|
||||
} else if let Ok(data) = serde_json::from_str::<$generic>(&buf) {
|
||||
self = data.into();
|
||||
log::info!("New version failed, trying previous: Parsed JSON for {:?}", std::any::type_name::<$generic>());
|
||||
} else if let Ok(data) = toml::from_str::<$generic>(&buf) {
|
||||
self = data.into();
|
||||
log::info!("Newvious version failed, trying previous: Parsed TOML for {:?}", std::any::type_name::<$generic>());
|
||||
})* else {
|
||||
self.rename_file_old();
|
||||
self = Self::new();
|
||||
}
|
||||
} else {
|
||||
error!("Config file {} zero read length", self.file_name());
|
||||
}
|
||||
}
|
||||
self.write();
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std_config_load!(StdConfigLoad:);
|
||||
std_config_load!(StdConfigLoad1: T1);
|
||||
std_config_load!(StdConfigLoad2: T1, T2);
|
||||
std_config_load!(StdConfigLoad3: T1, T2, T3);
|
||||
std_config_load!(StdConfigLoad4: T1, T2, T3, T4);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn check_macro_from_1() {
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
struct Test {}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
struct Old1 {}
|
||||
|
||||
impl crate::StdConfig for Test {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
fn config_dir() -> PathBuf {
|
||||
PathBuf::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Old1> for Test {
|
||||
fn from(_: Old1) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::StdConfigLoad1<Old1> for Test {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_macro_from_3() {
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
struct Test {}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
struct Old1 {}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
struct Old2 {}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
struct Old3 {}
|
||||
|
||||
impl crate::StdConfig for Test {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
fn config_dir() -> PathBuf {
|
||||
PathBuf::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Old1> for Test {
|
||||
fn from(_: Old1) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Old2> for Test {
|
||||
fn from(_: Old2) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Old3> for Test {
|
||||
fn from(_: Old3) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::StdConfigLoad3<Old1, Old2, Old3> for Test {}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
[package]
|
||||
name = "daemon-user"
|
||||
version = "1.3.1"
|
||||
license = "MPL-2.0"
|
||||
version.workspace = true
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Usermode daemon for user settings, anime, per-key lighting"
|
||||
|
||||
[lib]
|
||||
@@ -14,20 +15,25 @@ name = "asusd-user"
|
||||
path = "src/daemon.rs"
|
||||
|
||||
[dependencies]
|
||||
dirs.workspace = true
|
||||
smol.workspace = true
|
||||
|
||||
# serialisation
|
||||
serde = "^1.0"
|
||||
serde_json = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_derive.workspace = true
|
||||
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_aura = { path = "../rog-aura" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_platform = { path = "../rog-platform" }
|
||||
config-traits = { path = "../config-traits" }
|
||||
|
||||
dirs = "^4.0"
|
||||
zbus.workspace = true
|
||||
|
||||
zbus = "^2.2"
|
||||
zvariant = "^3.0"
|
||||
zvariant_derive = "^3.0"
|
||||
# cli and logging
|
||||
log.workspace = true
|
||||
env_logger.workspace = true
|
||||
|
||||
smol = "^1.2"
|
||||
[dev-dependencies]
|
||||
cargo-husky.workspace = true
|
||||
219
daemon-user/src/config.rs
Normal file
@@ -0,0 +1,219 @@
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2};
|
||||
use rog_aura::advanced::LedCode;
|
||||
use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static};
|
||||
use rog_aura::{Colour, Speed};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
const ROOT_CONF_DIR: &str = "rog";
|
||||
|
||||
fn root_conf_dir() -> PathBuf {
|
||||
let mut dir = dirs::config_dir().unwrap_or_else(|| PathBuf::from("/tmp"));
|
||||
dir.push(ROOT_CONF_DIR);
|
||||
dir
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ConfigAnime {
|
||||
pub name: String,
|
||||
pub anime: Vec<ActionLoader>,
|
||||
}
|
||||
|
||||
impl ConfigAnime {
|
||||
pub fn create(&self, anime_type: AnimeType) -> Result<AnimeSequences, Error> {
|
||||
let mut seq = AnimeSequences::new(anime_type);
|
||||
|
||||
for (idx, action) in self.anime.iter().enumerate() {
|
||||
seq.insert(idx, action)?;
|
||||
}
|
||||
|
||||
Ok(seq)
|
||||
}
|
||||
|
||||
pub fn set_name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ConfigAnime {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "anime-default".to_owned(),
|
||||
anime: vec![
|
||||
ActionLoader::AsusImage {
|
||||
file: "/usr/share/asusd/anime/custom/diagonal-template.png".into(),
|
||||
brightness: 1.0,
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(2),
|
||||
None,
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
},
|
||||
ActionLoader::AsusAnimation {
|
||||
file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(6),
|
||||
None,
|
||||
Duration::from_secs(3),
|
||||
)),
|
||||
},
|
||||
ActionLoader::ImageAnimation {
|
||||
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
|
||||
scale: 0.9,
|
||||
angle: 0.65,
|
||||
translation: Vec2::default(),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(2),
|
||||
Some(Duration::from_secs(2)),
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
},
|
||||
ActionLoader::Image {
|
||||
file: "/usr/share/asusd/anime/custom/rust.png".into(),
|
||||
scale: 1.0,
|
||||
angle: 0.0,
|
||||
translation: Vec2::default(),
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(2),
|
||||
Some(Duration::from_secs(1)),
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
brightness: 0.6,
|
||||
},
|
||||
ActionLoader::Pause(Duration::from_secs(1)),
|
||||
ActionLoader::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: 0.5,
|
||||
time: AnimTime::Count(2),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfig for ConfigAnime {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
format!("{}.ron", self.name)
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
root_conf_dir()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for ConfigAnime {}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ConfigAura {
|
||||
pub name: String,
|
||||
pub aura: AuraSequences,
|
||||
}
|
||||
|
||||
impl ConfigAura {
|
||||
pub fn set_name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ConfigAura {
|
||||
fn default() -> Self {
|
||||
let mut seq = AuraSequences::new(false);
|
||||
let mut key = Effect::Breathe(Breathe::new(
|
||||
LedCode::W,
|
||||
Colour(255, 0, 20),
|
||||
Colour(20, 255, 0),
|
||||
Speed::Low,
|
||||
));
|
||||
|
||||
seq.push(key.clone());
|
||||
key.set_led(LedCode::A);
|
||||
seq.push(key.clone());
|
||||
key.set_led(LedCode::S);
|
||||
seq.push(key.clone());
|
||||
key.set_led(LedCode::D);
|
||||
seq.push(key);
|
||||
|
||||
let key = Effect::Breathe(Breathe::new(
|
||||
LedCode::F,
|
||||
Colour(255, 0, 0),
|
||||
Colour(255, 0, 0),
|
||||
Speed::High,
|
||||
));
|
||||
seq.push(key);
|
||||
|
||||
let mut key = Effect::Static(Static::new(LedCode::RCtrl, Colour(0, 0, 255)));
|
||||
seq.push(key.clone());
|
||||
key.set_led(LedCode::LCtrl);
|
||||
seq.push(key.clone());
|
||||
key.set_led(LedCode::Esc);
|
||||
seq.push(key);
|
||||
|
||||
let key = Effect::DoomFlicker(DoomFlicker::new(LedCode::N9, Colour(0, 0, 255), 80, 40));
|
||||
seq.push(key);
|
||||
|
||||
Self {
|
||||
name: "aura-default".to_owned(),
|
||||
aura: seq,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfig for ConfigAura {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
format!("{}.ron", self.name)
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
root_conf_dir()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for ConfigAura {}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct ConfigBase {
|
||||
/// Name of active anime config file in the user config directory
|
||||
pub active_anime: Option<String>,
|
||||
/// Name of active aura config file in the user config directory
|
||||
pub active_aura: Option<String>,
|
||||
}
|
||||
|
||||
impl StdConfig for ConfigBase {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
active_anime: Some("anime-default".to_owned()),
|
||||
active_aura: Some("aura-default".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
"rog-user.ron".to_owned()
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
root_conf_dir()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for ConfigBase {}
|
||||
@@ -1,27 +1,25 @@
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use config_traits::StdConfig;
|
||||
use rog_anime::error::AnimeError;
|
||||
use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2};
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Mutex,
|
||||
},
|
||||
};
|
||||
use std::{sync::Arc, thread::sleep, time::Instant};
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
use zvariant_derive::Type;
|
||||
use zbus::zvariant::{ObjectPath, Type};
|
||||
|
||||
use crate::user_config::ConfigLoadSave;
|
||||
use crate::{error::Error, user_config::UserAnimeConfig};
|
||||
use crate::config::ConfigAnime;
|
||||
use crate::error::Error;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
|
||||
pub struct Timer {
|
||||
type_of: TimeType,
|
||||
/// If time type is Timer then this is milliseonds, otherwise it is animation loop count
|
||||
/// If time type is Timer then this is milliseonds, otherwise it is
|
||||
/// animation loop count
|
||||
count: u64,
|
||||
/// Used only for `TimeType::Timer`, milliseonds to fade the image in for
|
||||
fade_in: Option<u64>,
|
||||
@@ -63,8 +61,8 @@ pub enum TimeType {
|
||||
Infinite,
|
||||
}
|
||||
|
||||
/// The inner object exists to allow the zbus proxy to share it with a runner thread
|
||||
/// and a zbus server behind `Arc<Mutex<T>>`
|
||||
/// The inner object exists to allow the zbus proxy to share it with a runner
|
||||
/// thread and a zbus server behind `Arc<Mutex<T>>`
|
||||
pub struct CtrlAnimeInner<'a> {
|
||||
sequences: Sequences,
|
||||
client: RogDbusClientBlocking<'a>,
|
||||
@@ -83,7 +81,9 @@ impl<'a> CtrlAnimeInner<'static> {
|
||||
do_early_return,
|
||||
})
|
||||
}
|
||||
/// To be called on each main loop iteration to pump out commands to the anime
|
||||
|
||||
/// To be called on each main loop iteration to pump out commands to the
|
||||
/// anime
|
||||
pub fn run(&'a self) -> Result<(), Error> {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
@@ -102,7 +102,7 @@ impl<'a> CtrlAnimeInner<'static> {
|
||||
.write(output)
|
||||
.map_err(|e| AnimeError::Dbus(format!("{}", e)))
|
||||
.map(|_| false)
|
||||
})?;
|
||||
});
|
||||
}
|
||||
ActionData::Image(image) => {
|
||||
self.client
|
||||
@@ -123,10 +123,10 @@ impl<'a> CtrlAnimeInner<'static> {
|
||||
sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
ActionData::AudioEq => {}
|
||||
ActionData::SystemInfo => {}
|
||||
ActionData::TimeDate => {}
|
||||
ActionData::Matrix => {}
|
||||
ActionData::AudioEq
|
||||
| ActionData::SystemInfo
|
||||
| ActionData::TimeDate
|
||||
| ActionData::Matrix => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,16 +135,16 @@ impl<'a> CtrlAnimeInner<'static> {
|
||||
}
|
||||
|
||||
pub struct CtrlAnime<'a> {
|
||||
config: Arc<Mutex<UserAnimeConfig>>,
|
||||
config: Arc<Mutex<ConfigAnime>>,
|
||||
client: RogDbusClientBlocking<'a>,
|
||||
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
|
||||
/// Must be the same Atomic as in CtrlAnimeInner
|
||||
inner_early_return: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl<'a> CtrlAnime<'static> {
|
||||
impl CtrlAnime<'static> {
|
||||
pub fn new(
|
||||
config: Arc<Mutex<UserAnimeConfig>>,
|
||||
config: Arc<Mutex<ConfigAnime>>,
|
||||
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
|
||||
client: RogDbusClientBlocking<'static>,
|
||||
inner_early_return: Arc<AtomicBool>,
|
||||
@@ -184,7 +184,7 @@ impl CtrlAnime<'static> {
|
||||
pub fn insert_asus_gif(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
file: &str,
|
||||
time: Timer,
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
@@ -207,7 +207,7 @@ impl CtrlAnime<'static> {
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
config.write();
|
||||
|
||||
let json = serde_json::to_string_pretty(&*config).expect("Parse config to JSON failed");
|
||||
|
||||
@@ -222,7 +222,7 @@ impl CtrlAnime<'static> {
|
||||
pub fn insert_image_gif(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
file: &str,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
xy: (f32, f32),
|
||||
@@ -252,7 +252,7 @@ impl CtrlAnime<'static> {
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
config.write();
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
@@ -268,7 +268,7 @@ impl CtrlAnime<'static> {
|
||||
pub fn insert_image(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
file: &str,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
xy: (f32, f32),
|
||||
@@ -297,7 +297,7 @@ impl CtrlAnime<'static> {
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
config.write();
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
@@ -322,7 +322,7 @@ impl CtrlAnime<'static> {
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
config.write();
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
@@ -345,7 +345,7 @@ impl CtrlAnime<'static> {
|
||||
if (index as usize) < config.anime.len() {
|
||||
config.anime.remove(index as usize);
|
||||
}
|
||||
config.write()?;
|
||||
config.write();
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_aura::aura_detection::LaptopLedData;
|
||||
use rog_aura::layouts::KeyLayout;
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
use rog_user::{
|
||||
ctrl_anime::{CtrlAnime, CtrlAnimeInner},
|
||||
user_config::*,
|
||||
DBUS_NAME,
|
||||
};
|
||||
use rog_user::config::*;
|
||||
use rog_user::ctrl_anime::{CtrlAnime, CtrlAnimeInner};
|
||||
use rog_user::DBUS_NAME;
|
||||
use smol::Executor;
|
||||
use std::sync::Mutex;
|
||||
use std::{fs::OpenOptions, io::Read, path::PathBuf, sync::Arc};
|
||||
use zbus::Connection;
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
#[cfg(not(feature = "local_data"))]
|
||||
const DATA_DIR: &str = "/usr/share/rog-gui/";
|
||||
#[cfg(feature = "local_data")]
|
||||
@@ -20,6 +21,13 @@ const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR");
|
||||
const BOARD_NAME: &str = "/sys/class/dmi/id/board_name";
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut logger = env_logger::Builder::new();
|
||||
logger
|
||||
.parse_default_env()
|
||||
.target(env_logger::Target::Stdout)
|
||||
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
|
||||
.init();
|
||||
|
||||
println!(" user daemon v{}", rog_user::VERSION);
|
||||
println!(" rog-anime v{}", rog_anime::VERSION);
|
||||
println!(" rog-dbus v{}", rog_dbus::VERSION);
|
||||
@@ -28,8 +36,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (client, _) = RogDbusClientBlocking::new()?;
|
||||
let supported = client.proxies().supported().supported_functions()?;
|
||||
|
||||
let mut config = UserConfig::new();
|
||||
config.load()?;
|
||||
let config = ConfigBase::new().load();
|
||||
|
||||
let executor = Executor::new();
|
||||
|
||||
@@ -38,7 +45,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
if supported.anime_ctrl.0 {
|
||||
if let Some(cfg) = config.active_anime {
|
||||
let anime_type = get_anime_type()?;
|
||||
let anime_config = UserAnimeConfig::load(cfg)?;
|
||||
let anime_config = ConfigAnime::new().set_name(cfg).load();
|
||||
let anime = anime_config.create(anime_type)?;
|
||||
let anime_config = Arc::new(Mutex::new(anime_config));
|
||||
|
||||
@@ -69,24 +76,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// if supported.keyboard_led.per_key_led_mode {
|
||||
if let Some(cfg) = config.active_aura {
|
||||
let mut aura_config = UserAuraConfig::load(cfg)?;
|
||||
let mut aura_config = ConfigAura::new().set_name(cfg).load();
|
||||
// let baord_name = std::fs::read_to_string(BOARD_NAME)?;
|
||||
|
||||
// Find and load a matching layout for laptop
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(PathBuf::from(BOARD_NAME))
|
||||
.map_err(|e| {
|
||||
println!("{BOARD_NAME}, {e}");
|
||||
e
|
||||
})?;
|
||||
let mut board_name = String::new();
|
||||
file.read_to_string(&mut board_name)?;
|
||||
let led_support = LaptopLedData::get_data();
|
||||
|
||||
let layout = KeyLayout::find_layout(board_name.as_str(), PathBuf::from(DATA_DIR))
|
||||
let layout = KeyLayout::find_layout(led_support, PathBuf::from(DATA_DIR))
|
||||
.map_err(|e| {
|
||||
println!("{BOARD_NAME}, {e}");
|
||||
})
|
||||
.unwrap_or(KeyLayout::ga401_layout());
|
||||
.unwrap_or_else(|_| KeyLayout::default_layout());
|
||||
|
||||
executor
|
||||
.spawn(async move {
|
||||
@@ -99,7 +98,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
aura_config.aura.next_state(&layout);
|
||||
let packets = aura_config.aura.create_packets();
|
||||
|
||||
client.proxies().led().per_key_raw(packets).unwrap();
|
||||
client
|
||||
.proxies()
|
||||
.led()
|
||||
.direct_addressing_raw(packets)
|
||||
.unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_millis(33));
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ pub enum Error {
|
||||
|
||||
impl fmt::Display for Error {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::Io(err) => write!(f, "Failed to open: {}", err),
|
||||
Error::ConfigLoadFail => write!(f, "Failed to load user config"),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
pub mod user_config;
|
||||
pub mod config;
|
||||
|
||||
pub mod error;
|
||||
|
||||
|
||||
@@ -1,318 +0,0 @@
|
||||
use std::{
|
||||
fs::{create_dir, OpenOptions},
|
||||
io::{Read, Write},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences, Vec2};
|
||||
use rog_aura::{keys::Key, Breathe, Colour, Effect, Flicker, LedType, Speed, Static};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
pub trait ConfigLoadSave<T: DeserializeOwned + serde::Serialize> {
|
||||
fn name(&self) -> String;
|
||||
|
||||
fn default_with_name(name: String) -> T;
|
||||
|
||||
fn write(&self) -> Result<(), Error>
|
||||
where
|
||||
Self: serde::Serialize,
|
||||
{
|
||||
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(())
|
||||
}
|
||||
|
||||
fn load(name: String) -> Result<T, 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 = Self::default_with_name(name);
|
||||
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::<T>(&buf) {
|
||||
return Ok(data);
|
||||
}
|
||||
}
|
||||
Err(Error::ConfigLoadFail)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct UserAnimeConfig {
|
||||
pub name: String,
|
||||
pub anime: Vec<ActionLoader>,
|
||||
}
|
||||
|
||||
impl UserAnimeConfig {
|
||||
pub fn create(&self, anime_type: AnimeType) -> Result<Sequences, Error> {
|
||||
let mut seq = Sequences::new(anime_type);
|
||||
|
||||
for (idx, action) in self.anime.iter().enumerate() {
|
||||
seq.insert(idx, action)?;
|
||||
}
|
||||
|
||||
Ok(seq)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigLoadSave<UserAnimeConfig> for UserAnimeConfig {
|
||||
fn name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn default_with_name(name: String) -> Self {
|
||||
UserAnimeConfig {
|
||||
name,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UserAnimeConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "default".to_string(),
|
||||
anime: vec![
|
||||
ActionLoader::AsusImage {
|
||||
file: "/usr/share/asusd/anime/custom/diagonal-template.png".into(),
|
||||
brightness: 1.0,
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(2),
|
||||
None,
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
},
|
||||
ActionLoader::AsusAnimation {
|
||||
file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(6),
|
||||
None,
|
||||
Duration::from_secs(3),
|
||||
)),
|
||||
},
|
||||
ActionLoader::ImageAnimation {
|
||||
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
|
||||
scale: 0.9,
|
||||
angle: 0.65,
|
||||
translation: Vec2::default(),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(2),
|
||||
Some(Duration::from_secs(2)),
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
},
|
||||
ActionLoader::Image {
|
||||
file: "/usr/share/asusd/anime/custom/rust.png".into(),
|
||||
scale: 1.0,
|
||||
angle: 0.0,
|
||||
translation: Vec2::default(),
|
||||
time: AnimTime::Fade(Fade::new(
|
||||
Duration::from_secs(2),
|
||||
Some(Duration::from_secs(1)),
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
brightness: 0.6,
|
||||
},
|
||||
ActionLoader::Pause(Duration::from_secs(1)),
|
||||
ActionLoader::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: 0.5,
|
||||
time: AnimTime::Count(2),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct UserAuraConfig {
|
||||
pub name: String,
|
||||
pub aura: rog_aura::Sequences,
|
||||
}
|
||||
|
||||
impl ConfigLoadSave<UserAuraConfig> for UserAuraConfig {
|
||||
fn name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn default_with_name(name: String) -> Self {
|
||||
UserAuraConfig {
|
||||
name,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UserAuraConfig {
|
||||
fn default() -> Self {
|
||||
let mut seq = rog_aura::Sequences::new();
|
||||
let mut key = Effect::Breathe(Breathe::new(
|
||||
LedType::Key(Key::W),
|
||||
Colour(255, 0, 20),
|
||||
Colour(20, 255, 0),
|
||||
Speed::Low,
|
||||
));
|
||||
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::A));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::S));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::D));
|
||||
seq.push(key);
|
||||
|
||||
let key = Effect::Breathe(Breathe::new(
|
||||
LedType::Key(Key::F),
|
||||
Colour(255, 0, 0),
|
||||
Colour(255, 0, 0),
|
||||
Speed::High,
|
||||
));
|
||||
seq.push(key);
|
||||
|
||||
let mut key = Effect::Static(Static::new(LedType::Key(Key::RCtrl), Colour(0, 0, 255)));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::LCtrl));
|
||||
seq.push(key.clone());
|
||||
key.set_led_type(LedType::Key(Key::Esc));
|
||||
seq.push(key);
|
||||
|
||||
let key = Effect::Flicker(Flicker::new(
|
||||
LedType::Key(Key::N9),
|
||||
Colour(0, 0, 255),
|
||||
80,
|
||||
40,
|
||||
));
|
||||
seq.push(key.clone());
|
||||
|
||||
Self {
|
||||
name: "default".to_string(),
|
||||
aura: seq,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct UserConfig {
|
||||
/// Name of active anime config file in the user config directory
|
||||
pub active_anime: Option<String>,
|
||||
/// Name of active aura config file in the user config directory
|
||||
pub active_aura: Option<String>,
|
||||
}
|
||||
|
||||
impl UserConfig {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
active_anime: Some("anime-default".to_string()),
|
||||
active_aura: Some("aura-default".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(&mut 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())?;
|
||||
}
|
||||
|
||||
path.push("rog-user.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 json = serde_json::to_string_pretty(&self).unwrap();
|
||||
file.write_all(json.as_bytes())?;
|
||||
} else if let Ok(data) = serde_json::from_str::<UserConfig>(&buf) {
|
||||
self.active_anime = data.active_anime;
|
||||
self.active_aura = data.active_aura;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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())?;
|
||||
}
|
||||
|
||||
path.push("rog-user.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(())
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||
//! # `DBus` interface proxy for: `org.asuslinux.Daemon`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||
//! Source: `Interface '/org/asuslinux/Anime' from service 'org.asuslinux.Daemon' on session bus`.
|
||||
//! This code was generated by `zbus-xmlgen` `1.0.0` from `DBus` introspection
|
||||
//! data. Source: `Interface '/org/asuslinux/Anime' from service
|
||||
//! 'org.asuslinux.Daemon' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
@@ -9,8 +10,8 @@
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! This `DBus` object implements
|
||||
//! [standard `DBus` interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "daemon"
|
||||
version = "4.4.0"
|
||||
license = "MPL-2.0"
|
||||
version.workspace = true
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||
description = "A daemon app for ASUS GX502 and similar laptops to control missing features"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "daemon"
|
||||
@@ -18,28 +18,33 @@ name = "asusd"
|
||||
path = "src/daemon.rs"
|
||||
|
||||
[dependencies]
|
||||
config-traits = { path = "../config-traits" }
|
||||
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
||||
rog_aura = { path = "../rog-aura", features = ["dbus"] }
|
||||
rog_platform = { path = "../rog-platform" }
|
||||
rog_profiles = { path = "../rog-profiles" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
|
||||
async-trait = "^0.1"
|
||||
smol = "^1.2"
|
||||
async-trait.workspace = true
|
||||
tokio.workspace = true
|
||||
|
||||
# cli and logging
|
||||
log = "^0.4"
|
||||
env_logger = "^0.9"
|
||||
log.workspace = true
|
||||
env_logger.workspace = true
|
||||
|
||||
zbus = "^2.2"
|
||||
zvariant = "^3.2"
|
||||
logind-zbus = { version = "^3.0" } #, default-features = false, features = ["non_blocking"] }
|
||||
zbus.workspace = true
|
||||
logind-zbus.workspace = true
|
||||
|
||||
# serialisation
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
serde_json = "^1.0"
|
||||
toml = "^0.5.8"
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
|
||||
# Device control
|
||||
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
||||
sysfs-class.workspace = true # used for backlight control and baord ID
|
||||
|
||||
concat-idents.workspace = true
|
||||
|
||||
systemd-zbus = "*"
|
||||
|
||||
[dev-dependencies]
|
||||
cargo-husky.workspace = true
|
||||
@@ -1,83 +1,77 @@
|
||||
use log::{error, warn};
|
||||
use config_traits::{StdConfig, StdConfigLoad2};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
||||
const CONFIG_FILE: &str = "asusd.ron";
|
||||
|
||||
#[derive(Deserialize, Serialize, Default, Debug)]
|
||||
pub struct Config {
|
||||
/// Save charge limit for restoring on boot
|
||||
pub bat_charge_limit: u8,
|
||||
pub panel_od: bool,
|
||||
pub disable_nvidia_powerd_on_battery: bool,
|
||||
pub ac_command: String,
|
||||
pub bat_command: String,
|
||||
}
|
||||
|
||||
impl StdConfig for Config {
|
||||
fn new() -> Self {
|
||||
Config {
|
||||
bat_charge_limit: 100,
|
||||
panel_od: false,
|
||||
disable_nvidia_powerd_on_battery: true,
|
||||
ac_command: String::new(),
|
||||
bat_command: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
CONFIG_FILE.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad2<Config455, Config458> for Config {}
|
||||
|
||||
#[derive(Deserialize, Serialize, Default)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
pub struct Config455 {
|
||||
/// Save charge limit for restoring on boot
|
||||
pub bat_charge_limit: u8,
|
||||
pub panel_od: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn new() -> Self {
|
||||
Config {
|
||||
bat_charge_limit: 100,
|
||||
panel_od: false,
|
||||
impl From<Config455> for Config {
|
||||
fn from(c: Config455) -> Self {
|
||||
Self {
|
||||
bat_charge_limit: c.bat_charge_limit,
|
||||
panel_od: c.panel_od,
|
||||
disable_nvidia_powerd_on_battery: true,
|
||||
ac_command: String::new(),
|
||||
bat_command: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Default)]
|
||||
pub struct Config458 {
|
||||
/// Save charge limit for restoring on boot
|
||||
pub bat_charge_limit: u8,
|
||||
pub panel_od: bool,
|
||||
pub ac_command: String,
|
||||
pub bat_command: String,
|
||||
}
|
||||
|
||||
impl From<Config458> for Config {
|
||||
fn from(c: Config458) -> Self {
|
||||
Self {
|
||||
bat_charge_limit: c.bat_charge_limit,
|
||||
panel_od: c.panel_od,
|
||||
disable_nvidia_powerd_on_battery: true,
|
||||
ac_command: c.ac_command,
|
||||
bat_command: c.bat_command,
|
||||
}
|
||||
}
|
||||
|
||||
/// `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(&PathBuf::from(CONFIG_PATH))
|
||||
.unwrap_or_else(|e| panic!("Error opening {}, {}", CONFIG_PATH, e)); // okay to cause panic here
|
||||
let mut buf = String::new();
|
||||
let config;
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len == 0 {
|
||||
config = Self::new();
|
||||
} else if let Ok(data) = serde_json::from_str(&buf) {
|
||||
config = data;
|
||||
} else {
|
||||
warn!(
|
||||
"Could not deserialise {}.\nWill rename to {}-old and recreate config",
|
||||
CONFIG_PATH, CONFIG_PATH
|
||||
);
|
||||
let cfg_old = CONFIG_PATH.to_string() + "-old";
|
||||
std::fs::rename(CONFIG_PATH, cfg_old).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
CONFIG_PATH, err
|
||||
)
|
||||
});
|
||||
config = Self::new();
|
||||
}
|
||||
} else {
|
||||
config = Self::new()
|
||||
}
|
||||
config.write();
|
||||
config
|
||||
}
|
||||
|
||||
pub fn read(&mut self) {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&CONFIG_PATH)
|
||||
.unwrap_or_else(|err| panic!("Error reading {}: {}", 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 {}", CONFIG_PATH);
|
||||
} else {
|
||||
*self = serde_json::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = File::create(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,14 +1,11 @@
|
||||
use crate::VERSION;
|
||||
use log::{error, info, warn};
|
||||
use rog_anime::{error::AnimeError, ActionData, ActionLoader, AnimTime, Vec2};
|
||||
use rog_anime::{AnimeType, Fade};
|
||||
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";
|
||||
use config_traits::{StdConfig, StdConfigLoad2};
|
||||
use rog_anime::error::AnimeError;
|
||||
use rog_anime::{ActionData, ActionLoader, AnimTime, AnimeType, Fade, Vec2};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
const CONFIG_FILE: &str = "anime.ron";
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct AnimeConfigV341 {
|
||||
@@ -18,25 +15,30 @@ pub struct AnimeConfigV341 {
|
||||
pub shutdown: Option<ActionLoader>,
|
||||
}
|
||||
|
||||
impl AnimeConfigV341 {
|
||||
pub(crate) fn into_current(self) -> AnimeConfig {
|
||||
impl From<AnimeConfigV341> for AnimeConfig {
|
||||
fn from(c: AnimeConfigV341) -> AnimeConfig {
|
||||
AnimeConfig {
|
||||
system: if let Some(ani) = self.system {
|
||||
system: if let Some(ani) = c.system {
|
||||
vec![ani]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
boot: if let Some(ani) = self.boot {
|
||||
boot: if let Some(ani) = c.boot {
|
||||
vec![ani]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
wake: if let Some(ani) = self.suspend {
|
||||
wake: if let Some(ani) = c.suspend {
|
||||
vec![ani]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
shutdown: if let Some(ani) = self.shutdown {
|
||||
shutdown: if let Some(ani) = c.shutdown.clone() {
|
||||
vec![ani]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
sleep: if let Some(ani) = c.shutdown.clone() {
|
||||
vec![ani]
|
||||
} else {
|
||||
vec![]
|
||||
@@ -57,13 +59,39 @@ pub struct AnimeConfigV352 {
|
||||
pub brightness: f32,
|
||||
}
|
||||
|
||||
impl AnimeConfigV352 {
|
||||
pub(crate) fn into_current(self) -> AnimeConfig {
|
||||
impl From<AnimeConfigV352> for AnimeConfig {
|
||||
fn from(c: AnimeConfigV352) -> AnimeConfig {
|
||||
AnimeConfig {
|
||||
system: self.system,
|
||||
boot: self.boot,
|
||||
wake: self.wake,
|
||||
shutdown: self.shutdown,
|
||||
system: c.system,
|
||||
boot: c.boot,
|
||||
wake: c.wake,
|
||||
sleep: c.shutdown.clone(),
|
||||
shutdown: c.shutdown,
|
||||
brightness: 1.0,
|
||||
awake_enabled: true,
|
||||
boot_anim_enabled: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct AnimeConfigV460 {
|
||||
pub system: Vec<ActionLoader>,
|
||||
pub boot: Vec<ActionLoader>,
|
||||
pub wake: Vec<ActionLoader>,
|
||||
pub sleep: Vec<ActionLoader>,
|
||||
pub shutdown: Vec<ActionLoader>,
|
||||
pub brightness: f32,
|
||||
}
|
||||
|
||||
impl From<AnimeConfigV460> for AnimeConfig {
|
||||
fn from(c: AnimeConfigV460) -> AnimeConfig {
|
||||
AnimeConfig {
|
||||
system: c.system,
|
||||
boot: c.boot,
|
||||
wake: c.wake,
|
||||
sleep: c.sleep,
|
||||
shutdown: c.shutdown,
|
||||
brightness: 1.0,
|
||||
awake_enabled: true,
|
||||
boot_anim_enabled: true,
|
||||
@@ -76,6 +104,7 @@ pub struct AnimeConfigCached {
|
||||
pub system: Vec<ActionData>,
|
||||
pub boot: Vec<ActionData>,
|
||||
pub wake: Vec<ActionData>,
|
||||
pub sleep: Vec<ActionData>,
|
||||
pub shutdown: Vec<ActionData>,
|
||||
}
|
||||
|
||||
@@ -86,25 +115,31 @@ impl AnimeConfigCached {
|
||||
anime_type: AnimeType,
|
||||
) -> Result<(), AnimeError> {
|
||||
let mut sys = Vec::with_capacity(config.system.len());
|
||||
for ani in config.system.iter() {
|
||||
for ani in &config.system {
|
||||
sys.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.system = sys;
|
||||
|
||||
let mut boot = Vec::with_capacity(config.boot.len());
|
||||
for ani in config.boot.iter() {
|
||||
for ani in &config.boot {
|
||||
boot.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.boot = boot;
|
||||
|
||||
let mut wake = Vec::with_capacity(config.wake.len());
|
||||
for ani in config.wake.iter() {
|
||||
for ani in &config.wake {
|
||||
wake.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.wake = wake;
|
||||
|
||||
let mut sleep = Vec::with_capacity(config.sleep.len());
|
||||
for ani in &config.sleep {
|
||||
sleep.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.sleep = sleep;
|
||||
|
||||
let mut shutdown = Vec::with_capacity(config.shutdown.len());
|
||||
for ani in config.shutdown.iter() {
|
||||
for ani in &config.shutdown {
|
||||
shutdown.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.shutdown = shutdown;
|
||||
@@ -113,11 +148,12 @@ impl AnimeConfigCached {
|
||||
}
|
||||
|
||||
/// Config for base system actions for the anime display
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct AnimeConfig {
|
||||
pub system: Vec<ActionLoader>,
|
||||
pub boot: Vec<ActionLoader>,
|
||||
pub wake: Vec<ActionLoader>,
|
||||
pub sleep: Vec<ActionLoader>,
|
||||
pub shutdown: Vec<ActionLoader>,
|
||||
pub brightness: f32,
|
||||
pub awake_enabled: bool,
|
||||
@@ -130,6 +166,7 @@ impl Default for AnimeConfig {
|
||||
system: Vec::new(),
|
||||
boot: Vec::new(),
|
||||
wake: Vec::new(),
|
||||
sleep: Vec::new(),
|
||||
shutdown: Vec::new(),
|
||||
brightness: 1.0,
|
||||
awake_enabled: true,
|
||||
@@ -138,70 +175,36 @@ impl Default for AnimeConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfig for AnimeConfig {
|
||||
fn new() -> Self {
|
||||
Self::create_default()
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
CONFIG_FILE.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad2<AnimeConfigV341, AnimeConfigV352> for AnimeConfig {}
|
||||
|
||||
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(mut data) = serde_json::from_str(&buf) {
|
||||
Self::clamp_config_brightness(&mut data);
|
||||
return data;
|
||||
} else if let Ok(data) = serde_json::from_str::<AnimeConfigV341>(&buf) {
|
||||
let mut config = data.into_current();
|
||||
config.write();
|
||||
info!("Updated config version to: {}", VERSION);
|
||||
Self::clamp_config_brightness(&mut config);
|
||||
return config;
|
||||
} else if let Ok(data) = serde_json::from_str::<AnimeConfigV352>(&buf) {
|
||||
let mut config = data.into_current();
|
||||
config.write();
|
||||
info!("Updated config version to: {}", VERSION);
|
||||
Self::clamp_config_brightness(&mut config);
|
||||
return config;
|
||||
}
|
||||
warn!(
|
||||
"Could not deserialise {}.\nWill rename to {}-old and recreate config",
|
||||
ANIME_CONFIG_PATH, ANIME_CONFIG_PATH
|
||||
);
|
||||
let cfg_old = ANIME_CONFIG_PATH.to_string() + "-old";
|
||||
std::fs::rename(ANIME_CONFIG_PATH, cfg_old).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
ANIME_CONFIG_PATH, err
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
AnimeConfig::create_default(&mut file)
|
||||
}
|
||||
// fn clamp_config_brightness(mut config: &mut AnimeConfig) {
|
||||
// if config.brightness < 0.0 || config.brightness > 1.0 {
|
||||
// warn!(
|
||||
// "Clamped brightness to [0.0 ; 1.0], was {}",
|
||||
// config.brightness
|
||||
// );
|
||||
// config.brightness = f32::max(0.0, f32::min(1.0, config.brightness));
|
||||
// }
|
||||
// }
|
||||
|
||||
fn clamp_config_brightness(mut config: &mut AnimeConfig) {
|
||||
if config.brightness < 0.0 || config.brightness > 1.0 {
|
||||
warn!(
|
||||
"Clamped brightness to [0.0 ; 1.0], was {}",
|
||||
config.brightness
|
||||
);
|
||||
config.brightness = f32::max(0.0, f32::min(1.0, config.brightness));
|
||||
}
|
||||
}
|
||||
|
||||
fn create_default(file: &mut File) -> Self {
|
||||
fn create_default() -> Self {
|
||||
// create a default config here
|
||||
let config = AnimeConfig {
|
||||
AnimeConfig {
|
||||
system: vec![],
|
||||
boot: vec![ActionLoader::ImageAnimation {
|
||||
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
|
||||
@@ -227,6 +230,14 @@ impl AnimeConfig {
|
||||
Duration::from_secs(2),
|
||||
)),
|
||||
}],
|
||||
sleep: vec![ActionLoader::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,
|
||||
}],
|
||||
shutdown: vec![ActionLoader::ImageAnimation {
|
||||
file: "/usr/share/asusd/anime/custom/sonic-wait.gif".into(),
|
||||
scale: 0.9,
|
||||
@@ -238,35 +249,6 @@ impl AnimeConfig {
|
||||
brightness: 1.0,
|
||||
awake_enabled: true,
|
||||
boot_anim_enabled: true,
|
||||
};
|
||||
// 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,29 +1,25 @@
|
||||
pub mod config;
|
||||
pub mod zbus;
|
||||
/// Implements `CtrlTask`, Reloadable, `ZbusRun`
|
||||
pub mod trait_impls;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{error, info, warn};
|
||||
use rog_anime::{
|
||||
error::AnimeError,
|
||||
usb::{
|
||||
get_anime_type, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on,
|
||||
pkts_for_init,
|
||||
},
|
||||
ActionData, AnimeDataBuffer, AnimePacketType, AnimeType,
|
||||
};
|
||||
use rog_platform::{hid_raw::HidRaw, supported::AnimeSupportedFunctions, usb_raw::USBRaw};
|
||||
use smol::Executor;
|
||||
use std::convert::TryFrom;
|
||||
use std::error::Error;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
error::Error,
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
thread::sleep,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::thread::sleep;
|
||||
|
||||
use crate::{error::RogError, GetSupported};
|
||||
use ::zbus::export::futures_util::lock::Mutex;
|
||||
use log::{error, info, warn};
|
||||
use rog_anime::error::AnimeError;
|
||||
use rog_anime::usb::{get_anime_type, pkt_for_flush, pkts_for_init};
|
||||
use rog_anime::{ActionData, AnimeDataBuffer, AnimePacketType, AnimeType};
|
||||
use rog_platform::hid_raw::HidRaw;
|
||||
use rog_platform::supported::AnimeSupportedFunctions;
|
||||
use rog_platform::usb_raw::USBRaw;
|
||||
|
||||
use self::config::{AnimeConfig, AnimeConfigCached};
|
||||
use crate::error::RogError;
|
||||
use crate::GetSupported;
|
||||
|
||||
impl GetSupported for CtrlAnime {
|
||||
type A = AnimeSupportedFunctions;
|
||||
@@ -66,13 +62,14 @@ impl CtrlAnime {
|
||||
|
||||
Ok(ctrl)
|
||||
}
|
||||
|
||||
// let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
|
||||
|
||||
/// 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.
|
||||
/// 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.
|
||||
/// 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");
|
||||
@@ -80,11 +77,15 @@ impl CtrlAnime {
|
||||
}
|
||||
|
||||
// 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
|
||||
// - 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
|
||||
// The only reason for this outer thread is to prevent blocking while waiting
|
||||
// for the next spawned thread to exit
|
||||
// TODO: turn this in to async task (maybe? COuld still risk blocking main
|
||||
// thread)
|
||||
std::thread::Builder::new()
|
||||
.name("AniMe system thread start".into())
|
||||
.spawn(move || {
|
||||
@@ -95,7 +96,7 @@ impl CtrlAnime {
|
||||
let thread_running;
|
||||
let anime_type;
|
||||
loop {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
if let Some(lock) = inner.try_lock() {
|
||||
thread_exit = lock.thread_exit.clone();
|
||||
thread_running = lock.thread_running.clone();
|
||||
anime_type = lock.anime_type;
|
||||
@@ -112,18 +113,17 @@ impl CtrlAnime {
|
||||
|
||||
info!("AniMe no previous system thread running (now)");
|
||||
thread_exit.store(false, Ordering::SeqCst);
|
||||
|
||||
thread_running.store(true, Ordering::SeqCst);
|
||||
'main: loop {
|
||||
thread_running.store(true, Ordering::SeqCst);
|
||||
for action in actions.iter() {
|
||||
for action in &actions {
|
||||
if thread_exit.load(Ordering::SeqCst) {
|
||||
break 'main;
|
||||
}
|
||||
match action {
|
||||
ActionData::Animation(frames) => {
|
||||
if let Err(err) = rog_anime::run_animation(frames, &|frame| {
|
||||
rog_anime::run_animation(frames, &|frame| {
|
||||
if thread_exit.load(Ordering::Acquire) {
|
||||
info!("rog-anime: frame-loop was asked to exit");
|
||||
info!("rog-anime: animation sub-loop was asked to exit");
|
||||
return Ok(true); // Do safe exit
|
||||
}
|
||||
inner
|
||||
@@ -139,28 +139,32 @@ impl CtrlAnime {
|
||||
.ok();
|
||||
false // Don't exit yet
|
||||
})
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
AnimeError::NoFrames
|
||||
})
|
||||
}) {
|
||||
warn!("rog_anime::run_animation:Animation {}", err);
|
||||
.map_or_else(
|
||||
|| {
|
||||
warn!("rog_anime::run_animation:callback failed");
|
||||
Err(AnimeError::NoFrames)
|
||||
},
|
||||
Ok,
|
||||
)
|
||||
});
|
||||
if thread_exit.load(Ordering::Acquire) {
|
||||
info!("rog-anime: sub-loop exited and main loop exiting now");
|
||||
break 'main;
|
||||
};
|
||||
}
|
||||
}
|
||||
ActionData::Image(image) => {
|
||||
once = false;
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
if let Some(lock) = inner.try_lock() {
|
||||
lock.write_data_buffer(image.as_ref().clone())
|
||||
.map_err(|e| error!("{}", e))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
ActionData::Pause(duration) => sleep(*duration),
|
||||
ActionData::AudioEq => {}
|
||||
ActionData::SystemInfo => {}
|
||||
ActionData::TimeDate => {}
|
||||
ActionData::Matrix => {}
|
||||
ActionData::AudioEq
|
||||
| ActionData::SystemInfo
|
||||
| ActionData::TimeDate
|
||||
| ActionData::Matrix => {}
|
||||
}
|
||||
}
|
||||
if thread_exit.load(Ordering::SeqCst) {
|
||||
@@ -171,7 +175,7 @@ impl CtrlAnime {
|
||||
}
|
||||
}
|
||||
// Clear the display on exit
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
if let Some(lock) = inner.try_lock() {
|
||||
if let Ok(data) =
|
||||
AnimeDataBuffer::from_vec(anime_type, vec![0u8; anime_type.data_length()])
|
||||
.map_err(|e| error!("{}", e))
|
||||
@@ -202,7 +206,7 @@ impl CtrlAnime {
|
||||
*led = bright as u8;
|
||||
}
|
||||
let data = AnimePacketType::try_from(buffer)?;
|
||||
for row in data.iter() {
|
||||
for row in &data {
|
||||
self.node.write_bytes(row)?;
|
||||
}
|
||||
self.node.write_bytes(&pkt_for_flush())?;
|
||||
@@ -216,85 +220,3 @@ impl CtrlAnime {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnimeTask {
|
||||
inner: Arc<Mutex<CtrlAnime>>,
|
||||
}
|
||||
|
||||
impl CtrlAnimeTask {
|
||||
pub async fn new(inner: Arc<Mutex<CtrlAnime>>) -> CtrlAnimeTask {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::CtrlTask for CtrlAnimeTask {
|
||||
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
let run_action =
|
||||
|start: bool, lock: MutexGuard<CtrlAnime>, inner: Arc<Mutex<CtrlAnime>>| {
|
||||
if start {
|
||||
info!("CtrlAnimeTask running sleep animation");
|
||||
CtrlAnime::run_thread(inner.clone(), lock.cache.shutdown.clone(), true);
|
||||
} else {
|
||||
info!("CtrlAnimeTask running wake animation");
|
||||
CtrlAnime::run_thread(inner.clone(), lock.cache.wake.clone(), true);
|
||||
}
|
||||
};
|
||||
|
||||
let inner1 = self.inner.clone();
|
||||
let inner2 = self.inner.clone();
|
||||
let inner3 = self.inner.clone();
|
||||
let inner4 = self.inner.clone();
|
||||
self.create_sys_event_tasks(
|
||||
executor,
|
||||
// Loop is required to try an attempt to get the mutex *without* blocking
|
||||
// other threads - it is possible to end up with deadlocks otherwise.
|
||||
move || loop {
|
||||
if let Ok(lock) = inner1.clone().try_lock() {
|
||||
run_action(true, lock, inner1.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Ok(lock) = inner2.clone().try_lock() {
|
||||
run_action(false, lock, inner2.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Ok(lock) = inner3.clone().try_lock() {
|
||||
run_action(true, lock, inner3.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Ok(lock) = inner4.clone().try_lock() {
|
||||
run_action(false, lock, inner4.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
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() {
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?;
|
||||
lock.node.write_bytes(&pkt_for_apply())?;
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled))?;
|
||||
lock.node.write_bytes(&pkt_for_apply())?;
|
||||
|
||||
let action = lock.cache.boot.clone();
|
||||
CtrlAnime::run_thread(self.0.clone(), action, true);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
212
daemon/src/ctrl_anime/trait_impls.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use config_traits::StdConfig;
|
||||
use log::warn;
|
||||
use rog_anime::usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on};
|
||||
use rog_anime::{AnimeDataBuffer, AnimePowerStates};
|
||||
use zbus::export::futures_util::lock::Mutex;
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use super::CtrlAnime;
|
||||
use crate::error::RogError;
|
||||
|
||||
pub(super) const ZBUS_PATH: &str = "/org/asuslinux/Anime";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
/// The struct with the main dbus methods requires this trait
|
||||
#[async_trait]
|
||||
impl crate::ZbusRun for CtrlAnimeZbus {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, ZBUS_PATH, server).await;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> {
|
||||
let lock = self.0.lock().await;
|
||||
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||
lock.write_data_buffer(input).map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
err
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the global AniMe brightness
|
||||
async fn set_brightness(&self, bright: f32) {
|
||||
let mut lock = self.0.lock().await;
|
||||
let mut bright = bright;
|
||||
if bright < 0.0 {
|
||||
bright = 0.0;
|
||||
} else if bright > 1.0 {
|
||||
bright = 1.0;
|
||||
}
|
||||
lock.config.brightness = bright;
|
||||
lock.config.write();
|
||||
}
|
||||
|
||||
/// Set whether the AniMe is displaying images/data
|
||||
async fn set_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) {
|
||||
let mut lock = self.0.lock().await;
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_on(status))
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
})
|
||||
.ok();
|
||||
lock.config.awake_enabled = status;
|
||||
lock.config.write();
|
||||
|
||||
Self::notify_power_states(
|
||||
&ctxt,
|
||||
AnimePowerStates {
|
||||
brightness: lock.config.brightness.floor() as u8,
|
||||
enabled: lock.config.awake_enabled,
|
||||
boot_anim_enabled: lock.config.boot_anim_enabled,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// Set whether the AniMe will show boot, suspend, or off animations
|
||||
async fn set_boot_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, on: bool) {
|
||||
let mut lock = self.0.lock().await;
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_boot(on))
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
})
|
||||
.ok();
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_apply())
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
})
|
||||
.ok();
|
||||
lock.config.boot_anim_enabled = on;
|
||||
lock.config.write();
|
||||
|
||||
Self::notify_power_states(
|
||||
&ctxt,
|
||||
AnimePowerStates {
|
||||
brightness: lock.config.brightness.floor() as u8,
|
||||
enabled: lock.config.awake_enabled,
|
||||
boot_anim_enabled: lock.config.boot_anim_enabled,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// The main loop is the base system set action if the user isn't running
|
||||
/// the user daemon
|
||||
async fn run_main_loop(&self, start: bool) {
|
||||
if start {
|
||||
let lock = self.0.lock().await;
|
||||
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||
CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get status of if the AniMe LEDs are on/displaying while system is awake
|
||||
#[dbus_interface(property)]
|
||||
async fn awake_enabled(&self) -> bool {
|
||||
let lock = self.0.lock().await;
|
||||
lock.config.awake_enabled
|
||||
}
|
||||
|
||||
/// Get the status of if factory system-status animations are enabled
|
||||
#[dbus_interface(property)]
|
||||
async fn boot_enabled(&self) -> bool {
|
||||
let lock = self.0.lock().await;
|
||||
lock.config.boot_anim_enabled
|
||||
}
|
||||
|
||||
/// Notify listeners of the status of AniMe LED power and factory
|
||||
/// system-status animations
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_power_states(
|
||||
ctxt: &SignalContext<'_>,
|
||||
data: AnimePowerStates,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::CtrlTask for CtrlAnimeZbus {
|
||||
fn zbus_path() -> &'static str {
|
||||
ZBUS_PATH
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let inner1 = self.0.clone();
|
||||
let inner2 = self.0.clone();
|
||||
let inner3 = self.0.clone();
|
||||
let inner4 = self.0.clone();
|
||||
self.create_sys_event_tasks(
|
||||
move || {
|
||||
// on_sleep
|
||||
let inner1 = inner1.clone();
|
||||
async move {
|
||||
let lock = inner1.lock().await;
|
||||
CtrlAnime::run_thread(inner1.clone(), lock.cache.sleep.clone(), true);
|
||||
}
|
||||
},
|
||||
move || {
|
||||
// on_wake
|
||||
let inner2 = inner2.clone();
|
||||
async move {
|
||||
let lock = inner2.lock().await;
|
||||
CtrlAnime::run_thread(inner2.clone(), lock.cache.wake.clone(), true);
|
||||
}
|
||||
},
|
||||
move || {
|
||||
// on_shutdown
|
||||
let inner3 = inner3.clone();
|
||||
async move {
|
||||
let lock = inner3.lock().await;
|
||||
CtrlAnime::run_thread(inner3.clone(), lock.cache.shutdown.clone(), true);
|
||||
}
|
||||
},
|
||||
move || {
|
||||
// on_boot
|
||||
let inner4 = inner4.clone();
|
||||
async move {
|
||||
let lock = inner4.lock().await;
|
||||
CtrlAnime::run_thread(inner4.clone(), lock.cache.boot.clone(), true);
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Reloadable for CtrlAnimeZbus {
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Some(lock) = self.0.try_lock() {
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?;
|
||||
lock.node.write_bytes(&pkt_for_apply())?;
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled))?;
|
||||
lock.node.write_bytes(&pkt_for_apply())?;
|
||||
|
||||
let action = lock.cache.boot.clone();
|
||||
CtrlAnime::run_thread(self.0.clone(), action, true);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::warn;
|
||||
use rog_anime::{
|
||||
usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on},
|
||||
AnimeDataBuffer, AnimePowerStates,
|
||||
};
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use super::CtrlAnime;
|
||||
|
||||
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
/// The struct with the main dbus methods requires this trait
|
||||
#[async_trait]
|
||||
impl crate::ZbusAdd for CtrlAnimeZbus {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, "/org/asuslinux/Anime", server).await;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) -> zbus::fdo::Result<()> {
|
||||
'outer: loop {
|
||||
if let Ok(lock) = self.0.try_lock() {
|
||||
lock.thread_exit.store(true, Ordering::SeqCst);
|
||||
lock.write_data_buffer(input).map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
err
|
||||
})?;
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the global AniMe brightness
|
||||
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 > 1.0 {
|
||||
bright = 1.0;
|
||||
}
|
||||
lock.config.brightness = bright;
|
||||
lock.config.write();
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set whether the AniMe is displaying images/data
|
||||
async fn set_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) {
|
||||
let states;
|
||||
'outer: loop {
|
||||
if let Ok(mut lock) = self.0.try_lock() {
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_on(status))
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
})
|
||||
.ok();
|
||||
lock.config.awake_enabled = status;
|
||||
lock.config.write();
|
||||
|
||||
states = Some(AnimePowerStates {
|
||||
brightness: lock.config.brightness.floor() as u8,
|
||||
enabled: lock.config.awake_enabled,
|
||||
boot_anim_enabled: lock.config.boot_anim_enabled,
|
||||
});
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
if let Some(state) = states {
|
||||
Self::notify_power_states(&ctxt, state).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// Set whether the AniMe will show boot, suspend, or off animations
|
||||
async fn set_boot_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, on: bool) {
|
||||
let states;
|
||||
'outer: loop {
|
||||
if let Ok(mut lock) = self.0.try_lock() {
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_set_boot(on))
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
})
|
||||
.ok();
|
||||
lock.node
|
||||
.write_bytes(&pkt_for_apply())
|
||||
.map_err(|err| {
|
||||
warn!("rog_anime::run_animation:callback {}", err);
|
||||
})
|
||||
.ok();
|
||||
lock.config.boot_anim_enabled = on;
|
||||
lock.config.write();
|
||||
|
||||
states = Some(AnimePowerStates {
|
||||
brightness: lock.config.brightness.floor() as u8,
|
||||
enabled: lock.config.awake_enabled,
|
||||
boot_anim_enabled: lock.config.boot_anim_enabled,
|
||||
});
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
if let Some(state) = states {
|
||||
Self::notify_power_states(&ctxt, state).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get status of if the AniMe LEDs are on/displaying while system is awake
|
||||
#[dbus_interface(property)]
|
||||
fn awake_enabled(&self) -> bool {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
return ctrl.config.awake_enabled;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Get the status of if factory system-status animations are enabled
|
||||
#[dbus_interface(property)]
|
||||
fn boot_enabled(&self) -> bool {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
return ctrl.config.boot_anim_enabled;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Notify listeners of the status of AniMe LED power and factory system-status animations
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_power_states(
|
||||
ctxt: &SignalContext<'_>,
|
||||
data: AnimePowerStates,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
use crate::laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES};
|
||||
use log::{error, warn};
|
||||
use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev};
|
||||
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT};
|
||||
use rog_platform::hid_raw::HidRaw;
|
||||
use rog_platform::keyboard_led::KeyboardLed;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use rog_aura::aura_detection::LaptopLedData;
|
||||
use rog_aura::usb::{AuraDevRog1, AuraDevRog2, AuraDevTuf, AuraDevice, AuraPowerDev};
|
||||
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
const CONFIG_FILE: &str = "aura.ron";
|
||||
|
||||
/// Enable/disable LED control in various states such as
|
||||
/// when the device is awake, suspended, shutting down or
|
||||
@@ -17,8 +14,8 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AuraPowerConfig {
|
||||
AuraDevTuf(HashSet<AuraDevTuf>),
|
||||
AuraDev1866(HashSet<AuraDev1866>),
|
||||
AuraDev19b6(HashSet<AuraDev19b6>),
|
||||
AuraDevRog1(HashSet<AuraDevRog1>),
|
||||
AuraDevRog2(HashSet<AuraDevRog2>),
|
||||
}
|
||||
|
||||
impl AuraPowerConfig {
|
||||
@@ -26,13 +23,13 @@ impl AuraPowerConfig {
|
||||
pub fn to_bytes(control: &Self) -> [u8; 3] {
|
||||
match control {
|
||||
AuraPowerConfig::AuraDevTuf(_) => [0, 0, 0],
|
||||
AuraPowerConfig::AuraDev1866(c) => {
|
||||
let c: Vec<AuraDev1866> = c.iter().map(|v| *v).collect();
|
||||
AuraDev1866::to_bytes(&c)
|
||||
AuraPowerConfig::AuraDevRog1(c) => {
|
||||
let c: Vec<AuraDevRog1> = c.iter().copied().collect();
|
||||
AuraDevRog1::to_bytes(&c)
|
||||
}
|
||||
AuraPowerConfig::AuraDev19b6(c) => {
|
||||
let c: Vec<AuraDev19b6> = c.iter().map(|v| *v).collect();
|
||||
AuraDev19b6::to_bytes(&c)
|
||||
AuraPowerConfig::AuraDevRog2(c) => {
|
||||
let c: Vec<AuraDevRog2> = c.iter().copied().collect();
|
||||
AuraDevRog2::to_bytes(&c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,13 +45,13 @@ impl AuraPowerConfig {
|
||||
]);
|
||||
}
|
||||
|
||||
if let Self::AuraDev1866(c) = control {
|
||||
if let Self::AuraDevRog1(c) = control {
|
||||
return Some([
|
||||
true,
|
||||
c.contains(&AuraDev1866::Boot),
|
||||
c.contains(&AuraDev1866::Awake),
|
||||
c.contains(&AuraDev1866::Sleep),
|
||||
c.contains(&AuraDev1866::Keyboard),
|
||||
c.contains(&AuraDevRog1::Boot),
|
||||
c.contains(&AuraDevRog1::Awake),
|
||||
c.contains(&AuraDevRog1::Sleep),
|
||||
c.contains(&AuraDevRog1::Keyboard),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -70,8 +67,9 @@ impl AuraPowerConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn set_0x1866(&mut self, power: AuraDev1866, on: bool) {
|
||||
if let Self::AuraDev1866(p) = self {
|
||||
|
||||
pub fn set_0x1866(&mut self, power: AuraDevRog1, on: bool) {
|
||||
if let Self::AuraDevRog1(p) = self {
|
||||
if on {
|
||||
p.insert(power);
|
||||
} else {
|
||||
@@ -80,8 +78,8 @@ impl AuraPowerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_0x19b6(&mut self, power: AuraDev19b6, on: bool) {
|
||||
if let Self::AuraDev19b6(p) = self {
|
||||
pub fn set_0x19b6(&mut self, power: AuraDevRog2, on: bool) {
|
||||
if let Self::AuraDevRog2(p) = self {
|
||||
if on {
|
||||
p.insert(power);
|
||||
} else {
|
||||
@@ -95,26 +93,26 @@ impl From<&AuraPowerConfig> for AuraPowerDev {
|
||||
fn from(config: &AuraPowerConfig) -> Self {
|
||||
match config {
|
||||
AuraPowerConfig::AuraDevTuf(d) => AuraPowerDev {
|
||||
tuf: d.iter().map(|o| *o).collect(),
|
||||
tuf: d.iter().copied().collect(),
|
||||
x1866: vec![],
|
||||
x19b6: vec![],
|
||||
},
|
||||
AuraPowerConfig::AuraDev1866(d) => AuraPowerDev {
|
||||
AuraPowerConfig::AuraDevRog1(d) => AuraPowerDev {
|
||||
tuf: vec![],
|
||||
x1866: d.iter().map(|o| *o).collect(),
|
||||
x1866: d.iter().copied().collect(),
|
||||
x19b6: vec![],
|
||||
},
|
||||
AuraPowerConfig::AuraDev19b6(d) => AuraPowerDev {
|
||||
AuraPowerConfig::AuraDevRog2(d) => AuraPowerDev {
|
||||
tuf: vec![],
|
||||
x1866: vec![],
|
||||
x19b6: d.iter().map(|o| *o).collect(),
|
||||
x19b6: d.iter().copied().collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
// #[serde(default)]
|
||||
pub struct AuraConfig {
|
||||
pub brightness: LedBrightness,
|
||||
pub current_mode: AuraModeNum,
|
||||
@@ -124,38 +122,40 @@ pub struct AuraConfig {
|
||||
pub enabled: AuraPowerConfig,
|
||||
}
|
||||
|
||||
impl Default for AuraConfig {
|
||||
fn default() -> Self {
|
||||
let mut prod_id = AuraDevice::Unknown;
|
||||
for prod in ASUS_KEYBOARD_DEVICES.iter() {
|
||||
if let Ok(_) = HidRaw::new(prod) {
|
||||
prod_id = AuraDevice::from(*prod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
impl StdConfig for AuraConfig {
|
||||
fn new() -> Self {
|
||||
// Self::create_default(AuraDevice::X19b6, &LaptopLedData::get_data())
|
||||
panic!("AuraConfig::new() should not be used, use AuraConfig::create_default() instead");
|
||||
}
|
||||
|
||||
if prod_id == AuraDevice::Unknown {
|
||||
if let Ok(p) = KeyboardLed::new() {
|
||||
if p.has_kbd_rgb_mode() {
|
||||
prod_id = AuraDevice::Tuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||
}
|
||||
|
||||
let enabled = if prod_id == AuraDevice::X19B6 {
|
||||
AuraPowerConfig::AuraDev19b6(HashSet::from([
|
||||
AuraDev19b6::BootLogo,
|
||||
AuraDev19b6::BootKeyb,
|
||||
AuraDev19b6::SleepLogo,
|
||||
AuraDev19b6::SleepKeyb,
|
||||
AuraDev19b6::AwakeLogo,
|
||||
AuraDev19b6::AwakeKeyb,
|
||||
AuraDev19b6::ShutdownLogo,
|
||||
AuraDev19b6::ShutdownKeyb,
|
||||
AuraDev19b6::BootBar,
|
||||
AuraDev19b6::AwakeBar,
|
||||
AuraDev19b6::SleepBar,
|
||||
AuraDev19b6::ShutdownBar,
|
||||
fn file_name(&self) -> String {
|
||||
CONFIG_FILE.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for AuraConfig {}
|
||||
|
||||
impl AuraConfig {
|
||||
pub fn create_default(prod_id: AuraDevice, support_data: &LaptopLedData) -> Self {
|
||||
// create a default config here
|
||||
let enabled = if prod_id == AuraDevice::X19b6 {
|
||||
AuraPowerConfig::AuraDevRog2(HashSet::from([
|
||||
AuraDevRog2::BootLogo,
|
||||
AuraDevRog2::BootKeyb,
|
||||
AuraDevRog2::SleepLogo,
|
||||
AuraDevRog2::SleepKeyb,
|
||||
AuraDevRog2::AwakeLogo,
|
||||
AuraDevRog2::AwakeKeyb,
|
||||
AuraDevRog2::ShutdownLogo,
|
||||
AuraDevRog2::ShutdownKeyb,
|
||||
AuraDevRog2::BootBar,
|
||||
AuraDevRog2::AwakeBar,
|
||||
AuraDevRog2::SleepBar,
|
||||
AuraDevRog2::ShutdownBar,
|
||||
]))
|
||||
} else if prod_id == AuraDevice::Tuf {
|
||||
AuraPowerConfig::AuraDevTuf(HashSet::from([
|
||||
@@ -165,76 +165,31 @@ impl Default for AuraConfig {
|
||||
AuraDevTuf::Keyboard,
|
||||
]))
|
||||
} else {
|
||||
AuraPowerConfig::AuraDev1866(HashSet::from([
|
||||
AuraDev1866::Awake,
|
||||
AuraDev1866::Boot,
|
||||
AuraDev1866::Sleep,
|
||||
AuraDev1866::Keyboard,
|
||||
AuraDev1866::Lightbar,
|
||||
AuraPowerConfig::AuraDevRog1(HashSet::from([
|
||||
AuraDevRog1::Awake,
|
||||
AuraDevRog1::Boot,
|
||||
AuraDevRog1::Sleep,
|
||||
AuraDevRog1::Keyboard,
|
||||
AuraDevRog1::Lightbar,
|
||||
]))
|
||||
};
|
||||
|
||||
AuraConfig {
|
||||
let mut config = AuraConfig {
|
||||
brightness: LedBrightness::Med,
|
||||
current_mode: AuraModeNum::Static,
|
||||
builtins: BTreeMap::new(),
|
||||
multizone: None,
|
||||
multizone_on: false,
|
||||
enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
impl AuraConfig {
|
||||
/// `load` will attempt to read the config, and panic if the dir is missing
|
||||
pub fn load(supported_led_modes: &LaptopLedData) -> Self {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&AURA_CONFIG_PATH)
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"The file {} or directory /etc/asusd/ is missing",
|
||||
AURA_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 AuraConfig::create_default(&mut file, supported_led_modes);
|
||||
} else {
|
||||
if let Ok(data) = serde_json::from_str(&buf) {
|
||||
return data;
|
||||
}
|
||||
warn!(
|
||||
"Could not deserialise {}.\nWill rename to {}-old and recreate config",
|
||||
AURA_CONFIG_PATH, AURA_CONFIG_PATH
|
||||
);
|
||||
let cfg_old = AURA_CONFIG_PATH.to_string() + "-old";
|
||||
std::fs::rename(AURA_CONFIG_PATH, cfg_old).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
AURA_CONFIG_PATH, err
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
AuraConfig::create_default(&mut file, supported_led_modes)
|
||||
}
|
||||
|
||||
fn create_default(file: &mut File, support_data: &LaptopLedData) -> Self {
|
||||
// create a default config here
|
||||
let mut config = AuraConfig::default();
|
||||
|
||||
for n in &support_data.standard {
|
||||
for n in &support_data.basic_modes {
|
||||
config
|
||||
.builtins
|
||||
.insert(*n, AuraEffect::default_with_mode(*n));
|
||||
|
||||
if !support_data.multizone.is_empty() {
|
||||
if !support_data.basic_zones.is_empty() {
|
||||
let mut default = vec![];
|
||||
for (i, tmp) in support_data.multizone.iter().enumerate() {
|
||||
for (i, tmp) in support_data.basic_zones.iter().enumerate() {
|
||||
default.push(AuraEffect {
|
||||
mode: *n,
|
||||
zone: *tmp,
|
||||
@@ -242,7 +197,7 @@ impl AuraConfig {
|
||||
colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]),
|
||||
speed: Speed::Med,
|
||||
direction: Direction::Left,
|
||||
})
|
||||
});
|
||||
}
|
||||
if let Some(m) = config.multizone.as_mut() {
|
||||
m.insert(*n, default);
|
||||
@@ -253,68 +208,37 @@ impl AuraConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Should be okay to unwrap this as is since it is a Default
|
||||
let json = serde_json::to_string(&config).unwrap();
|
||||
file.write_all(json.as_bytes())
|
||||
.unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH));
|
||||
config
|
||||
}
|
||||
|
||||
pub fn read(&mut self) {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&AURA_CONFIG_PATH)
|
||||
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_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 {}", AURA_CONFIG_PATH);
|
||||
} else {
|
||||
let x: AuraConfig = serde_json::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH));
|
||||
*self = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = File::create(AURA_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));
|
||||
}
|
||||
|
||||
/// Set the mode data, current mode, and if multizone enabled.
|
||||
///
|
||||
/// Multipurpose, will accept AuraEffect with zones and put in the correct store.
|
||||
/// Multipurpose, will accept `AuraEffect` with zones and put in the correct
|
||||
/// store.
|
||||
pub fn set_builtin(&mut self, effect: AuraEffect) {
|
||||
self.current_mode = effect.mode;
|
||||
match effect.zone() {
|
||||
AuraZone::None => {
|
||||
self.builtins.insert(*effect.mode(), effect);
|
||||
self.multizone_on = false;
|
||||
}
|
||||
_ => {
|
||||
if let Some(multi) = self.multizone.as_mut() {
|
||||
if let Some(fx) = multi.get_mut(effect.mode()) {
|
||||
for fx in fx.iter_mut() {
|
||||
if fx.zone == effect.zone {
|
||||
*fx = effect;
|
||||
return;
|
||||
}
|
||||
if effect.zone() == AuraZone::None {
|
||||
self.builtins.insert(*effect.mode(), effect);
|
||||
self.multizone_on = false;
|
||||
} else {
|
||||
if let Some(multi) = self.multizone.as_mut() {
|
||||
if let Some(fx) = multi.get_mut(effect.mode()) {
|
||||
for fx in fx.iter_mut() {
|
||||
if fx.zone == effect.zone {
|
||||
*fx = effect;
|
||||
return;
|
||||
}
|
||||
fx.push(effect);
|
||||
} else {
|
||||
multi.insert(*effect.mode(), vec![effect]);
|
||||
}
|
||||
fx.push(effect);
|
||||
} else {
|
||||
let mut tmp = BTreeMap::new();
|
||||
tmp.insert(*effect.mode(), vec![effect]);
|
||||
self.multizone = Some(tmp);
|
||||
multi.insert(*effect.mode(), vec![effect]);
|
||||
}
|
||||
self.multizone_on = true;
|
||||
} else {
|
||||
let mut tmp = BTreeMap::new();
|
||||
tmp.insert(*effect.mode(), vec![effect]);
|
||||
self.multizone = Some(tmp);
|
||||
}
|
||||
self.multizone_on = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,33 +252,44 @@ impl AuraConfig {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::AuraConfig;
|
||||
use rog_aura::aura_detection::LaptopLedData;
|
||||
use rog_aura::usb::AuraDevice;
|
||||
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour};
|
||||
|
||||
use super::AuraConfig;
|
||||
|
||||
#[test]
|
||||
fn set_multizone_4key_config() {
|
||||
let mut config = AuraConfig::default();
|
||||
let mut config = AuraConfig::create_default(AuraDevice::X19b6, &LaptopLedData::default());
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.colour1 = Colour(0xff, 0x00, 0xff);
|
||||
effect.zone = AuraZone::Key1;
|
||||
let effect = AuraEffect {
|
||||
colour1: Colour(0xff, 0x00, 0xff),
|
||||
zone: AuraZone::Key1,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
assert!(config.multizone.is_some());
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.colour1 = Colour(0x00, 0xff, 0xff);
|
||||
effect.zone = AuraZone::Key2;
|
||||
let effect = AuraEffect {
|
||||
colour1: Colour(0x00, 0xff, 0xff),
|
||||
zone: AuraZone::Key2,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.colour1 = Colour(0xff, 0xff, 0x00);
|
||||
effect.zone = AuraZone::Key3;
|
||||
let effect = AuraEffect {
|
||||
colour1: Colour(0xff, 0xff, 0x00),
|
||||
zone: AuraZone::Key3,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.colour1 = Colour(0x00, 0xff, 0x00);
|
||||
effect.zone = AuraZone::Key4;
|
||||
let effect = AuraEffect {
|
||||
colour1: Colour(0x00, 0xff, 0x00),
|
||||
zone: AuraZone::Key4,
|
||||
..Default::default()
|
||||
};
|
||||
let effect_clone = effect.clone();
|
||||
config.set_builtin(effect);
|
||||
// This should replace existing
|
||||
@@ -371,27 +306,35 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn set_multizone_multimode_config() {
|
||||
let mut config = AuraConfig::default();
|
||||
let mut config = AuraConfig::create_default(AuraDevice::X19b6, &LaptopLedData::default());
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.zone = AuraZone::Key1;
|
||||
let effect = AuraEffect {
|
||||
zone: AuraZone::Key1,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
assert!(config.multizone.is_some());
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.zone = AuraZone::Key2;
|
||||
effect.mode = AuraModeNum::Breathe;
|
||||
let effect = AuraEffect {
|
||||
zone: AuraZone::Key2,
|
||||
mode: AuraModeNum::Breathe,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.zone = AuraZone::Key3;
|
||||
effect.mode = AuraModeNum::Comet;
|
||||
let effect = AuraEffect {
|
||||
zone: AuraZone::Key3,
|
||||
mode: AuraModeNum::Comet,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.zone = AuraZone::Key4;
|
||||
effect.mode = AuraModeNum::Pulse;
|
||||
let effect = AuraEffect {
|
||||
zone: AuraZone::Key4,
|
||||
mode: AuraModeNum::Pulse,
|
||||
..Default::default()
|
||||
};
|
||||
config.set_builtin(effect);
|
||||
|
||||
let res = config.multizone.unwrap();
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
use crate::{
|
||||
error::RogError,
|
||||
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
||||
CtrlTask,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use log::{error, info, warn};
|
||||
use rog_aura::{
|
||||
usb::{AuraDevice, LED_APPLY, LED_SET},
|
||||
AuraEffect, KeyColourArray, LedBrightness, PerKeyRaw, LED_MSG_LEN,
|
||||
};
|
||||
use rog_aura::{AuraZone, Direction, Speed, GRADIENT};
|
||||
use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions};
|
||||
use smol::Executor;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::MutexGuard;
|
||||
|
||||
use crate::GetSupported;
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use log::{info, warn};
|
||||
use rog_aura::advanced::{LedUsbPackets, UsbPackets};
|
||||
use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES};
|
||||
use rog_aura::usb::{AuraDevice, LED_APPLY, LED_SET};
|
||||
use rog_aura::{AuraEffect, AuraZone, Direction, LedBrightness, Speed, GRADIENT, LED_MSG_LEN};
|
||||
use rog_platform::hid_raw::HidRaw;
|
||||
use rog_platform::keyboard_led::KeyboardLed;
|
||||
use rog_platform::supported::LedSupportedFunctions;
|
||||
|
||||
use super::config::{AuraConfig, AuraPowerConfig};
|
||||
use crate::error::RogError;
|
||||
use crate::GetSupported;
|
||||
|
||||
impl GetSupported for CtrlKbdLed {
|
||||
type A = LedSupportedFunctions;
|
||||
@@ -27,14 +20,14 @@ impl GetSupported for CtrlKbdLed {
|
||||
fn get_supported() -> Self::A {
|
||||
// let mode = <&str>::from(&<AuraModes>::from(*mode));
|
||||
let laptop = LaptopLedData::get_data();
|
||||
let stock_led_modes = laptop.standard;
|
||||
let multizone_led_mode = laptop.multizone;
|
||||
let per_key_led_mode = laptop.per_key;
|
||||
let stock_led_modes = laptop.basic_modes;
|
||||
let multizone_led_mode = laptop.basic_zones;
|
||||
let advanced_type = laptop.advanced_type;
|
||||
|
||||
let mut prod_id = AuraDevice::Unknown;
|
||||
for prod in ASUS_KEYBOARD_DEVICES.iter() {
|
||||
if let Ok(_) = HidRaw::new(prod) {
|
||||
prod_id = AuraDevice::from(*prod);
|
||||
for prod in ASUS_KEYBOARD_DEVICES {
|
||||
if HidRaw::new(prod.into()).is_ok() {
|
||||
prod_id = prod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -47,16 +40,16 @@ impl GetSupported for CtrlKbdLed {
|
||||
}
|
||||
|
||||
LedSupportedFunctions {
|
||||
prod_id,
|
||||
brightness_set: rgb.is_ok(),
|
||||
stock_led_modes,
|
||||
multizone_led_mode,
|
||||
per_key_led_mode,
|
||||
dev_id: prod_id,
|
||||
brightness: rgb.is_ok(),
|
||||
basic_modes: stock_led_modes,
|
||||
basic_zones: multizone_led_mode,
|
||||
advanced_type: advanced_type.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd)]
|
||||
pub enum LEDNode {
|
||||
KbdLed(KeyboardLed),
|
||||
Rog(HidRaw),
|
||||
@@ -65,7 +58,7 @@ pub enum LEDNode {
|
||||
|
||||
pub struct CtrlKbdLed {
|
||||
// TODO: config stores the keyboard type as an AuraPower, use or update this
|
||||
pub led_prod: Option<String>,
|
||||
pub led_prod: AuraDevice,
|
||||
pub led_node: LEDNode,
|
||||
pub kd_brightness: KeyboardLed,
|
||||
pub supported_modes: LaptopLedData,
|
||||
@@ -74,133 +67,44 @@ pub struct CtrlKbdLed {
|
||||
pub config: AuraConfig,
|
||||
}
|
||||
|
||||
pub struct CtrlKbdLedTask {
|
||||
inner: Arc<Mutex<CtrlKbdLed>>,
|
||||
}
|
||||
|
||||
impl CtrlKbdLedTask {
|
||||
pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> {
|
||||
let bright = lock.kd_brightness.get_brightness()?;
|
||||
lock.config.read();
|
||||
lock.config.brightness = (bright as u32).into();
|
||||
lock.config.write();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for CtrlKbdLedTask {
|
||||
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
let load_save = |start: bool, mut lock: MutexGuard<CtrlKbdLed>| {
|
||||
// If waking up
|
||||
if !start {
|
||||
info!("CtrlKbdLedTask reloading brightness and modes");
|
||||
lock.set_brightness(lock.config.brightness)
|
||||
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
|
||||
.ok();
|
||||
lock.write_current_config_mode()
|
||||
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
|
||||
.ok();
|
||||
} else if start {
|
||||
info!("CtrlKbdLedTask saving last brightness");
|
||||
Self::update_config(&mut lock)
|
||||
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
|
||||
.ok();
|
||||
}
|
||||
};
|
||||
|
||||
let inner1 = self.inner.clone();
|
||||
let inner2 = self.inner.clone();
|
||||
let inner3 = self.inner.clone();
|
||||
let inner4 = self.inner.clone();
|
||||
self.create_sys_event_tasks(
|
||||
executor,
|
||||
// Loop so that we do aquire the lock but also don't block other
|
||||
// threads (prevents potential deadlocks)
|
||||
move || loop {
|
||||
if let Ok(lock) = inner1.clone().try_lock() {
|
||||
load_save(true, lock);
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Ok(lock) = inner2.clone().try_lock() {
|
||||
load_save(false, lock);
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Ok(lock) = inner3.clone().try_lock() {
|
||||
load_save(false, lock);
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Ok(lock) = inner4.clone().try_lock() {
|
||||
load_save(false, lock);
|
||||
break;
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlKbdLedReloader(pub Arc<Mutex<CtrlKbdLed>>);
|
||||
|
||||
impl crate::Reloadable for CtrlKbdLedReloader {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||
ctrl.write_current_config_mode()?;
|
||||
ctrl.set_power_states().map_err(|err| warn!("{err}")).ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlKbdLedZbus(pub Arc<Mutex<CtrlKbdLed>>);
|
||||
|
||||
impl CtrlKbdLedZbus {
|
||||
pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlKbdLed {
|
||||
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
|
||||
let mut led_prod = None;
|
||||
let mut led_node = None;
|
||||
for prod in ASUS_KEYBOARD_DEVICES.iter() {
|
||||
match HidRaw::new(prod) {
|
||||
pub fn new(supported_modes: LaptopLedData) -> Result<Self, RogError> {
|
||||
let mut led_prod = AuraDevice::Unknown;
|
||||
let mut usb_node = None;
|
||||
for prod in ASUS_KEYBOARD_DEVICES {
|
||||
match HidRaw::new(prod.into()) {
|
||||
Ok(node) => {
|
||||
led_prod = Some(prod.to_string());
|
||||
led_node = Some(node);
|
||||
info!("Looked for keyboard controller 0x{prod}: Found");
|
||||
led_prod = prod;
|
||||
usb_node = Some(node);
|
||||
info!(
|
||||
"Looked for keyboard controller 0x{}: Found",
|
||||
<&str>::from(prod)
|
||||
);
|
||||
break;
|
||||
}
|
||||
Err(err) => info!("Looked for keyboard controller 0x{prod}: {err}"),
|
||||
Err(err) => info!(
|
||||
"Looked for keyboard controller 0x{}: {err}",
|
||||
<&str>::from(prod)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
let rgb_led = KeyboardLed::new()?;
|
||||
|
||||
if led_node.is_none() && !rgb_led.has_kbd_rgb_mode() {
|
||||
if usb_node.is_none() && !rgb_led.has_kbd_rgb_mode() {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
if let Ok(prod_family) = dmi.product_family() {
|
||||
if prod_family.contains("TUF") {
|
||||
warn!("A kernel patch is in progress for TUF RGB support");
|
||||
warn!(
|
||||
"kbd_rgb_mode was not found in the /sys/. You require a minimum 6.1 \
|
||||
kernel and a supported TUF laptop"
|
||||
);
|
||||
}
|
||||
}
|
||||
return Err(RogError::NoAuraKeyboard);
|
||||
}
|
||||
|
||||
let led_node = if let Some(rog) = led_node {
|
||||
let led_node = if let Some(rog) = usb_node {
|
||||
info!("Found ROG USB keyboard");
|
||||
LEDNode::Rog(rog)
|
||||
} else if rgb_led.has_kbd_rgb_mode() {
|
||||
@@ -210,9 +114,18 @@ impl CtrlKbdLed {
|
||||
LEDNode::None
|
||||
};
|
||||
|
||||
let config_init = AuraConfig::create_default(led_prod, &supported_modes);
|
||||
let mut config = config_init.clone().load();
|
||||
// Do updates of supported modes if required
|
||||
for mode in &config_init.builtins {
|
||||
if !config.builtins.contains_key(mode.0) {
|
||||
config.builtins.insert(*mode.0, mode.1.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let ctrl = CtrlKbdLed {
|
||||
led_prod,
|
||||
led_node,
|
||||
led_node, // on TUF this is the same as rgb_led / kd_brightness
|
||||
kd_brightness: rgb_led, // If was none then we already returned above
|
||||
supported_modes,
|
||||
flip_effect_write: false,
|
||||
@@ -225,13 +138,13 @@ impl CtrlKbdLed {
|
||||
pub(super) fn get_brightness(&self) -> Result<u8, RogError> {
|
||||
self.kd_brightness
|
||||
.get_brightness()
|
||||
.map_err(|e| RogError::Platform(e))
|
||||
.map_err(RogError::Platform)
|
||||
}
|
||||
|
||||
pub(super) fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
|
||||
self.kd_brightness
|
||||
.set_brightness(brightness as u8)
|
||||
.map_err(|e| RogError::Platform(e))
|
||||
.map_err(RogError::Platform)
|
||||
}
|
||||
|
||||
pub fn next_brightness(&mut self) -> Result<(), RogError> {
|
||||
@@ -256,7 +169,8 @@ impl CtrlKbdLed {
|
||||
self.set_brightness(self.config.brightness)
|
||||
}
|
||||
|
||||
/// Set combination state for boot animation/sleep animation/all leds/keys leds/side leds LED active
|
||||
/// Set combination state for boot animation/sleep animation/all leds/keys
|
||||
/// leds/side leds LED active
|
||||
pub(super) fn set_power_states(&mut self) -> Result<(), RogError> {
|
||||
if let LEDNode::KbdLed(platform) = &mut self.led_node {
|
||||
if let Some(pwr) = AuraPowerConfig::to_tuf_bool_array(&self.config.enabled) {
|
||||
@@ -277,13 +191,12 @@ impl CtrlKbdLed {
|
||||
|
||||
/// Set an Aura effect if the effect mode or zone is supported.
|
||||
///
|
||||
/// On success the aura config file is read to refresh cached values, then the effect is
|
||||
/// stored and config written to disk.
|
||||
/// On success the aura config file is read to refresh cached values, then
|
||||
/// the effect is stored and config written to disk.
|
||||
pub(crate) fn set_effect(&mut self, effect: AuraEffect) -> Result<(), RogError> {
|
||||
if !self.supported_modes.standard.contains(&effect.mode) {
|
||||
return Err(RogError::AuraEffectNotSupported);
|
||||
} else if effect.zone != AuraZone::None
|
||||
&& !self.supported_modes.multizone.contains(&effect.zone)
|
||||
if !self.supported_modes.basic_modes.contains(&effect.mode)
|
||||
|| effect.zone != AuraZone::None
|
||||
&& !self.supported_modes.basic_zones.contains(&effect.zone)
|
||||
{
|
||||
return Err(RogError::AuraEffectNotSupported);
|
||||
}
|
||||
@@ -298,7 +211,7 @@ impl CtrlKbdLed {
|
||||
/// Write an effect block. This is for per-key, but can be repurposed to
|
||||
/// write the raw factory mode packets - when doing this it is expected that
|
||||
/// only the first `Vec` (`effect[0]`) is valid.
|
||||
pub fn write_effect_block(&mut self, effect: &PerKeyRaw) -> Result<(), RogError> {
|
||||
pub fn write_effect_block(&mut self, effect: &UsbPackets) -> Result<(), RogError> {
|
||||
let pkt_type = effect[0][1];
|
||||
const PER_KEY_TYPE: u8 = 0xbc;
|
||||
|
||||
@@ -312,7 +225,7 @@ impl CtrlKbdLed {
|
||||
} else {
|
||||
if !self.per_key_mode_active {
|
||||
if let LEDNode::Rog(hid_raw) = &self.led_node {
|
||||
let init = KeyColourArray::get_init_msg();
|
||||
let init = LedUsbPackets::get_init_msg();
|
||||
hid_raw.write_bytes(&init)?;
|
||||
}
|
||||
self.per_key_mode_active = true;
|
||||
@@ -338,7 +251,7 @@ impl CtrlKbdLed {
|
||||
let current = self.config.current_mode;
|
||||
if let Some(idx) = self
|
||||
.supported_modes
|
||||
.standard
|
||||
.basic_modes
|
||||
.iter()
|
||||
.position(|v| *v == current)
|
||||
{
|
||||
@@ -346,17 +259,17 @@ impl CtrlKbdLed {
|
||||
// goes past end of array
|
||||
if reverse {
|
||||
if idx == 0 {
|
||||
idx = self.supported_modes.standard.len() - 1;
|
||||
idx = self.supported_modes.basic_modes.len() - 1;
|
||||
} else {
|
||||
idx -= 1;
|
||||
}
|
||||
} else {
|
||||
idx += 1;
|
||||
if idx == self.supported_modes.standard.len() {
|
||||
if idx == self.supported_modes.basic_modes.len() {
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
let next = self.supported_modes.standard[idx];
|
||||
let next = self.supported_modes.basic_modes[idx];
|
||||
|
||||
self.config.read();
|
||||
// if self.config.builtins.contains_key(&next) {
|
||||
@@ -393,7 +306,7 @@ impl CtrlKbdLed {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_current_config_mode(&mut self) -> Result<(), RogError> {
|
||||
pub(super) fn write_current_config_mode(&mut self) -> Result<(), RogError> {
|
||||
if self.config.multizone_on {
|
||||
let mode = self.config.current_mode;
|
||||
let mut create = false;
|
||||
@@ -429,10 +342,11 @@ impl CtrlKbdLed {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a default for the `current_mode` if multizone and no config exists.
|
||||
/// Create a default for the `current_mode` if multizone and no config
|
||||
/// exists.
|
||||
fn create_multizone_default(&mut self) -> Result<(), RogError> {
|
||||
let mut default = vec![];
|
||||
for (i, tmp) in self.supported_modes.multizone.iter().enumerate() {
|
||||
for (i, tmp) in self.supported_modes.basic_zones.iter().enumerate() {
|
||||
default.push(AuraEffect {
|
||||
mode: self.config.current_mode,
|
||||
zone: *tmp,
|
||||
@@ -440,7 +354,7 @@ impl CtrlKbdLed {
|
||||
colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]),
|
||||
speed: Speed::Med,
|
||||
direction: Direction::Left,
|
||||
})
|
||||
});
|
||||
}
|
||||
if default.is_empty() {
|
||||
return Err(RogError::AuraEffectNotSupported);
|
||||
@@ -459,30 +373,29 @@ impl CtrlKbdLed {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rog_aura::aura_detection::LaptopLedData;
|
||||
use rog_aura::usb::AuraDevice;
|
||||
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour};
|
||||
use rog_platform::keyboard_led::KeyboardLed;
|
||||
|
||||
use crate::{
|
||||
ctrl_aura::{config::AuraConfig, controller::LEDNode},
|
||||
laptops::LaptopLedData,
|
||||
};
|
||||
|
||||
use super::CtrlKbdLed;
|
||||
use crate::ctrl_aura::config::AuraConfig;
|
||||
use crate::ctrl_aura::controller::LEDNode;
|
||||
|
||||
#[test]
|
||||
// #[ignore = "Must be manually run due to detection stage"]
|
||||
fn check_set_mode_errors() {
|
||||
// Checking to ensure set_mode errors when unsupported modes are tried
|
||||
let config = AuraConfig::default();
|
||||
let config = AuraConfig::create_default(AuraDevice::X19b6, &LaptopLedData::default());
|
||||
let supported_modes = LaptopLedData {
|
||||
prod_family: "".into(),
|
||||
board_names: vec![],
|
||||
standard: vec![AuraModeNum::Static],
|
||||
multizone: vec![],
|
||||
per_key: false,
|
||||
board_name: String::new(),
|
||||
layout_name: "ga401".to_owned(),
|
||||
basic_modes: vec![AuraModeNum::Static],
|
||||
basic_zones: vec![],
|
||||
advanced_type: rog_aura::AdvancedAuraType::None,
|
||||
};
|
||||
let mut controller = CtrlKbdLed {
|
||||
led_prod: None,
|
||||
led_prod: AuraDevice::X19b6,
|
||||
led_node: LEDNode::None,
|
||||
kd_brightness: KeyboardLed::default(),
|
||||
supported_modes,
|
||||
@@ -491,11 +404,14 @@ mod tests {
|
||||
config,
|
||||
};
|
||||
|
||||
let mut effect = AuraEffect::default();
|
||||
effect.colour1 = Colour(0xff, 0x00, 0xff);
|
||||
effect.zone = AuraZone::None;
|
||||
let mut effect = AuraEffect {
|
||||
colour1: Colour(0xff, 0x00, 0xff),
|
||||
zone: AuraZone::None,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// This error comes from write_bytes because we don't have a keyboard node stored
|
||||
// This error comes from write_bytes because we don't have a keyboard node
|
||||
// stored
|
||||
assert_eq!(
|
||||
controller
|
||||
.set_effect(effect.clone())
|
||||
@@ -523,12 +439,9 @@ mod tests {
|
||||
"Aura effect not supported"
|
||||
);
|
||||
|
||||
controller.supported_modes.multizone.push(AuraZone::Key2);
|
||||
controller.supported_modes.basic_zones.push(AuraZone::Key2);
|
||||
assert_eq!(
|
||||
controller
|
||||
.set_effect(effect.clone())
|
||||
.unwrap_err()
|
||||
.to_string(),
|
||||
controller.set_effect(effect).unwrap_err().to_string(),
|
||||
"No supported Aura keyboard"
|
||||
);
|
||||
}
|
||||
@@ -536,16 +449,16 @@ mod tests {
|
||||
#[test]
|
||||
fn create_multizone_if_no_config() {
|
||||
// Checking to ensure set_mode errors when unsupported modes are tried
|
||||
let config = AuraConfig::default();
|
||||
let config = AuraConfig::create_default(AuraDevice::X19b6, &LaptopLedData::default());
|
||||
let supported_modes = LaptopLedData {
|
||||
prod_family: "".into(),
|
||||
board_names: vec![],
|
||||
standard: vec![AuraModeNum::Static],
|
||||
multizone: vec![],
|
||||
per_key: false,
|
||||
board_name: String::new(),
|
||||
layout_name: "ga401".to_owned(),
|
||||
basic_modes: vec![AuraModeNum::Static],
|
||||
basic_zones: vec![],
|
||||
advanced_type: rog_aura::AdvancedAuraType::None,
|
||||
};
|
||||
let mut controller = CtrlKbdLed {
|
||||
led_prod: None,
|
||||
led_prod: AuraDevice::X19b6,
|
||||
led_node: LEDNode::None,
|
||||
kd_brightness: KeyboardLed::default(),
|
||||
supported_modes,
|
||||
@@ -558,8 +471,8 @@ mod tests {
|
||||
assert!(controller.create_multizone_default().is_err());
|
||||
assert!(controller.config.multizone.is_none());
|
||||
|
||||
controller.supported_modes.multizone.push(AuraZone::Key1);
|
||||
controller.supported_modes.multizone.push(AuraZone::Key2);
|
||||
controller.supported_modes.basic_zones.push(AuraZone::Key1);
|
||||
controller.supported_modes.basic_zones.push(AuraZone::Key2);
|
||||
assert!(controller.create_multizone_default().is_ok());
|
||||
assert!(controller.config.multizone.is_some());
|
||||
|
||||
@@ -574,16 +487,16 @@ mod tests {
|
||||
#[test]
|
||||
fn next_mode_create_multizone_if_no_config() {
|
||||
// Checking to ensure set_mode errors when unsupported modes are tried
|
||||
let config = AuraConfig::default();
|
||||
let config = AuraConfig::create_default(AuraDevice::X19b6, &LaptopLedData::default());
|
||||
let supported_modes = LaptopLedData {
|
||||
prod_family: "".into(),
|
||||
board_names: vec![],
|
||||
standard: vec![AuraModeNum::Static],
|
||||
multizone: vec![AuraZone::Key1, AuraZone::Key2],
|
||||
per_key: false,
|
||||
board_name: String::new(),
|
||||
layout_name: "ga401".to_owned(),
|
||||
basic_modes: vec![AuraModeNum::Static],
|
||||
basic_zones: vec![AuraZone::Key1, AuraZone::Key2],
|
||||
advanced_type: rog_aura::AdvancedAuraType::None,
|
||||
};
|
||||
let mut controller = CtrlKbdLed {
|
||||
led_prod: None,
|
||||
led_prod: AuraDevice::X19b6,
|
||||
led_node: LEDNode::None,
|
||||
kd_brightness: KeyboardLed::default(),
|
||||
supported_modes,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod config;
|
||||
pub mod controller;
|
||||
pub mod zbus;
|
||||
/// Implements `CtrlTask`, `Reloadable`, `ZbusRun`
|
||||
pub mod trait_impls;
|
||||
|
||||
327
daemon/src/ctrl_aura/trait_impls.rs
Normal file
@@ -0,0 +1,327 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use config_traits::StdConfig;
|
||||
use log::{error, info, warn};
|
||||
use rog_aura::advanced::UsbPackets;
|
||||
use rog_aura::usb::AuraPowerDev;
|
||||
use rog_aura::{AuraEffect, AuraModeNum, LedBrightness};
|
||||
use zbus::export::futures_util::lock::{Mutex, MutexGuard};
|
||||
use zbus::export::futures_util::StreamExt;
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use super::controller::CtrlKbdLed;
|
||||
use crate::error::RogError;
|
||||
use crate::CtrlTask;
|
||||
|
||||
pub(super) const ZBUS_PATH: &str = "/org/asuslinux/Aura";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlKbdLedZbus(pub Arc<Mutex<CtrlKbdLed>>);
|
||||
|
||||
impl CtrlKbdLedZbus {
|
||||
fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> {
|
||||
let bright = lock.kd_brightness.get_brightness()?;
|
||||
lock.config.read();
|
||||
lock.config.brightness = (bright as u32).into();
|
||||
lock.config.write();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusRun for CtrlKbdLedZbus {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, ZBUS_PATH, server).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// The main interface for changing, reading, or notfying signals
|
||||
///
|
||||
/// LED commands are split between Brightness, Modes, Per-Key
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlKbdLedZbus {
|
||||
/// Set the keyboard brightness level (0-3)
|
||||
async fn set_brightness(&mut self, brightness: LedBrightness) {
|
||||
let ctrl = self.0.lock().await;
|
||||
ctrl.set_brightness(brightness)
|
||||
.map_err(|err| warn!("{}", err))
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// Set a variety of states, input is array of enum.
|
||||
/// `enabled` sets if the sent array should be disabled or enabled
|
||||
///
|
||||
/// ```text
|
||||
/// pub struct AuraPowerDev {
|
||||
/// pub x1866: Vec<AuraDev1866>,
|
||||
/// pub x19b6: Vec<AuraDev19b6>,
|
||||
/// }
|
||||
/// pub enum AuraDev1866 {
|
||||
/// Awake,
|
||||
/// Keyboard,
|
||||
/// Lightbar,
|
||||
/// Boot,
|
||||
/// Sleep,
|
||||
/// }
|
||||
/// enum AuraDev19b6 {
|
||||
/// BootLogo,
|
||||
/// BootKeyb,
|
||||
/// AwakeLogo,
|
||||
/// AwakeKeyb,
|
||||
/// SleepLogo,
|
||||
/// SleepKeyb,
|
||||
/// ShutdownLogo,
|
||||
/// ShutdownKeyb,
|
||||
/// AwakeBar,
|
||||
/// BootBar,
|
||||
/// SleepBar,
|
||||
/// ShutdownBar,
|
||||
/// }
|
||||
/// ```
|
||||
async fn set_leds_power(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
options: AuraPowerDev,
|
||||
enabled: bool,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
for p in options.tuf {
|
||||
ctrl.config.enabled.set_tuf(p, enabled);
|
||||
}
|
||||
for p in options.x1866 {
|
||||
ctrl.config.enabled.set_0x1866(p, enabled);
|
||||
}
|
||||
for p in options.x19b6 {
|
||||
ctrl.config.enabled.set_0x19b6(p, enabled);
|
||||
}
|
||||
|
||||
ctrl.config.write();
|
||||
|
||||
ctrl.set_power_states().map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
Self::notify_power_states(&ctxt, &AuraPowerDev::from(&ctrl.config.enabled))
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_led_mode(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
effect: AuraEffect,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
|
||||
ctrl.set_effect(effect).map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
Self::notify_led(&ctxt, mode.clone())
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_led_mode(
|
||||
&self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
|
||||
ctrl.toggle_mode(false).map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
Self::notify_led(&ctxt, mode.clone())
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn prev_led_mode(
|
||||
&self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
|
||||
ctrl.toggle_mode(true).map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
Self::notify_led(&ctxt, mode.clone())
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_led_brightness(&self) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.next_brightness().map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn prev_led_brightness(&self) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.prev_brightness().map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// As property doesn't work for AuraPowerDev (complexity of serialization?)
|
||||
// #[dbus_interface(property)]
|
||||
async fn leds_enabled(&self) -> AuraPowerDev {
|
||||
let ctrl = self.0.lock().await;
|
||||
AuraPowerDev::from(&ctrl.config.enabled)
|
||||
}
|
||||
|
||||
/// Return the current mode data
|
||||
async fn led_mode(&self) -> AuraModeNum {
|
||||
let ctrl = self.0.lock().await;
|
||||
ctrl.config.current_mode
|
||||
}
|
||||
|
||||
/// Return a list of available modes
|
||||
async fn led_modes(&self) -> BTreeMap<AuraModeNum, AuraEffect> {
|
||||
let ctrl = self.0.lock().await;
|
||||
ctrl.config.builtins.clone()
|
||||
}
|
||||
|
||||
/// On machine that have some form of either per-key keyboard or per-zone
|
||||
/// this can be used to write custom effects over dbus. The input is a
|
||||
/// nested `Vec<Vec<8>>` where `Vec<u8>` is a raw USB packet
|
||||
async fn direct_addressing_raw(&self, data: UsbPackets) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.write_effect_block(&data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the current LED brightness
|
||||
#[dbus_interface(property)]
|
||||
async fn led_brightness(&self) -> i8 {
|
||||
let ctrl = self.0.lock().await;
|
||||
ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1)
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_led(signal_ctxt: &SignalContext<'_>, data: AuraEffect) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_power_states(
|
||||
signal_ctxt: &SignalContext<'_>,
|
||||
data: &AuraPowerDev,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for CtrlKbdLedZbus {
|
||||
fn zbus_path() -> &'static str {
|
||||
ZBUS_PATH
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let load_save = |start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| {
|
||||
// If waking up
|
||||
if !start {
|
||||
info!("CtrlKbdLedTask reloading brightness and modes");
|
||||
lock.set_brightness(lock.config.brightness)
|
||||
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
|
||||
.ok();
|
||||
lock.write_current_config_mode()
|
||||
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
|
||||
.ok();
|
||||
} else if start {
|
||||
info!("CtrlKbdLedTask saving last brightness");
|
||||
Self::update_config(&mut lock)
|
||||
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
|
||||
.ok();
|
||||
}
|
||||
};
|
||||
|
||||
let inner1 = self.0.clone();
|
||||
let inner2 = self.0.clone();
|
||||
let inner3 = self.0.clone();
|
||||
let inner4 = self.0.clone();
|
||||
self.create_sys_event_tasks(
|
||||
// Loop so that we do aquire the lock but also don't block other
|
||||
// threads (prevents potential deadlocks)
|
||||
move || {
|
||||
let inner1 = inner1.clone();
|
||||
async move {
|
||||
let lock = inner1.lock().await;
|
||||
load_save(true, lock);
|
||||
}
|
||||
},
|
||||
move || {
|
||||
let inner2 = inner2.clone();
|
||||
async move {
|
||||
let lock = inner2.lock().await;
|
||||
load_save(false, lock);
|
||||
}
|
||||
},
|
||||
move || {
|
||||
let inner3 = inner3.clone();
|
||||
async move {
|
||||
let lock = inner3.lock().await;
|
||||
load_save(false, lock);
|
||||
}
|
||||
},
|
||||
move || {
|
||||
let inner4 = inner4.clone();
|
||||
async move {
|
||||
let lock = inner4.lock().await;
|
||||
load_save(false, lock);
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
let ctrl2 = self.0.clone();
|
||||
let ctrl = self.0.lock().await;
|
||||
let mut watch = ctrl.kd_brightness.monitor_brightness()?;
|
||||
tokio::spawn(async move {
|
||||
let mut buffer = [0; 32];
|
||||
watch
|
||||
.event_stream(&mut buffer)
|
||||
.unwrap()
|
||||
.for_each(|_| async {
|
||||
if let Some(lock) = ctrl2.try_lock() {
|
||||
load_save(true, lock);
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Reloadable for CtrlKbdLedZbus {
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.write_current_config_mode()?;
|
||||
ctrl.set_power_states().map_err(|err| warn!("{err}")).ok();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::warn;
|
||||
use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw};
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use super::controller::CtrlKbdLedZbus;
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusAdd for CtrlKbdLedZbus {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, "/org/asuslinux/Aura", server).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// The main interface for changing, reading, or notfying signals
|
||||
///
|
||||
/// LED commands are split between Brightness, Modes, Per-Key
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlKbdLedZbus {
|
||||
/// Set the keyboard brightness level (0-3)
|
||||
async fn set_brightness(&mut self, brightness: LedBrightness) {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
ctrl.set_brightness(brightness)
|
||||
.map_err(|err| warn!("{}", err))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a variety of states, input is array of enum.
|
||||
/// `enabled` sets if the sent array should be disabled or enabled
|
||||
///
|
||||
/// ```text
|
||||
/// pub struct AuraPowerDev {
|
||||
/// pub x1866: Vec<AuraDev1866>,
|
||||
/// pub x19b6: Vec<AuraDev19b6>,
|
||||
/// }
|
||||
/// pub enum AuraDev1866 {
|
||||
/// Awake,
|
||||
/// Keyboard,
|
||||
/// Lightbar,
|
||||
/// Boot,
|
||||
/// Sleep,
|
||||
/// }
|
||||
/// enum AuraDev19b6 {
|
||||
/// BootLogo,
|
||||
/// BootKeyb,
|
||||
/// AwakeLogo,
|
||||
/// AwakeKeyb,
|
||||
/// SleepLogo,
|
||||
/// SleepKeyb,
|
||||
/// ShutdownLogo,
|
||||
/// ShutdownKeyb,
|
||||
/// AwakeBar,
|
||||
/// BootBar,
|
||||
/// SleepBar,
|
||||
/// ShutdownBar,
|
||||
/// }
|
||||
/// ```
|
||||
async fn set_leds_power(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
options: AuraPowerDev,
|
||||
enabled: bool,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut states = None;
|
||||
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||
for p in options.tuf {
|
||||
ctrl.config.enabled.set_tuf(p, enabled);
|
||||
}
|
||||
for p in options.x1866 {
|
||||
ctrl.config.enabled.set_0x1866(p, enabled);
|
||||
}
|
||||
for p in options.x19b6 {
|
||||
ctrl.config.enabled.set_0x19b6(p, enabled);
|
||||
}
|
||||
|
||||
ctrl.config.write();
|
||||
|
||||
ctrl.set_power_states().map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
states = Some(AuraPowerDev::from(&ctrl.config.enabled));
|
||||
}
|
||||
// Need to pull state out like this due to MutexGuard
|
||||
if let Some(states) = states {
|
||||
Self::notify_power_states(&ctxt, &states)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_led_mode(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
effect: AuraEffect,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut led = None;
|
||||
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||
ctrl.set_effect(effect).map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
led = Some(mode.clone());
|
||||
}
|
||||
}
|
||||
if let Some(led) = led {
|
||||
Self::notify_led(&ctxt, led)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_led_mode(
|
||||
&self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut led = None;
|
||||
if let Ok(mut ctrl) = self.0.lock() {
|
||||
ctrl.toggle_mode(false).map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
led = Some(mode.clone());
|
||||
}
|
||||
}
|
||||
if let Some(led) = led {
|
||||
Self::notify_led(&ctxt, led)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn prev_led_mode(
|
||||
&self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut led = None;
|
||||
if let Ok(mut ctrl) = self.0.lock() {
|
||||
ctrl.toggle_mode(true).map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
led = Some(mode.clone());
|
||||
}
|
||||
}
|
||||
if let Some(led) = led {
|
||||
Self::notify_led(&ctxt, led)
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_led_brightness(&self) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||
ctrl.next_brightness().map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn prev_led_brightness(&self) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||
ctrl.prev_brightness().map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// As property doesn't work for AuraPowerDev (complexity of serialization?)
|
||||
// #[dbus_interface(property)]
|
||||
async fn leds_enabled(&self) -> AuraPowerDev {
|
||||
loop {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
return AuraPowerDev::from(&ctrl.config.enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current mode data
|
||||
async fn led_mode(&self) -> AuraModeNum {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
return ctrl.config.current_mode;
|
||||
}
|
||||
AuraModeNum::Static
|
||||
}
|
||||
|
||||
/// Return a list of available modes
|
||||
async fn led_modes(&self) -> BTreeMap<AuraModeNum, AuraEffect> {
|
||||
loop {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
return ctrl.config.builtins.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||
ctrl.write_effect_block(&data)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the current LED brightness
|
||||
#[dbus_interface(property)]
|
||||
async fn led_brightness(&self) -> i8 {
|
||||
if let Ok(ctrl) = self.0.try_lock() {
|
||||
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
|
||||
}
|
||||
warn!("SetKeyBacklight could not serialise");
|
||||
-1
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_led(signal_ctxt: &SignalContext<'_>, data: AuraEffect) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_power_states(
|
||||
signal_ctxt: &SignalContext<'_>,
|
||||
data: &AuraPowerDev,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
@@ -1,29 +1,32 @@
|
||||
use crate::CtrlTask;
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
use async_trait::async_trait;
|
||||
use log::{info, warn};
|
||||
use rog_platform::platform::{AsusPlatform, GpuMode};
|
||||
use rog_platform::supported::RogBiosSupportedFunctions;
|
||||
use smol::Executor;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::Connection;
|
||||
use zbus::{dbus_interface, SignalContext};
|
||||
|
||||
static ASUS_POST_LOGO_SOUND: &str =
|
||||
use async_trait::async_trait;
|
||||
use config_traits::StdConfig;
|
||||
use log::{info, warn};
|
||||
use rog_platform::platform::{AsusPlatform, GpuMode};
|
||||
use rog_platform::supported::RogBiosSupportedFunctions;
|
||||
use zbus::export::futures_util::lock::Mutex;
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::RogError;
|
||||
use crate::{task_watch_item, CtrlTask, GetSupported};
|
||||
|
||||
const ZBUS_PATH: &str = "/org/asuslinux/Platform";
|
||||
const ASUS_POST_LOGO_SOUND: &str =
|
||||
"/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlRogBios {
|
||||
pub struct CtrlPlatform {
|
||||
platform: AsusPlatform,
|
||||
config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlRogBios {
|
||||
impl GetSupported for CtrlPlatform {
|
||||
type A = RogBiosSupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
@@ -49,7 +52,7 @@ impl GetSupported for CtrlRogBios {
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlRogBios {
|
||||
impl CtrlPlatform {
|
||||
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||
let platform = AsusPlatform::new()?;
|
||||
|
||||
@@ -59,12 +62,12 @@ impl CtrlRogBios {
|
||||
}
|
||||
|
||||
if Path::new(ASUS_POST_LOGO_SOUND).exists() {
|
||||
CtrlRogBios::set_path_mutable(ASUS_POST_LOGO_SOUND)?;
|
||||
CtrlPlatform::set_path_mutable(ASUS_POST_LOGO_SOUND)?;
|
||||
} else {
|
||||
info!("Switch for POST boot sound not detected");
|
||||
}
|
||||
|
||||
Ok(CtrlRogBios { platform, config })
|
||||
Ok(CtrlPlatform { platform, config })
|
||||
}
|
||||
|
||||
fn set_path_mutable(path: &str) -> Result<(), RogError> {
|
||||
@@ -78,7 +81,7 @@ impl CtrlRogBios {
|
||||
}
|
||||
|
||||
fn set_gfx_mode(&self, mode: GpuMode) -> Result<(), RogError> {
|
||||
self.platform.set_gpu_mux_mode(mode.to_mux())?;
|
||||
self.platform.set_gpu_mux_mode(mode.to_mux_attr())?;
|
||||
// self.update_initramfs(enable)?;
|
||||
if mode == GpuMode::Discrete {
|
||||
info!("Set system-level graphics mode: Dedicated Nvidia");
|
||||
@@ -89,15 +92,8 @@ impl CtrlRogBios {
|
||||
}
|
||||
|
||||
pub fn get_boot_sound() -> Result<i8, RogError> {
|
||||
let path = ASUS_POST_LOGO_SOUND;
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(path)
|
||||
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||
|
||||
let mut data = Vec::new();
|
||||
file.read_to_end(&mut data)
|
||||
.map_err(|err| RogError::Read(path.into(), err))?;
|
||||
let data = std::fs::read(ASUS_POST_LOGO_SOUND)
|
||||
.map_err(|err| RogError::Read(ASUS_POST_LOGO_SOUND.into(), err))?;
|
||||
|
||||
let idx = data.len() - 1;
|
||||
Ok(data[idx] as i8)
|
||||
@@ -112,6 +108,7 @@ impl CtrlRogBios {
|
||||
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||
|
||||
let mut data = Vec::new();
|
||||
#[allow(clippy::verbose_file_reads)]
|
||||
file.read_to_end(&mut data)
|
||||
.map_err(|err| RogError::Read(path.into(), err))?;
|
||||
|
||||
@@ -129,7 +126,7 @@ impl CtrlRogBios {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_panel_od(&self, enable: bool) -> Result<(), RogError> {
|
||||
fn set_panel_overdrive(&self, enable: bool) -> Result<(), RogError> {
|
||||
self.platform.set_panel_od(enable).map_err(|err| {
|
||||
warn!("CtrlRogBios: set_panel_overdrive {}", err);
|
||||
err
|
||||
@@ -139,7 +136,7 @@ impl CtrlRogBios {
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlRogBios {
|
||||
impl CtrlPlatform {
|
||||
async fn set_gpu_mux_mode(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
@@ -147,7 +144,7 @@ impl CtrlRogBios {
|
||||
) {
|
||||
self.set_gfx_mode(mode)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err);
|
||||
warn!("CtrlRogBios: set_gpu_mux_mode {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
@@ -156,7 +153,7 @@ impl CtrlRogBios {
|
||||
|
||||
fn gpu_mux_mode(&self) -> GpuMode {
|
||||
match self.platform.get_gpu_mux_mode() {
|
||||
Ok(m) => GpuMode::from_mux(m),
|
||||
Ok(m) => GpuMode::from_mux(m as u8),
|
||||
Err(e) => {
|
||||
warn!("CtrlRogBios: get_gfx_mode {}", e);
|
||||
GpuMode::Error
|
||||
@@ -197,80 +194,154 @@ impl CtrlRogBios {
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_post_boot_sound(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()> {}
|
||||
|
||||
async fn set_panel_overdrive(
|
||||
async fn set_panel_od(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
overdrive: bool,
|
||||
) {
|
||||
if self
|
||||
.set_panel_od(overdrive)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlRogBios: set_panel_overdrive {}", err);
|
||||
err
|
||||
})
|
||||
.is_ok()
|
||||
{
|
||||
if let Ok(mut lock) = self.config.try_lock() {
|
||||
lock.panel_od = overdrive;
|
||||
lock.write();
|
||||
match self.platform.set_panel_od(overdrive) {
|
||||
Ok(_) => {
|
||||
if let Some(mut lock) = self.config.try_lock() {
|
||||
lock.panel_od = overdrive;
|
||||
lock.write();
|
||||
}
|
||||
Self::notify_panel_od(&ctxt, overdrive).await.ok();
|
||||
}
|
||||
Self::notify_panel_overdrive(&ctxt, overdrive).await.ok();
|
||||
}
|
||||
Err(err) => warn!("CtrlRogBios: set_panel_overdrive {}", err),
|
||||
};
|
||||
}
|
||||
|
||||
fn panel_overdrive(&self) -> bool {
|
||||
self.platform
|
||||
/// Get the `panel_od` value from platform. Updates the stored value in
|
||||
/// internal config also.
|
||||
fn panel_od(&self) -> bool {
|
||||
let od = self
|
||||
.platform
|
||||
.get_panel_od()
|
||||
.map_err(|err| {
|
||||
warn!("CtrlRogBios: get panel overdrive {}", err);
|
||||
warn!("CtrlRogBios: get_panel_od {}", err);
|
||||
err
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if let Some(mut lock) = self.config.try_lock() {
|
||||
lock.panel_od = od;
|
||||
lock.write();
|
||||
}
|
||||
od
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_panel_od(signal_ctxt: &SignalContext<'_>, overdrive: bool) -> zbus::Result<()> {
|
||||
}
|
||||
|
||||
async fn set_dgpu_disable(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
disable: bool,
|
||||
) {
|
||||
match self.platform.set_dgpu_disable(disable) {
|
||||
Ok(_) => {
|
||||
Self::notify_dgpu_disable(&ctxt, disable).await.ok();
|
||||
}
|
||||
Err(err) => warn!("CtrlRogBios: set_dgpu_disable {}", err),
|
||||
};
|
||||
}
|
||||
|
||||
fn dgpu_disable(&self) -> bool {
|
||||
self.platform
|
||||
.get_dgpu_disable()
|
||||
.map_err(|err| {
|
||||
warn!("CtrlRogBios: get_dgpu_disable {}", err);
|
||||
err
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_panel_overdrive(
|
||||
async fn notify_dgpu_disable(
|
||||
signal_ctxt: &SignalContext<'_>,
|
||||
overdrive: bool,
|
||||
disable: bool,
|
||||
) -> zbus::Result<()> {
|
||||
}
|
||||
|
||||
async fn set_egpu_enable(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
enable: bool,
|
||||
) {
|
||||
match self.platform.set_egpu_enable(enable) {
|
||||
Ok(_) => {
|
||||
Self::notify_egpu_enable(&ctxt, enable).await.ok();
|
||||
}
|
||||
Err(err) => warn!("CtrlRogBios: set_egpu_enable {}", err),
|
||||
};
|
||||
}
|
||||
|
||||
fn egpu_enable(&self) -> bool {
|
||||
self.platform
|
||||
.get_egpu_enable()
|
||||
.map_err(|err| {
|
||||
warn!("CtrlRogBios: get_egpu_enable {}", err);
|
||||
err
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_egpu_enable(signal_ctxt: &SignalContext<'_>, enable: bool) -> zbus::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusAdd for CtrlRogBios {
|
||||
impl crate::ZbusRun for CtrlPlatform {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, "/org/asuslinux/Platform", server).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Reloadable for CtrlRogBios {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
#[async_trait]
|
||||
impl crate::Reloadable for CtrlPlatform {
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
if self.platform.has_panel_od() {
|
||||
let p = if let Ok(lock) = self.config.try_lock() {
|
||||
let p = if let Some(lock) = self.config.try_lock() {
|
||||
lock.panel_od
|
||||
} else {
|
||||
false
|
||||
};
|
||||
self.set_panel_od(p)?;
|
||||
self.set_panel_overdrive(p)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlPlatform {
|
||||
task_watch_item!(panel_od platform);
|
||||
|
||||
task_watch_item!(dgpu_disable platform);
|
||||
|
||||
task_watch_item!(egpu_enable platform);
|
||||
// NOTE: see note further below
|
||||
// task_watch_item!(gpu_mux_mode platform);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for CtrlRogBios {
|
||||
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
impl CtrlTask for CtrlPlatform {
|
||||
fn zbus_path() -> &'static str {
|
||||
ZBUS_PATH
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let platform1 = self.clone();
|
||||
let platform2 = self.clone();
|
||||
self.create_sys_event_tasks(
|
||||
executor,
|
||||
move || {},
|
||||
move || async { {} },
|
||||
move || {
|
||||
info!("CtrlRogBios reloading panel_od");
|
||||
if let Ok(lock) = platform1.config.try_lock() {
|
||||
let platform1 = platform1.clone();
|
||||
async move {
|
||||
info!("CtrlRogBios reloading panel_od");
|
||||
let lock = platform1.config.lock().await;
|
||||
if platform1.platform.has_panel_od() {
|
||||
platform1
|
||||
.set_panel_od(lock.panel_od)
|
||||
.set_panel_overdrive(lock.panel_od)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
@@ -279,13 +350,15 @@ impl CtrlTask for CtrlRogBios {
|
||||
}
|
||||
}
|
||||
},
|
||||
move || {},
|
||||
move || async { {} },
|
||||
move || {
|
||||
info!("CtrlRogBios reloading panel_od");
|
||||
if let Ok(lock) = platform2.config.try_lock() {
|
||||
let platform2 = platform2.clone();
|
||||
async move {
|
||||
info!("CtrlRogBios reloading panel_od");
|
||||
let lock = platform2.config.lock().await;
|
||||
if platform2.platform.has_panel_od() {
|
||||
platform2
|
||||
.set_panel_od(lock.panel_od)
|
||||
.set_panel_overdrive(lock.panel_od)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
@@ -297,6 +370,13 @@ impl CtrlTask for CtrlRogBios {
|
||||
)
|
||||
.await;
|
||||
|
||||
self.watch_panel_od(signal_ctxt.clone()).await?;
|
||||
self.watch_dgpu_disable(signal_ctxt.clone()).await?;
|
||||
self.watch_egpu_enable(signal_ctxt.clone()).await?;
|
||||
// NOTE: Can't have this as a watch because on a write to it, it reverts back to
|
||||
// booted-with value as it does not actually change until reboot.
|
||||
// self.watch_gpu_mux_mode(signal_ctxt.clone()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
use crate::CtrlTask;
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{info, warn};
|
||||
use config_traits::StdConfig;
|
||||
use log::{error, info, warn};
|
||||
use rog_platform::power::AsusPower;
|
||||
use rog_platform::supported::ChargeSupportedFunctions;
|
||||
use smol::Executor;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::dbus_interface;
|
||||
use zbus::Connection;
|
||||
use zbus::SignalContext;
|
||||
use systemd_zbus::{ManagerProxy as SystemdProxy, Mode, UnitFileState};
|
||||
use tokio::time::sleep;
|
||||
use zbus::export::futures_util::lock::Mutex;
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::RogError;
|
||||
use crate::{task_watch_item, CtrlTask, GetSupported};
|
||||
|
||||
const ZBUS_PATH: &str = "/org/asuslinux/Power";
|
||||
const NVIDIA_POWERD: &str = "nvidia-powerd.service";
|
||||
|
||||
impl GetSupported for CtrlPower {
|
||||
type A = ChargeSupportedFunctions;
|
||||
@@ -33,7 +41,7 @@ pub struct CtrlPower {
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlPower {
|
||||
async fn set_limit(
|
||||
async fn set_charge_control_end_threshold(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
limit: u8,
|
||||
@@ -47,31 +55,63 @@ impl CtrlPower {
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
Self::notify_charge(&ctxt, limit).await?;
|
||||
Self::notify_charge_control_end_threshold(&ctxt, limit)
|
||||
.await
|
||||
.ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn limit(&self) -> i8 {
|
||||
if let Ok(config) = self.config.try_lock() {
|
||||
return config.bat_charge_limit as i8;
|
||||
fn charge_control_end_threshold(&self) -> u8 {
|
||||
loop {
|
||||
if let Some(mut config) = self.config.try_lock() {
|
||||
let limit = self
|
||||
.power
|
||||
.get_charge_control_end_threshold()
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: get_charge_control_end_threshold {}", err);
|
||||
err
|
||||
})
|
||||
.unwrap_or(100);
|
||||
|
||||
config.read();
|
||||
config.bat_charge_limit = limit;
|
||||
config.write();
|
||||
|
||||
return config.bat_charge_limit;
|
||||
}
|
||||
}
|
||||
-1
|
||||
}
|
||||
|
||||
fn mains_online(&self) -> bool {
|
||||
if self.power.has_online() {
|
||||
if let Ok(v) = self.power.get_online() {
|
||||
return v == 1;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_charge(ctxt: &SignalContext<'_>, limit: u8) -> zbus::Result<()>;
|
||||
async fn notify_charge_control_end_threshold(
|
||||
ctxt: &SignalContext<'_>,
|
||||
limit: u8,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_mains_online(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusAdd for CtrlPower {
|
||||
impl crate::ZbusRun for CtrlPower {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, "/org/asuslinux/Charge", server).await;
|
||||
Self::add_to_server_helper(self, ZBUS_PATH, server).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Reloadable for CtrlPower {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Some(mut config) = self.config.try_lock() {
|
||||
config.read();
|
||||
self.set(config.bat_charge_limit)?;
|
||||
}
|
||||
@@ -80,6 +120,8 @@ impl crate::Reloadable for CtrlPower {
|
||||
}
|
||||
|
||||
impl CtrlPower {
|
||||
task_watch_item!(charge_control_end_threshold power);
|
||||
|
||||
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||
Ok(CtrlPower {
|
||||
power: AsusPower::new()?,
|
||||
@@ -96,7 +138,7 @@ impl CtrlPower {
|
||||
|
||||
info!("Battery charge limit: {}", limit);
|
||||
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
if let Some(mut config) = self.config.try_lock() {
|
||||
config.read();
|
||||
config.bat_charge_limit = limit;
|
||||
config.write();
|
||||
@@ -108,40 +150,138 @@ impl CtrlPower {
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for CtrlPower {
|
||||
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
fn zbus_path() -> &'static str {
|
||||
ZBUS_PATH
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let conn = zbus::Connection::system().await?;
|
||||
let sysd1 = SystemdProxy::new(&conn).await?;
|
||||
let sysd2 = sysd1.clone();
|
||||
let sysd3 = sysd1.clone();
|
||||
|
||||
let power1 = self.clone();
|
||||
let power2 = self.clone();
|
||||
self.create_sys_event_tasks(
|
||||
executor,
|
||||
move || {},
|
||||
move || async {},
|
||||
move || {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
if let Ok(lock) = power1.config.try_lock() {
|
||||
power1
|
||||
let power = power1.clone();
|
||||
let sysd = sysd1.clone();
|
||||
async move {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
let lock = power.config.lock().await;
|
||||
power
|
||||
.set(lock.bat_charge_limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
|
||||
if lock.disable_nvidia_powerd_on_battery {
|
||||
if let Ok(value) = power.power.get_online() {
|
||||
do_nvidia_powerd_action(&sysd, value == 1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
move || {},
|
||||
move || async {},
|
||||
move || {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
if let Ok(lock) = power2.config.try_lock() {
|
||||
power2
|
||||
let power = power2.clone();
|
||||
let sysd = sysd2.clone();
|
||||
async move {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
let lock = power.config.lock().await;
|
||||
power
|
||||
.set(lock.bat_charge_limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
|
||||
if lock.disable_nvidia_powerd_on_battery {
|
||||
if let Ok(value) = power.power.get_online() {
|
||||
do_nvidia_powerd_action(&sysd, value == 1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
let config = self.config.clone();
|
||||
self.watch_charge_control_end_threshold(signal_ctxt.clone())
|
||||
.await?;
|
||||
|
||||
let ctrl = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut online = 10;
|
||||
loop {
|
||||
if let Ok(value) = ctrl.power.get_online() {
|
||||
if online != value {
|
||||
online = value;
|
||||
let mut config = config.lock().await;
|
||||
config.read();
|
||||
|
||||
if config.disable_nvidia_powerd_on_battery {
|
||||
do_nvidia_powerd_action(&sysd3, value == 1).await;
|
||||
}
|
||||
|
||||
Self::notify_mains_online(&signal_ctxt, value == 1)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut prog: Vec<&str> = Vec::new();
|
||||
if value == 1 {
|
||||
// AC ONLINE
|
||||
prog = config.ac_command.split_whitespace().collect();
|
||||
} else if value == 0 {
|
||||
// BATTERY
|
||||
prog = config.bat_command.split_whitespace().collect();
|
||||
}
|
||||
|
||||
if prog.len() > 1 {
|
||||
let mut cmd = Command::new(prog[0]);
|
||||
for arg in prog.iter().skip(1) {
|
||||
cmd.arg(*arg);
|
||||
}
|
||||
if let Err(e) = cmd.spawn() {
|
||||
if value == 1 {
|
||||
error!("AC power command error: {e}");
|
||||
} else {
|
||||
error!("Battery power command error: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The inotify doesn't pick up events when the kernel changes internal value
|
||||
// so we need to watch it with a thread and sleep unfortunately
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn do_nvidia_powerd_action(proxy: &SystemdProxy<'_>, ac_on: bool) {
|
||||
if let Ok(res) = proxy.get_unit_file_state(NVIDIA_POWERD).await {
|
||||
if res == UnitFileState::Enabled {
|
||||
if ac_on {
|
||||
proxy
|
||||
.start_unit(NVIDIA_POWERD, Mode::Replace)
|
||||
.await
|
||||
.map_err(|e| error!("Error stopping {NVIDIA_POWERD}, {e:?}"))
|
||||
.ok();
|
||||
} else {
|
||||
proxy
|
||||
.stop_unit(NVIDIA_POWERD, Mode::Replace)
|
||||
.await
|
||||
.map_err(|e| error!("Error stopping {NVIDIA_POWERD}, {e:?}"))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +1,60 @@
|
||||
use log::{error, warn};
|
||||
use rog_profiles::{FanCurveProfiles, Profile};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use rog_profiles::fan_curve_set::FanCurveSet;
|
||||
use rog_profiles::Profile;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::CONFIG_PATH_BASE;
|
||||
|
||||
const CONFIG_FILE: &str = "profile.ron";
|
||||
const CONFIG_FAN_FILE: &str = "fan_curves.ron";
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct ProfileConfig {
|
||||
#[serde(skip)]
|
||||
config_path: String,
|
||||
/// For restore on boot
|
||||
pub active_profile: Profile,
|
||||
/// States to restore
|
||||
pub fan_curves: Option<FanCurveProfiles>,
|
||||
}
|
||||
|
||||
impl ProfileConfig {
|
||||
fn new(config_path: String) -> Self {
|
||||
impl StdConfig for ProfileConfig {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
config_path,
|
||||
active_profile: Profile::Balanced,
|
||||
fan_curves: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(config_path: String) -> Self {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&config_path)
|
||||
.unwrap_or_else(|_| panic!("The directory /etc/asusd/ is missing")); // okay to cause panic here
|
||||
let mut buf = String::new();
|
||||
let mut config;
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len == 0 {
|
||||
config = Self::new(config_path);
|
||||
} else if let Ok(data) = toml::from_str(&buf) {
|
||||
config = data;
|
||||
config.config_path = config_path;
|
||||
} else {
|
||||
warn!(
|
||||
"Could not deserialise {}.\nWill rename to {}-old and recreate config",
|
||||
config_path, config_path
|
||||
);
|
||||
let cfg_old = config_path.clone() + "-old";
|
||||
std::fs::rename(config_path.clone(), cfg_old).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Could not rename. Please remove {} then restart service: Error {}",
|
||||
config_path, err
|
||||
)
|
||||
});
|
||||
config = Self::new(config_path);
|
||||
}
|
||||
} else {
|
||||
config = Self::new(config_path);
|
||||
}
|
||||
config
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
PathBuf::from(CONFIG_PATH_BASE)
|
||||
}
|
||||
|
||||
pub fn read(&mut self) {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&self.config_path)
|
||||
.unwrap_or_else(|err| panic!("Error reading {}: {}", self.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 {}", self.config_path);
|
||||
} else {
|
||||
let mut data: ProfileConfig = toml::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", self.config_path));
|
||||
// copy over serde skipped values
|
||||
data.config_path = self.config_path.clone();
|
||||
*self = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = File::create(&self.config_path).expect("Couldn't overwrite config");
|
||||
let data = toml::to_string(self).expect("Parse config to toml failed");
|
||||
file.write_all(data.as_bytes())
|
||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||
fn file_name(&self) -> String {
|
||||
CONFIG_FILE.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for ProfileConfig {}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
pub struct FanCurveConfig {
|
||||
pub balanced: FanCurveSet,
|
||||
pub performance: FanCurveSet,
|
||||
pub quiet: FanCurveSet,
|
||||
}
|
||||
|
||||
impl StdConfig for FanCurveConfig {
|
||||
/// Create a new config. The defaults are zeroed so the device must be read
|
||||
/// to get the actual device defaults.
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
PathBuf::from(CONFIG_PATH_BASE)
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
CONFIG_FAN_FILE.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for FanCurveConfig {}
|
||||
|
||||
@@ -1,17 +1,48 @@
|
||||
use crate::error::RogError;
|
||||
use crate::{CtrlTask, GetSupported};
|
||||
use async_trait::async_trait;
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use log::{info, warn};
|
||||
use rog_platform::platform::AsusPlatform;
|
||||
use rog_platform::supported::PlatformProfileFunctions;
|
||||
use rog_profiles::error::ProfileError;
|
||||
use rog_profiles::{FanCurveProfiles, Profile};
|
||||
use smol::Executor;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use super::config::ProfileConfig;
|
||||
use super::config::{FanCurveConfig, ProfileConfig};
|
||||
use crate::error::RogError;
|
||||
use crate::GetSupported;
|
||||
|
||||
// TODO: macro wrapper for warn/info/error log macros to add module name
|
||||
const MOD_NAME: &str = "CtrlPlatformProfile";
|
||||
|
||||
pub struct FanCurves {
|
||||
config_file: FanCurveConfig,
|
||||
profiles: FanCurveProfiles,
|
||||
}
|
||||
|
||||
impl FanCurves {
|
||||
pub fn update_profiles_from_config(&mut self) {
|
||||
self.profiles.balanced = self.config_file.balanced.clone();
|
||||
self.profiles.performance = self.config_file.performance.clone();
|
||||
self.profiles.quiet = self.config_file.quiet.clone();
|
||||
}
|
||||
|
||||
pub fn update_config_from_profiles(&mut self) {
|
||||
self.config_file.balanced = self.profiles.balanced.clone();
|
||||
self.config_file.performance = self.profiles.performance.clone();
|
||||
self.config_file.quiet = self.profiles.quiet.clone();
|
||||
}
|
||||
|
||||
pub fn profiles(&self) -> &FanCurveProfiles {
|
||||
&self.profiles
|
||||
}
|
||||
|
||||
pub fn profiles_mut(&mut self) -> &mut FanCurveProfiles {
|
||||
&mut self.profiles
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlPlatformProfile {
|
||||
pub config: ProfileConfig,
|
||||
pub profile_config: ProfileConfig,
|
||||
pub fan_curves: Option<FanCurves>,
|
||||
pub platform: AsusPlatform,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlPlatformProfile {
|
||||
@@ -19,7 +50,10 @@ impl GetSupported for CtrlPlatformProfile {
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
if !Profile::is_platform_profile_supported() {
|
||||
warn!("platform_profile kernel interface not found, your laptop does not support this, or the interface is missing.");
|
||||
warn!(
|
||||
"platform_profile kernel interface not found, your laptop does not support this, \
|
||||
or the interface is missing."
|
||||
);
|
||||
}
|
||||
|
||||
let res = FanCurveProfiles::is_supported();
|
||||
@@ -29,7 +63,10 @@ impl GetSupported for CtrlPlatformProfile {
|
||||
};
|
||||
|
||||
if !fan_curve_supported {
|
||||
info!("fan curves kernel interface not found, your laptop does not support this, or the interface is missing.");
|
||||
info!(
|
||||
"fan curves kernel interface not found, your laptop does not support this, or the \
|
||||
interface is missing."
|
||||
);
|
||||
}
|
||||
|
||||
PlatformProfileFunctions {
|
||||
@@ -39,43 +76,54 @@ impl GetSupported for CtrlPlatformProfile {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Reloadable for CtrlPlatformProfile {
|
||||
/// Fetch the active profile and use that to set all related components up
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Some(curves) = &mut self.config.fan_curves {
|
||||
if let Ok(mut device) = FanCurveProfiles::get_device() {
|
||||
// There is a possibility that the curve was default zeroed, so this call initialises
|
||||
// the data from system read and we need to save it after
|
||||
curves.write_profile_curve_to_platform(self.config.active_profile, &mut device)?;
|
||||
self.config.write();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlPlatformProfile {
|
||||
pub fn new(config: ProfileConfig) -> Result<Self, RogError> {
|
||||
if Profile::is_platform_profile_supported() {
|
||||
info!("Device has profile control available");
|
||||
let platform = AsusPlatform::new()?;
|
||||
if platform.has_platform_profile() || platform.has_throttle_thermal_policy() {
|
||||
info!("{MOD_NAME}: Device has profile control available");
|
||||
|
||||
let mut controller = CtrlPlatformProfile { config };
|
||||
let mut controller = CtrlPlatformProfile {
|
||||
profile_config: config,
|
||||
fan_curves: None,
|
||||
platform,
|
||||
};
|
||||
if FanCurveProfiles::get_device().is_ok() {
|
||||
info!("Device has fan curves available");
|
||||
if controller.config.fan_curves.is_none() {
|
||||
controller.config.fan_curves = Some(Default::default());
|
||||
info!("{MOD_NAME}: Device has fan curves available");
|
||||
let fan_config = FanCurveConfig::new();
|
||||
// Only do defaults if the config doesn't already exist
|
||||
if !fan_config.file_path().exists() {
|
||||
info!("{MOD_NAME}: Fetching default fan curves");
|
||||
controller.fan_curves = Some(FanCurves {
|
||||
config_file: fan_config,
|
||||
profiles: FanCurveProfiles::default(),
|
||||
});
|
||||
for _ in [Profile::Balanced, Profile::Performance, Profile::Quiet] {
|
||||
// For each profile we need to switch to it before we
|
||||
// can read the existing values from hardware. The ACPI method used
|
||||
// for this is what limits us.
|
||||
controller.set_next_profile()?;
|
||||
// Make sure to set the baseline to default
|
||||
controller.set_active_curve_to_defaults()?;
|
||||
|
||||
let active = Profile::get_active_profile().unwrap_or(Profile::Balanced);
|
||||
if let Some(curves) = controller.config.fan_curves.as_ref() {
|
||||
|
||||
if let Some(curves) = controller.fan_curves.as_ref() {
|
||||
info!(
|
||||
"{active:?}: {}",
|
||||
String::from(curves.get_fan_curves_for(active))
|
||||
"{MOD_NAME}: {active:?}: {}",
|
||||
String::from(curves.profiles().get_fan_curves_for(active))
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(curves) = controller.fan_curves.as_ref() {
|
||||
curves.config_file.write();
|
||||
}
|
||||
} else {
|
||||
info!("{MOD_NAME}: Fan curves previously stored, loading...");
|
||||
let mut fan_curves = FanCurves {
|
||||
config_file: fan_config.load(),
|
||||
profiles: FanCurveProfiles::default(),
|
||||
};
|
||||
fan_curves.update_profiles_from_config();
|
||||
controller.fan_curves = Some(fan_curves);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,25 +133,30 @@ impl CtrlPlatformProfile {
|
||||
Err(ProfileError::NotSupported.into())
|
||||
}
|
||||
|
||||
pub fn save_config(&self) {
|
||||
self.config.write();
|
||||
pub fn save_config(&mut self) {
|
||||
self.profile_config.write();
|
||||
if let Some(fans) = self.fan_curves.as_mut() {
|
||||
fans.update_config_from_profiles();
|
||||
fans.config_file.write(); // config write
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle to next profile in list. This will first read the config, switch, then write out
|
||||
/// Toggle to next profile in list. This will first read the config, switch,
|
||||
/// then write out
|
||||
pub(super) fn set_next_profile(&mut self) -> Result<(), RogError> {
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
match self.config.active_profile {
|
||||
match self.profile_config.active_profile {
|
||||
Profile::Balanced => {
|
||||
Profile::set_profile(Profile::Performance)?;
|
||||
self.config.active_profile = Profile::Performance;
|
||||
self.profile_config.active_profile = Profile::Performance;
|
||||
}
|
||||
Profile::Performance => {
|
||||
Profile::set_profile(Profile::Quiet)?;
|
||||
self.config.active_profile = Profile::Quiet;
|
||||
self.profile_config.active_profile = Profile::Quiet;
|
||||
}
|
||||
Profile::Quiet => {
|
||||
Profile::set_profile(Profile::Balanced)?;
|
||||
self.config.active_profile = Profile::Balanced;
|
||||
self.profile_config.active_profile = Profile::Balanced;
|
||||
}
|
||||
}
|
||||
self.write_profile_curve_to_platform()?;
|
||||
@@ -112,49 +165,27 @@ impl CtrlPlatformProfile {
|
||||
|
||||
/// Set the curve for the active profile active
|
||||
pub(super) fn write_profile_curve_to_platform(&mut self) -> Result<(), RogError> {
|
||||
if let Some(curves) = &mut self.config.fan_curves {
|
||||
if let Some(curves) = &mut self.fan_curves {
|
||||
if let Ok(mut device) = FanCurveProfiles::get_device() {
|
||||
curves.write_profile_curve_to_platform(self.config.active_profile, &mut device)?;
|
||||
curves.profiles_mut().write_profile_curve_to_platform(
|
||||
self.profile_config.active_profile,
|
||||
&mut device,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn set_active_curve_to_defaults(&mut self) -> Result<(), RogError> {
|
||||
if let Some(curves) = self.config.fan_curves.as_mut() {
|
||||
if let Some(curves) = self.fan_curves.as_mut() {
|
||||
if let Ok(mut device) = FanCurveProfiles::get_device() {
|
||||
curves.set_active_curve_to_defaults(self.config.active_profile, &mut device)?;
|
||||
curves.profiles_mut().set_active_curve_to_defaults(
|
||||
self.profile_config.active_profile,
|
||||
&mut device,
|
||||
)?;
|
||||
curves.update_config_from_profiles();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlProfileTask {
|
||||
ctrl: Arc<Mutex<CtrlPlatformProfile>>,
|
||||
}
|
||||
|
||||
impl CtrlProfileTask {
|
||||
pub fn new(ctrl: Arc<Mutex<CtrlPlatformProfile>>) -> Self {
|
||||
Self { ctrl }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for CtrlProfileTask {
|
||||
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
let ctrl = self.ctrl.clone();
|
||||
self.repeating_task(666, executor, move || {
|
||||
if let Ok(ref mut lock) = ctrl.try_lock() {
|
||||
let new_profile = Profile::get_active_profile().unwrap();
|
||||
if new_profile != lock.config.active_profile {
|
||||
lock.config.active_profile = new_profile;
|
||||
lock.write_profile_curve_to_platform().unwrap();
|
||||
lock.save_config();
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod config;
|
||||
pub mod controller;
|
||||
pub mod zbus;
|
||||
/// Implements `CtrlTask`, Reloadable, `ZbusRun`
|
||||
pub mod trait_impls;
|
||||
|
||||
311
daemon/src/ctrl_profiles/trait_impls.rs
Normal file
@@ -0,0 +1,311 @@
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use config_traits::StdConfig;
|
||||
use log::{error, info, warn};
|
||||
use rog_profiles::fan_curve_set::{CurveData, FanCurveSet};
|
||||
use rog_profiles::{FanCurveProfiles, Profile};
|
||||
use zbus::export::futures_util::lock::Mutex;
|
||||
use zbus::export::futures_util::StreamExt;
|
||||
use zbus::fdo::Error;
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use super::controller::CtrlPlatformProfile;
|
||||
use crate::error::RogError;
|
||||
use crate::CtrlTask;
|
||||
|
||||
const MOD_NAME: &str = "ProfileZbus";
|
||||
|
||||
const ZBUS_PATH: &str = "/org/asuslinux/Profile";
|
||||
const UNSUPPORTED_MSG: &str =
|
||||
"Fan curves are not supported on this laptop or you require a patched kernel";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProfileZbus(pub Arc<Mutex<CtrlPlatformProfile>>);
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl ProfileZbus {
|
||||
/// Fetch profile names
|
||||
fn profiles(&mut self) -> zbus::fdo::Result<Vec<Profile>> {
|
||||
if let Ok(profiles) = Profile::get_profile_names() {
|
||||
return Ok(profiles);
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get all profile details".to_owned(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Toggle to next platform_profile. Names provided by `Profiles`.
|
||||
/// If fan-curves are supported will also activate a fan curve for profile.
|
||||
async fn next_profile(&mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>) {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.set_next_profile()
|
||||
.unwrap_or_else(|err| warn!("{MOD_NAME}: {}", err));
|
||||
ctrl.save_config();
|
||||
|
||||
Self::notify_profile(&ctxt, ctrl.profile_config.active_profile)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
async fn active_profile(&mut self) -> zbus::fdo::Result<Profile> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
Ok(ctrl.profile_config.active_profile)
|
||||
}
|
||||
|
||||
/// Set this platform_profile name as active
|
||||
async fn set_active_profile(
|
||||
&self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
profile: Profile,
|
||||
) {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
ctrl.profile_config.read();
|
||||
Profile::set_profile(profile)
|
||||
.map_err(|e| warn!("{MOD_NAME}: set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.profile_config.active_profile = profile;
|
||||
ctrl.write_profile_curve_to_platform()
|
||||
.map_err(|e| warn!("{MOD_NAME}: write_profile_curve_to_platform, {}", e))
|
||||
.ok();
|
||||
|
||||
ctrl.save_config();
|
||||
|
||||
Self::notify_profile(&ctxt, ctrl.profile_config.active_profile)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// Get a list of profiles that have fan-curves enabled.
|
||||
async fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result<Vec<Profile>> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
if let Some(curves) = &mut ctrl.fan_curves {
|
||||
return Ok(curves.profiles().get_enabled_curve_profiles());
|
||||
}
|
||||
Err(Error::Failed(UNSUPPORTED_MSG.to_owned()))
|
||||
}
|
||||
|
||||
/// Set a profile fan curve enabled status. Will also activate a fan curve
|
||||
/// if in the same profile mode
|
||||
async fn set_fan_curve_enabled(
|
||||
&mut self,
|
||||
profile: Profile,
|
||||
enabled: bool,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
if let Some(curves) = &mut ctrl.fan_curves {
|
||||
curves
|
||||
.profiles_mut()
|
||||
.set_profile_curve_enabled(profile, enabled);
|
||||
|
||||
ctrl.write_profile_curve_to_platform()
|
||||
.map_err(|e| warn!("{MOD_NAME}: write_profile_curve_to_platform, {}", e))
|
||||
.ok();
|
||||
|
||||
ctrl.save_config();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Failed(UNSUPPORTED_MSG.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the fan-curve data for the currently active Profile
|
||||
async fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result<FanCurveSet> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
if let Some(curves) = &mut ctrl.fan_curves {
|
||||
let curve = curves.profiles().get_fan_curves_for(profile);
|
||||
return Ok(curve.clone());
|
||||
}
|
||||
Err(Error::Failed(UNSUPPORTED_MSG.to_owned()))
|
||||
}
|
||||
|
||||
/// Set the fan curve for the specified profile.
|
||||
/// Will also activate the fan curve if the user is in the same mode.
|
||||
async fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
if let Some(curves) = &mut ctrl.fan_curves {
|
||||
curves
|
||||
.profiles_mut()
|
||||
.save_fan_curve(curve, profile)
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
} else {
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_owned()));
|
||||
}
|
||||
ctrl.write_profile_curve_to_platform()
|
||||
.map_err(|e| warn!("{MOD_NAME}: Profile::set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.save_config();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reset the stored (self) and device curve to the defaults of the
|
||||
/// platform.
|
||||
///
|
||||
/// Each platform_profile has a different default and the defualt can be
|
||||
/// read only for the currently active profile.
|
||||
async fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
ctrl.set_active_curve_to_defaults()
|
||||
.map_err(|e| warn!("{MOD_NAME}: Profile::set_active_curve_to_defaults, {}", e))
|
||||
.ok();
|
||||
ctrl.save_config();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reset the stored (self) and device curve to the defaults of the
|
||||
/// platform.
|
||||
///
|
||||
/// Each platform_profile has a different default and the defualt can be
|
||||
/// read only for the currently active profile.
|
||||
async fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
ctrl.profile_config.read();
|
||||
let active = Profile::get_active_profile().unwrap_or(Profile::Balanced);
|
||||
|
||||
Profile::set_profile(profile)
|
||||
.map_err(|e| warn!("{MOD_NAME}: set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.set_active_curve_to_defaults()
|
||||
.map_err(|e| warn!("{MOD_NAME}: Profile::set_active_curve_to_defaults, {}", e))
|
||||
.ok();
|
||||
|
||||
Profile::set_profile(active)
|
||||
.map_err(|e| warn!("{MOD_NAME}: set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.save_config();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_profile(signal_ctxt: &SignalContext<'_>, profile: Profile) -> zbus::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusRun for ProfileZbus {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, ZBUS_PATH, server).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for ProfileZbus {
|
||||
fn zbus_path() -> &'static str {
|
||||
ZBUS_PATH
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let ctrl = self.0.clone();
|
||||
let sig_ctx = signal_ctxt.clone();
|
||||
let mut watch = self
|
||||
.0
|
||||
.lock()
|
||||
.await
|
||||
.platform
|
||||
.monitor_throttle_thermal_policy()?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut buffer = [0; 32];
|
||||
if let Ok(stream) = watch.event_stream(&mut buffer) {
|
||||
stream
|
||||
.for_each(|_| async {
|
||||
let mut lock = ctrl.lock().await;
|
||||
if let Ok(profile) =
|
||||
lock.platform.get_throttle_thermal_policy().map_err(|e| {
|
||||
error!("{MOD_NAME}: get_throttle_thermal_policy error: {e}");
|
||||
})
|
||||
{
|
||||
let new_profile = Profile::from_throttle_thermal_policy(profile);
|
||||
if new_profile != lock.profile_config.active_profile {
|
||||
info!("{MOD_NAME}: platform_profile changed to {new_profile}");
|
||||
lock.profile_config.active_profile = new_profile;
|
||||
lock.write_profile_curve_to_platform().unwrap();
|
||||
lock.save_config();
|
||||
Profile::set_profile(lock.profile_config.active_profile)
|
||||
.map_err(|e| {
|
||||
error!("Profile::set_profile() error: {e}");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Self::notify_profile(&sig_ctx, lock.profile_config.active_profile)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
});
|
||||
|
||||
let ctrl = self.0.clone();
|
||||
let mut watch = self.0.lock().await.platform.monitor_platform_profile()?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut buffer = [0; 32];
|
||||
if let Ok(stream) = watch.event_stream(&mut buffer) {
|
||||
stream
|
||||
.for_each(|_| async {
|
||||
let mut lock = ctrl.lock().await;
|
||||
if let Ok(profile) = lock.platform.get_platform_profile().map_err(|e| {
|
||||
error!("get_platform_profile error: {e}");
|
||||
}) {
|
||||
if let Ok(new_profile) = Profile::from_str(&profile).map_err(|e| {
|
||||
error!("Profile::from_str(&profile) error: {e}");
|
||||
}) {
|
||||
if new_profile != lock.profile_config.active_profile {
|
||||
info!("{MOD_NAME}: platform_profile changed to {new_profile}");
|
||||
lock.profile_config.active_profile = new_profile;
|
||||
lock.write_profile_curve_to_platform().unwrap();
|
||||
lock.save_config();
|
||||
Profile::set_profile(lock.profile_config.active_profile)
|
||||
.map_err(|e| {
|
||||
error!("Profile::set_profile() error: {e}");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Self::notify_profile(
|
||||
&signal_ctxt,
|
||||
lock.profile_config.active_profile,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Reloadable for ProfileZbus {
|
||||
/// Fetch the active profile and use that to set all related components up
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
let mut ctrl = self.0.lock().await;
|
||||
let active = ctrl.profile_config.active_profile;
|
||||
if let Some(curves) = &mut ctrl.fan_curves {
|
||||
if let Ok(mut device) = FanCurveProfiles::get_device() {
|
||||
// There is a possibility that the curve was default zeroed, so this call
|
||||
// initialises the data from system read and we need to save it
|
||||
// after
|
||||
curves
|
||||
.profiles_mut()
|
||||
.write_profile_curve_to_platform(active, &mut device)?;
|
||||
ctrl.profile_config.write();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
use async_trait::async_trait;
|
||||
use log::warn;
|
||||
use rog_profiles::fan_curve_set::CurveData;
|
||||
use rog_profiles::fan_curve_set::FanCurveSet;
|
||||
use rog_profiles::Profile;
|
||||
use zbus::Connection;
|
||||
use zbus::SignalContext;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::{dbus_interface, fdo::Error};
|
||||
|
||||
use super::controller::CtrlPlatformProfile;
|
||||
|
||||
static UNSUPPORTED_MSG: &str =
|
||||
"Fan curves are not supported on this laptop or you require a patched kernel";
|
||||
|
||||
pub struct ProfileZbus {
|
||||
inner: Arc<Mutex<CtrlPlatformProfile>>,
|
||||
}
|
||||
|
||||
impl ProfileZbus {
|
||||
pub fn new(inner: Arc<Mutex<CtrlPlatformProfile>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl ProfileZbus {
|
||||
/// Fetch profile names
|
||||
fn profiles(&mut self) -> zbus::fdo::Result<Vec<Profile>> {
|
||||
if let Ok(profiles) = Profile::get_profile_names() {
|
||||
return Ok(profiles);
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get all profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Toggle to next platform_profile. Names provided by `Profiles`.
|
||||
/// If fan-curves are supported will also activate a fan curve for profile.
|
||||
async fn next_profile(&mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>) {
|
||||
let mut profile = None;
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.set_next_profile()
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
ctrl.save_config();
|
||||
profile = Some(ctrl.config.active_profile);
|
||||
}
|
||||
if let Some(profile) = profile {
|
||||
Self::notify_profile(&ctxt, profile).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn active_profile(&mut self) -> zbus::fdo::Result<Profile> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
return Ok(ctrl.config.active_profile);
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile name".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Set this platform_profile name as active
|
||||
async fn set_active_profile(
|
||||
&self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
profile: Profile,
|
||||
) {
|
||||
let mut tmp = None;
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
// Read first just incase the user has modified the config before calling this
|
||||
ctrl.config.read();
|
||||
Profile::set_profile(profile)
|
||||
.map_err(|e| warn!("set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.config.active_profile = profile;
|
||||
ctrl.write_profile_curve_to_platform()
|
||||
.map_err(|e| warn!("write_profile_curve_to_platform, {}", e))
|
||||
.ok();
|
||||
|
||||
ctrl.save_config();
|
||||
tmp = Some(ctrl.config.active_profile);
|
||||
}
|
||||
if let Some(profile) = tmp {
|
||||
Self::notify_profile(&ctxt, profile).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a list of profiles that have fan-curves enabled.
|
||||
fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result<Vec<Profile>> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &ctrl.config.fan_curves {
|
||||
return Ok(curves.get_enabled_curve_profiles().to_vec());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get enabled fan curve names".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Set a profile fan curve enabled status. Will also activate a fan curve if in the
|
||||
/// same profile mode
|
||||
fn set_fan_curve_enabled(&mut self, profile: Profile, enabled: bool) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
return if let Some(curves) = &mut ctrl.config.fan_curves {
|
||||
curves.set_profile_curve_enabled(profile, enabled);
|
||||
|
||||
ctrl.write_profile_curve_to_platform()
|
||||
.map_err(|e| warn!("write_profile_curve_to_platform, {}", e))
|
||||
.ok();
|
||||
|
||||
ctrl.save_config();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Failed(UNSUPPORTED_MSG.to_string()))
|
||||
};
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get enabled fan curve names".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Get the fan-curve data for the currently active Profile
|
||||
fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result<FanCurveSet> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &ctrl.config.fan_curves {
|
||||
let curve = curves.get_fan_curves_for(profile);
|
||||
return Ok(curve.clone());
|
||||
}
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
Err(Error::Failed("Failed to get fan curve data".to_string()))
|
||||
}
|
||||
|
||||
/// Set the fan curve for the specified profile.
|
||||
/// Will also activate the fan curve if the user is in the same mode.
|
||||
fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
if let Some(curves) = &mut ctrl.config.fan_curves {
|
||||
curves
|
||||
.save_fan_curve(curve, profile)
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
} else {
|
||||
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
|
||||
}
|
||||
ctrl.write_profile_curve_to_platform()
|
||||
.map_err(|e| warn!("Profile::set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.save_config();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reset the stored (self) and device curve to the defaults of the platform.
|
||||
///
|
||||
/// Each platform_profile has a different default and the defualt can be read
|
||||
/// only for the currently active profile.
|
||||
fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
ctrl.set_active_curve_to_defaults()
|
||||
.map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e))
|
||||
.ok();
|
||||
ctrl.save_config();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reset the stored (self) and device curve to the defaults of the platform.
|
||||
///
|
||||
/// Each platform_profile has a different default and the defualt can be read
|
||||
/// only for the currently active profile.
|
||||
fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
ctrl.config.read();
|
||||
let active = Profile::get_active_profile().unwrap_or(Profile::Balanced);
|
||||
|
||||
Profile::set_profile(profile)
|
||||
.map_err(|e| warn!("set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.set_active_curve_to_defaults()
|
||||
.map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e))
|
||||
.ok();
|
||||
|
||||
Profile::set_profile(active)
|
||||
.map_err(|e| warn!("set_profile, {}", e))
|
||||
.ok();
|
||||
ctrl.save_config();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_profile(signal_ctxt: &SignalContext<'_>, profile: Profile) -> zbus::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusAdd for ProfileZbus {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, "/org/asuslinux/Profile", server).await;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,27 @@
|
||||
use async_trait::async_trait;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use zbus::dbus_interface;
|
||||
use zbus::Connection;
|
||||
use zvariant::Type;
|
||||
use zbus::zvariant::Type;
|
||||
use zbus::{dbus_interface, Connection};
|
||||
|
||||
use crate::{
|
||||
ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_platform::CtrlRogBios,
|
||||
ctrl_power::CtrlPower, ctrl_profiles::controller::CtrlPlatformProfile, GetSupported,
|
||||
};
|
||||
use crate::ctrl_anime::CtrlAnime;
|
||||
use crate::ctrl_aura::controller::CtrlKbdLed;
|
||||
use crate::ctrl_platform::CtrlPlatform;
|
||||
use crate::ctrl_power::CtrlPower;
|
||||
use crate::ctrl_profiles::controller::CtrlPlatformProfile;
|
||||
use crate::GetSupported;
|
||||
|
||||
use rog_platform::supported::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, Type)]
|
||||
pub struct SupportedFunctions {
|
||||
pub anime_ctrl: AnimeSupportedFunctions,
|
||||
pub charge_ctrl: ChargeSupportedFunctions,
|
||||
pub platform_profile: PlatformProfileFunctions,
|
||||
pub keyboard_led: LedSupportedFunctions,
|
||||
pub rog_bios_ctrl: RogBiosSupportedFunctions,
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Type)]
|
||||
pub struct SupportedFunctions(rog_platform::supported::SupportedFunctions);
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl SupportedFunctions {
|
||||
fn supported_functions(&self) -> &SupportedFunctions {
|
||||
self
|
||||
pub fn supported_functions(&self) -> &rog_platform::supported::SupportedFunctions {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusAdd for SupportedFunctions {
|
||||
impl crate::ZbusRun for SupportedFunctions {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, "/org/asuslinux/Supported", server).await;
|
||||
}
|
||||
@@ -38,12 +31,12 @@ impl GetSupported for SupportedFunctions {
|
||||
type A = SupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
SupportedFunctions {
|
||||
Self(rog_platform::supported::SupportedFunctions {
|
||||
anime_ctrl: CtrlAnime::get_supported(),
|
||||
keyboard_led: CtrlKbdLed::get_supported(),
|
||||
charge_ctrl: CtrlPower::get_supported(),
|
||||
platform_profile: CtrlPlatformProfile::get_supported(),
|
||||
rog_bios_ctrl: CtrlRogBios::get_supported(),
|
||||
}
|
||||
rog_bios_ctrl: CtrlPlatform::get_supported(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,39 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use ::zbus::export::futures_util::lock::Mutex;
|
||||
use ::zbus::Connection;
|
||||
use daemon::ctrl_profiles::controller::CtrlProfileTask;
|
||||
use log::LevelFilter;
|
||||
use log::{error, info, warn};
|
||||
use smol::Executor;
|
||||
|
||||
use config_traits::{StdConfig, StdConfigLoad, StdConfigLoad2};
|
||||
use daemon::config::Config;
|
||||
use daemon::ctrl_anime::config::AnimeConfig;
|
||||
use daemon::ctrl_anime::zbus::CtrlAnimeZbus;
|
||||
use daemon::ctrl_anime::*;
|
||||
use daemon::ctrl_aura::config::AuraConfig;
|
||||
use daemon::ctrl_aura::controller::{
|
||||
CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus,
|
||||
};
|
||||
use daemon::ctrl_platform::CtrlRogBios;
|
||||
use daemon::ctrl_anime::trait_impls::CtrlAnimeZbus;
|
||||
use daemon::ctrl_anime::CtrlAnime;
|
||||
use daemon::ctrl_aura::controller::CtrlKbdLed;
|
||||
use daemon::ctrl_aura::trait_impls::CtrlKbdLedZbus;
|
||||
use daemon::ctrl_platform::CtrlPlatform;
|
||||
use daemon::ctrl_power::CtrlPower;
|
||||
use daemon::ctrl_profiles::config::ProfileConfig;
|
||||
use daemon::{
|
||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||
};
|
||||
use daemon::{
|
||||
ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus},
|
||||
laptops::LaptopLedData,
|
||||
};
|
||||
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
||||
use daemon::ctrl_profiles::controller::CtrlPlatformProfile;
|
||||
use daemon::ctrl_profiles::trait_impls::ProfileZbus;
|
||||
use daemon::ctrl_supported::SupportedFunctions;
|
||||
use daemon::{print_board_info, CtrlTask, GetSupported, Reloadable, ZbusRun};
|
||||
use log::{error, info, warn};
|
||||
use rog_aura::aura_detection::LaptopLedData;
|
||||
use rog_dbus::DBUS_NAME;
|
||||
use rog_profiles::Profile;
|
||||
use tokio::time::sleep;
|
||||
use zbus::SignalContext;
|
||||
|
||||
static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf";
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut logger = env_logger::Builder::new();
|
||||
logger
|
||||
.parse_default_env()
|
||||
.target(env_logger::Target::Stdout)
|
||||
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
|
||||
.filter(None, LevelFilter::Info)
|
||||
.init();
|
||||
|
||||
let is_service = match env::var_os("IS_SERVICE") {
|
||||
@@ -61,117 +57,79 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
info!(" rog-profiles v{}", rog_profiles::VERSION);
|
||||
info!("rog-platform v{}", rog_platform::VERSION);
|
||||
|
||||
let mut executor = Executor::new();
|
||||
|
||||
smol::block_on(start_daemon(&mut executor))?;
|
||||
start_daemon().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The actual main loop for the daemon
|
||||
async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box<dyn Error>> {
|
||||
async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
let supported = SupportedFunctions::get_supported();
|
||||
print_board_info();
|
||||
println!("{}", serde_json::to_string_pretty(&supported)?);
|
||||
println!("{}", supported.supported_functions());
|
||||
|
||||
// Start zbus server
|
||||
let mut connection = Connection::system().await?;
|
||||
|
||||
let config = Config::load();
|
||||
let config = Config::new().load();
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
|
||||
supported.add_to_server(&mut connection).await;
|
||||
|
||||
match CtrlRogBios::new(config.clone()) {
|
||||
Ok(mut ctrl) => {
|
||||
// Do a reload of any settings
|
||||
ctrl.reload()
|
||||
.unwrap_or_else(|err| warn!("CtrlRogBios: {}", err));
|
||||
// Then register to dbus server
|
||||
ctrl.add_to_server(&mut connection).await;
|
||||
|
||||
let task = CtrlRogBios::new(config.clone())?;
|
||||
task.create_tasks(executor).await.ok();
|
||||
match CtrlPlatform::new(config.clone()) {
|
||||
Ok(ctrl) => {
|
||||
let sig_ctx = CtrlPlatform::signal_context(&connection)?;
|
||||
start_tasks(ctrl, &mut connection, sig_ctx).await?;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("rog_bios_control: {}", err);
|
||||
error!("CtrlPlatform: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
match CtrlPower::new(config.clone()) {
|
||||
Ok(mut ctrl) => {
|
||||
// Do a reload of any settings
|
||||
ctrl.reload()
|
||||
.unwrap_or_else(|err| warn!("CtrlPower: {}", err));
|
||||
// Then register to dbus server
|
||||
ctrl.add_to_server(&mut connection).await;
|
||||
|
||||
let task = CtrlPower::new(config)?;
|
||||
task.create_tasks(executor).await.ok();
|
||||
Ok(ctrl) => {
|
||||
let sig_ctx = CtrlPower::signal_context(&connection)?;
|
||||
start_tasks(ctrl, &mut connection, sig_ctx).await?;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("charge_control: {}", err);
|
||||
error!("CtrlPower: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
if Profile::is_platform_profile_supported() {
|
||||
let profile_config = ProfileConfig::load(PROFILE_CONFIG_PATH.into());
|
||||
let profile_config = ProfileConfig::new().load();
|
||||
match CtrlPlatformProfile::new(profile_config) {
|
||||
Ok(mut ctrl) => {
|
||||
ctrl.reload()
|
||||
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
||||
|
||||
let tmp = Arc::new(Mutex::new(ctrl));
|
||||
let task = CtrlProfileTask::new(tmp.clone());
|
||||
task.create_tasks(executor).await.ok();
|
||||
|
||||
let task = ProfileZbus::new(tmp.clone());
|
||||
task.add_to_server(&mut connection).await;
|
||||
Ok(ctrl) => {
|
||||
let zbus = ProfileZbus(Arc::new(Mutex::new(ctrl)));
|
||||
let sig_ctx = ProfileZbus::signal_context(&connection)?;
|
||||
start_tasks(zbus, &mut connection, sig_ctx).await?;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Profile control: {}", err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("platform_profile support not found. This requires kernel 5.15.x or the patch applied: https://lkml.org/lkml/2021/8/18/1022");
|
||||
warn!("platform_profile support not found");
|
||||
}
|
||||
|
||||
match CtrlAnime::new(AnimeConfig::load()) {
|
||||
match CtrlAnime::new(AnimeConfig::new().load()) {
|
||||
Ok(ctrl) => {
|
||||
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 connection).await;
|
||||
|
||||
let task = CtrlAnimeTask::new(inner).await;
|
||||
task.create_tasks(executor).await.ok();
|
||||
let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl)));
|
||||
let sig_ctx = CtrlAnimeZbus::signal_context(&connection)?;
|
||||
start_tasks(zbus, &mut connection, sig_ctx).await?;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("AniMe control: {}", err);
|
||||
info!("AniMe control: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let laptop = LaptopLedData::get_data();
|
||||
let aura_config = AuraConfig::load(&laptop);
|
||||
match CtrlKbdLed::new(laptop, aura_config) {
|
||||
// CtrlKbdLed deviates from the config pattern above due to requiring a keyboard
|
||||
// detection first
|
||||
match CtrlKbdLed::new(laptop) {
|
||||
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 connection)
|
||||
.await;
|
||||
|
||||
let task = CtrlKbdLedTask::new(inner);
|
||||
task.create_tasks(executor).await.ok();
|
||||
let zbus = CtrlKbdLedZbus(Arc::new(Mutex::new(ctrl)));
|
||||
let sig_ctx = CtrlKbdLedZbus::signal_context(&connection)?;
|
||||
start_tasks(zbus, &mut connection, sig_ctx).await?;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Keyboard control: {}", err);
|
||||
@@ -180,7 +138,28 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box<dyn Error>>
|
||||
|
||||
// Request dbus name after finishing initalizing all functions
|
||||
connection.request_name(DBUS_NAME).await?;
|
||||
|
||||
loop {
|
||||
smol::block_on(executor.tick());
|
||||
// This is just a blocker to idle and ensure the reator reacts
|
||||
sleep(Duration::from_millis(1000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_tasks<T>(
|
||||
mut zbus: T,
|
||||
connection: &mut Connection,
|
||||
signal_ctx: SignalContext<'static>,
|
||||
) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
T: ZbusRun + Reloadable + CtrlTask + Clone,
|
||||
{
|
||||
let task = zbus.clone();
|
||||
|
||||
zbus.reload()
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("Controller error: {}", err));
|
||||
zbus.add_to_server(connection).await;
|
||||
|
||||
task.create_tasks(signal_ctx).await.ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::convert::From;
|
||||
use std::fmt;
|
||||
|
||||
use config_traits::ron;
|
||||
use rog_anime::error::AnimeError;
|
||||
use rog_platform::error::PlatformError;
|
||||
use rog_profiles::error::ProfileError;
|
||||
use std::convert::From;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RogError {
|
||||
@@ -30,11 +32,15 @@ pub enum RogError {
|
||||
NoAuraNode,
|
||||
Anime(AnimeError),
|
||||
Platform(PlatformError),
|
||||
SystemdUnitAction(String),
|
||||
SystemdUnitWaitTimeout(String),
|
||||
Command(String, std::io::Error),
|
||||
ParseRon(ron::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for RogError {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RogError::ParseVendor => write!(f, "Parse gfx vendor error"),
|
||||
RogError::ParseLed => write!(f, "Parse LED error"),
|
||||
@@ -47,19 +53,38 @@ impl fmt::Display for RogError {
|
||||
RogError::NotFound(deets) => write!(f, "Not found: {}", deets),
|
||||
RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
|
||||
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
|
||||
RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
|
||||
RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets),
|
||||
RogError::MissingLedBrightNode(path, error) => write!(
|
||||
f,
|
||||
"Led node at {} is missing, please check you have the required patch or dkms \
|
||||
module installed: {}",
|
||||
path, error
|
||||
),
|
||||
RogError::ReloadFail(deets) => write!(f, "Reload error: {}", deets),
|
||||
RogError::Profiles(deets) => write!(f, "Profile error: {}", deets),
|
||||
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
|
||||
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
|
||||
RogError::Io(detail) => write!(f, "std::io error: {}", detail),
|
||||
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
|
||||
RogError::ChargeLimit(value) => write!(f, "Invalid charging limit, not in range 20-100%: {}", value),
|
||||
RogError::ChargeLimit(value) => {
|
||||
write!(f, "Invalid charging limit, not in range 20-100%: {}", value)
|
||||
}
|
||||
RogError::AuraEffectNotSupported => write!(f, "Aura effect not supported"),
|
||||
RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"),
|
||||
RogError::NoAuraNode => write!(f, "No Aura keyboard node found"),
|
||||
RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets),
|
||||
RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets),
|
||||
RogError::SystemdUnitAction(action) => {
|
||||
write!(f, "systemd unit action {} failed", action)
|
||||
}
|
||||
RogError::SystemdUnitWaitTimeout(state) => {
|
||||
write!(
|
||||
f,
|
||||
"Timed out waiting for systemd unit change {} state",
|
||||
state
|
||||
)
|
||||
}
|
||||
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
|
||||
RogError::ParseRon(error) => write!(f, "Parse config error: {}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,6 +121,12 @@ impl From<std::io::Error> for RogError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ron::Error> for RogError {
|
||||
fn from(err: ron::Error) -> Self {
|
||||
RogError::ParseRon(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RogError> for zbus::fdo::Error {
|
||||
#[inline]
|
||||
fn from(err: RogError) -> Self {
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
use log::{info, warn};
|
||||
use rog_aura::{AuraModeNum, AuraZone};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Read;
|
||||
|
||||
pub const ASUS_LED_MODE_CONF: &str = "/etc/asusd/asusd-ledmodes.toml";
|
||||
pub const ASUS_LED_MODE_USER_CONF: &str = "/etc/asusd/asusd-user-ledmodes.toml";
|
||||
pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"];
|
||||
|
||||
pub fn print_board_info() {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||
|
||||
info!("Product family: {}", prod_family.trim());
|
||||
info!("Board name: {}", board_name.trim());
|
||||
}
|
||||
|
||||
pub fn print_modes(supported_modes: &[u8]) {
|
||||
if !supported_modes.is_empty() {
|
||||
info!("Supported Keyboard LED modes are:");
|
||||
for mode in supported_modes {
|
||||
let mode = <&str>::from(&<AuraModeNum>::from(*mode));
|
||||
info!("- {}", mode);
|
||||
}
|
||||
info!(
|
||||
"If these modes are incorrect you can edit {}",
|
||||
ASUS_LED_MODE_CONF
|
||||
);
|
||||
} else {
|
||||
info!("No RGB control available");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
struct LedSupportFile {
|
||||
led_data: Vec<LaptopLedData>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct LaptopLedData {
|
||||
pub prod_family: String,
|
||||
pub board_names: Vec<String>,
|
||||
pub standard: Vec<AuraModeNum>,
|
||||
pub multizone: Vec<AuraZone>,
|
||||
pub per_key: bool,
|
||||
}
|
||||
|
||||
impl LaptopLedData {
|
||||
pub fn get_data() -> Self {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||
|
||||
if let Some(modes) = LedSupportFile::load_from_config() {
|
||||
if let Some(data) = modes.matcher(&prod_family, &board_name) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
info!("Using generic LED control for keyboard brightness only");
|
||||
LaptopLedData {
|
||||
prod_family,
|
||||
board_names: vec![board_name],
|
||||
standard: vec![],
|
||||
multizone: vec![],
|
||||
per_key: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LedSupportFile {
|
||||
/// Consumes the LEDModes
|
||||
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
|
||||
for config in self.led_data {
|
||||
if prod_family.contains(&config.prod_family) {
|
||||
for board in &config.board_names {
|
||||
if board_name.contains(board) {
|
||||
info!("Matched to {} {}", config.prod_family, board);
|
||||
return Some(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn load_from_config() -> Option<Self> {
|
||||
let mut loaded = false;
|
||||
let mut data = LedSupportFile::default();
|
||||
// Load user configs first so they are first to be checked
|
||||
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_USER_CONF) {
|
||||
let mut buf = String::new();
|
||||
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||
if l == 0 {
|
||||
warn!("{} is empty", ASUS_LED_MODE_USER_CONF);
|
||||
} else {
|
||||
if let Ok(mut tmp) = toml::from_str::<LedSupportFile>(&buf) {
|
||||
data.led_data.append(&mut tmp.led_data);
|
||||
}
|
||||
info!(
|
||||
"Loaded user-defined LED support data from {}",
|
||||
ASUS_LED_MODE_USER_CONF
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load and append the default LED support data
|
||||
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_CONF) {
|
||||
let mut buf = String::new();
|
||||
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||
if l == 0 {
|
||||
warn!("{} is empty", ASUS_LED_MODE_CONF);
|
||||
} else {
|
||||
let mut tmp: LedSupportFile = toml::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", ASUS_LED_MODE_CONF));
|
||||
data.led_data.append(&mut tmp.led_data);
|
||||
loaded = true;
|
||||
info!(
|
||||
"Loaded default LED support data from {}",
|
||||
ASUS_LED_MODE_CONF
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if loaded {
|
||||
return Some(data);
|
||||
}
|
||||
|
||||
warn!("Does {} exist?", ASUS_LED_MODE_USER_CONF);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fs::OpenOptions, io::Read, path::PathBuf};
|
||||
|
||||
use super::LaptopLedData;
|
||||
use rog_aura::{AuraModeNum, AuraZone};
|
||||
|
||||
#[test]
|
||||
fn check_data_parse() {
|
||||
let led = LaptopLedData {
|
||||
prod_family: "Test".to_owned(),
|
||||
board_names: vec!["Test".to_owned()],
|
||||
standard: vec![AuraModeNum::Static],
|
||||
multizone: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft],
|
||||
per_key: false,
|
||||
};
|
||||
|
||||
let toml = toml::to_string_pretty(&led).unwrap();
|
||||
println!("{toml}");
|
||||
|
||||
let mut data = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
data.push("../data/asusd-ledmodes.toml");
|
||||
|
||||
let mut file = OpenOptions::new().read(true).open(&data).unwrap();
|
||||
let mut buf = String::new();
|
||||
file.read_to_string(&mut buf).unwrap();
|
||||
|
||||
let x = toml::to_string_pretty(&buf).unwrap();
|
||||
println!("{x}");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#![deny(unused_must_use)]
|
||||
/// Configuration loading, saving
|
||||
pub mod config;
|
||||
/// Control of AniMe matrix display
|
||||
/// Control of anime matrix display
|
||||
pub mod ctrl_anime;
|
||||
/// Keyboard LED brightness control, RGB, and LED display modes
|
||||
pub mod ctrl_aura;
|
||||
@@ -11,33 +11,97 @@ pub mod ctrl_platform;
|
||||
pub mod ctrl_power;
|
||||
/// Control platform profiles + fan-curves if available
|
||||
pub mod ctrl_profiles;
|
||||
/// Laptop matching to determine capabilities
|
||||
pub mod laptops;
|
||||
|
||||
/// Fetch all supported functions for the laptop
|
||||
pub mod ctrl_supported;
|
||||
|
||||
pub mod error;
|
||||
|
||||
use std::time::Duration;
|
||||
use std::future::Future;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, info, warn};
|
||||
use logind_zbus::manager::ManagerProxy;
|
||||
use zbus::export::futures_util::StreamExt;
|
||||
use zbus::zvariant::ObjectPath;
|
||||
use zbus::{Connection, SignalContext};
|
||||
|
||||
use crate::error::RogError;
|
||||
use async_trait::async_trait;
|
||||
use config::Config;
|
||||
use log::warn;
|
||||
use logind_zbus::manager::ManagerProxy;
|
||||
use smol::{stream::StreamExt, Executor, Timer};
|
||||
use zbus::Connection;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
const CONFIG_PATH_BASE: &str = "/etc/asusd/";
|
||||
|
||||
/// This macro adds a function which spawns an `inotify` task on the passed in
|
||||
/// `Executor`.
|
||||
///
|
||||
/// The generated function is `watch_<name>()`. Self requires the following
|
||||
/// methods to be available:
|
||||
/// - `<name>() -> SomeValue`, functionally is a getter, but is allowed to have
|
||||
/// side effects.
|
||||
/// - `notify_<name>(SignalContext, SomeValue)`
|
||||
///
|
||||
/// In most cases if `SomeValue` is stored in a config then `<name>()` getter is
|
||||
/// expected to update it. The getter should *never* write back to the path or
|
||||
/// attribute that is being watched or an infinite loop will occur.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// impl CtrlRogBios {
|
||||
/// task_watch_item!(panel_od platform);
|
||||
/// task_watch_item!(gpu_mux_mode platform);
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! task_watch_item {
|
||||
($name:ident $self_inner:ident) => {
|
||||
concat_idents::concat_idents!(fn_name = watch_, $name {
|
||||
async fn fn_name(
|
||||
&self,
|
||||
signal_ctxt: SignalContext<'static>,
|
||||
) -> Result<(), RogError> {
|
||||
use zbus::export::futures_util::StreamExt;
|
||||
|
||||
let ctrl = self.clone();
|
||||
concat_idents::concat_idents!(watch_fn = monitor_, $name {
|
||||
match self.$self_inner.watch_fn() {
|
||||
Ok(mut watch) => {
|
||||
tokio::spawn(async move {
|
||||
let mut buffer = [0; 32];
|
||||
watch.event_stream(&mut buffer).unwrap().for_each(|_| async {
|
||||
let value = ctrl.$name();
|
||||
concat_idents::concat_idents!(notif_fn = notify_, $name {
|
||||
Self::notif_fn(&signal_ctxt, value).await.ok();
|
||||
});
|
||||
}).await;
|
||||
});
|
||||
}
|
||||
Err(e) => info!("inotify watch failed: {}. You can ignore this if your device does not support the feature", e),
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
pub trait Reloadable {
|
||||
fn reload(&mut self) -> Result<(), RogError>;
|
||||
pub fn print_board_info() {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||
|
||||
info!("Product family: {}", prod_family.trim());
|
||||
info!("Board name: {}", board_name.trim());
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ZbusAdd {
|
||||
pub trait Reloadable {
|
||||
async fn reload(&mut self) -> Result<(), RogError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ZbusRun {
|
||||
async fn add_to_server(self, server: &mut Connection);
|
||||
|
||||
async fn add_to_server_helper(
|
||||
@@ -60,34 +124,58 @@ pub trait ZbusAdd {
|
||||
/// Set up a task to run on the async executor
|
||||
#[async_trait]
|
||||
pub trait CtrlTask {
|
||||
/// Implement to set up various tasks that may be required, using the `Executor`.
|
||||
/// No blocking loops are allowed, or they must be run on a separate thread.
|
||||
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError>;
|
||||
fn zbus_path() -> &'static str;
|
||||
|
||||
/// Create a timed repeating task
|
||||
async fn repeating_task(
|
||||
&self,
|
||||
millis: u64,
|
||||
executor: &mut Executor,
|
||||
mut task: impl FnMut() + Send + 'static,
|
||||
) {
|
||||
let timer = Timer::interval(Duration::from_millis(millis));
|
||||
executor
|
||||
.spawn(async move {
|
||||
timer.for_each(|_| task()).await;
|
||||
})
|
||||
.detach();
|
||||
fn signal_context(connection: &Connection) -> Result<SignalContext<'static>, zbus::Error> {
|
||||
SignalContext::new(connection, Self::zbus_path())
|
||||
}
|
||||
|
||||
/// Free helper method to create tasks to run on: sleep, wake, shutdown, boot
|
||||
async fn create_sys_event_tasks(
|
||||
/// Implement to set up various tasks that may be required, using the
|
||||
/// `Executor`. No blocking loops are allowed, or they must be run on a
|
||||
/// separate thread.
|
||||
async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>;
|
||||
|
||||
// /// Create a timed repeating task
|
||||
// async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send +
|
||||
// 'static) { use std::time::Duration;
|
||||
// use tokio::time;
|
||||
// let mut timer = time::interval(Duration::from_millis(millis));
|
||||
// tokio::spawn(async move {
|
||||
// timer.tick().await;
|
||||
// task();
|
||||
// });
|
||||
// }
|
||||
|
||||
/// Free helper method to create tasks to run on: sleep, wake, shutdown,
|
||||
/// boot
|
||||
///
|
||||
/// The closures can potentially block, so execution time should be the
|
||||
/// minimal possible such as save a variable.
|
||||
async fn create_sys_event_tasks<
|
||||
Fut1,
|
||||
Fut2,
|
||||
Fut3,
|
||||
Fut4,
|
||||
F1: Send + 'static,
|
||||
F2: Send + 'static,
|
||||
F3: Send + 'static,
|
||||
F4: Send + 'static,
|
||||
>(
|
||||
&self,
|
||||
executor: &mut Executor,
|
||||
mut on_sleep: impl FnMut() + Send + 'static,
|
||||
mut on_wake: impl FnMut() + Send + 'static,
|
||||
mut on_shutdown: impl FnMut() + Send + 'static,
|
||||
mut on_boot: impl FnMut() + Send + 'static,
|
||||
) {
|
||||
mut on_sleep: F1,
|
||||
mut on_wake: F2,
|
||||
mut on_shutdown: F3,
|
||||
mut on_boot: F4,
|
||||
) where
|
||||
F1: FnMut() -> Fut1,
|
||||
F2: FnMut() -> Fut2,
|
||||
F3: FnMut() -> Fut3,
|
||||
F4: FnMut() -> Fut4,
|
||||
Fut1: Future<Output = ()> + Send,
|
||||
Fut2: Future<Output = ()> + Send,
|
||||
Fut3: Future<Output = ()> + Send,
|
||||
Fut4: Future<Output = ()> + Send,
|
||||
{
|
||||
let connection = Connection::system()
|
||||
.await
|
||||
.expect("Controller could not create dbus connection");
|
||||
@@ -96,54 +184,44 @@ pub trait CtrlTask {
|
||||
.await
|
||||
.expect("Controller could not create ManagerProxy");
|
||||
|
||||
executor
|
||||
.spawn(async move {
|
||||
if let Ok(notif) = manager.receive_prepare_for_sleep().await {
|
||||
notif
|
||||
.for_each(|event| {
|
||||
if let Ok(args) = event.args() {
|
||||
if args.start {
|
||||
on_sleep();
|
||||
} else if !args.start() {
|
||||
on_wake();
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
tokio::spawn(async move {
|
||||
if let Ok(mut notif) = manager.receive_prepare_for_sleep().await {
|
||||
while let Some(event) = notif.next().await {
|
||||
if let Ok(args) = event.args() {
|
||||
if args.start {
|
||||
debug!("Doing on_sleep()");
|
||||
on_sleep().await;
|
||||
} else if !args.start() {
|
||||
debug!("Doing on_wake()");
|
||||
on_wake().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
});
|
||||
|
||||
let manager = ManagerProxy::new(&connection)
|
||||
.await
|
||||
.expect("Controller could not create ManagerProxy");
|
||||
|
||||
executor
|
||||
.spawn(async move {
|
||||
if let Ok(notif) = manager.receive_prepare_for_shutdown().await {
|
||||
notif
|
||||
.for_each(|event| {
|
||||
if let Ok(args) = event.args() {
|
||||
if args.start {
|
||||
on_shutdown();
|
||||
} else if !args.start() {
|
||||
on_boot();
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
tokio::spawn(async move {
|
||||
if let Ok(mut notif) = manager.receive_prepare_for_shutdown().await {
|
||||
while let Some(event) = notif.next().await {
|
||||
if let Ok(args) = event.args() {
|
||||
if args.start {
|
||||
debug!("Doing on_shutdown()");
|
||||
on_shutdown().await;
|
||||
} else if !args.start() {
|
||||
debug!("Doing on_boot()");
|
||||
on_boot().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CtrlTaskComplex {
|
||||
type A;
|
||||
|
||||
fn do_task(&mut self, config: &mut Config, event: Self::A);
|
||||
}
|
||||
|
||||
pub trait GetSupported {
|
||||
type A;
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
[Unit]
|
||||
Description=ASUS Notifications
|
||||
StartLimitInterval=200
|
||||
StartLimitBurst=2
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/sleep 2
|
||||
ExecStart=/usr/bin/asus-notify
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
Type=simple
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -1,183 +0,0 @@
|
||||
[[led_data]]
|
||||
prod_family = "TUF"
|
||||
board_names = ["FA507"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "TUF Gaming"
|
||||
board_names = ["FX505D"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus S"
|
||||
board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus M"
|
||||
board_names = ["GU502GV"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus M"
|
||||
board_names = ["GM501GS"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4"]
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus M15"
|
||||
board_names = ["GU502LW", "GU502LV"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus M15"
|
||||
board_names = ["GU502LU"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus S17"
|
||||
board_names = ["GX703HS"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus"
|
||||
board_names = ["GM501GM", "GX531"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4"]
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G531GW", "G533QR", "G533QS", "G733QS", "G733QR", "G513QR", "G713QR", "G513QM", "G713IC", "G713RS"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G513QE", "GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY", "G713QM", "G512", "G713RW"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4"]
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G512LI", "G712LI", "G531GD"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G513IM"]
|
||||
standard = ["Flash", "Static", "Breathe", "Strobe", "Rainbow"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Strix"
|
||||
board_names = ["G731GV", "G731GW", "G531GV"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4"]
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Strix"
|
||||
board_names = ["GL504G"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4", "Logo", "BarLeft", "BarRight"]
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Strix"
|
||||
board_names = ["G731GT", "G731GU", "G531GT", "G531GU"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "Strix Scar"
|
||||
board_names = ["G531", "G731"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4"]
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG"
|
||||
board_names = ["GL553VE"]
|
||||
standard = ["Static", "Breathe", "Strobe"]
|
||||
multizone = ["Key1", "Key2", "Key3", "Key4"]
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus G14"
|
||||
board_names = ["GA401Q"]
|
||||
standard = ["Static", "Breathe", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus G14"
|
||||
board_names = ["GA402R"]
|
||||
standard = ["Static", "Breathe", "Pulse", "Rainbow"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
# GA503QE at higher priority (first match) than GA503Q
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus G15"
|
||||
board_names = ["GA503QE"]
|
||||
standard = ["Static", "Breathe", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus G15"
|
||||
board_names = ["GA503Q", "GA503R"]
|
||||
standard = ["Static", "Breathe", "Pulse", "Rainbow", "Strobe"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus"
|
||||
board_names = ["GX550L"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus Duo 15 SE"
|
||||
board_names = ["GX551Q"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = []
|
||||
per_key = true
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Flow X13"
|
||||
board_names = ["GV301QH", "GV301QE"]
|
||||
standard = ["Static", "Breathe", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G513IC", "G513RC"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = []
|
||||
per_key = false
|
||||
@@ -9,6 +9,7 @@ ENV{DMI_FAMILY}=="*TUF*", GOTO="asusd_start"
|
||||
ENV{DMI_FAMILY}=="*ROG*", GOTO="asusd_start"
|
||||
ENV{DMI_FAMILY}=="*Zephyrus*", GOTO="asusd_start"
|
||||
ENV{DMI_FAMILY}=="*Strix*", GOTO="asusd_start"
|
||||
ENV{DMI_FAMILY}=="*Vivo*ook*", GOTO="asusd_start"
|
||||
# No match so
|
||||
GOTO="asusd_end"
|
||||
|
||||
@@ -16,4 +17,4 @@ LABEL="asusd_start"
|
||||
ACTION=="add|change", DRIVER=="asus-nb-wmi", TAG+="systemd", ENV{SYSTEMD_WANTS}="asusd.service"
|
||||
ACTION=="add|remove", DRIVER=="asus-nb-wmi", TAG+="systemd", RUN+="systemctl restart asusd.service"
|
||||
|
||||
LABEL="asusd_end"
|
||||
LABEL="asusd_end"
|
||||
|
||||
@@ -3,13 +3,15 @@ Description=ASUS Notebook Control
|
||||
StartLimitInterval=200
|
||||
StartLimitBurst=2
|
||||
Before=multi-user.target
|
||||
After=power-profiles-daemon.service
|
||||
After=nvidia-powerd.service
|
||||
|
||||
[Service]
|
||||
Environment=IS_SERVICE=1
|
||||
Environment=RUST_LOG="info"
|
||||
ExecStartPre=/bin/sleep 2
|
||||
ExecStart=/usr/bin/asusd
|
||||
Restart=on-failure
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
Type=dbus
|
||||
BusName=org.asuslinux.Daemon
|
||||
|
||||
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 74 KiB |
69
deny.toml
Normal file
@@ -0,0 +1,69 @@
|
||||
# https://embarkstudios.github.io/cargo-deny/
|
||||
|
||||
targets = [
|
||||
{ triple = "aarch64-apple-darwin" },
|
||||
{ triple = "aarch64-linux-android" },
|
||||
{ triple = "wasm32-unknown-unknown" },
|
||||
{ triple = "x86_64-apple-darwin" },
|
||||
{ triple = "x86_64-pc-windows-msvc" },
|
||||
{ triple = "x86_64-unknown-linux-gnu" },
|
||||
{ triple = "x86_64-unknown-linux-musl" },
|
||||
]
|
||||
|
||||
[advisories]
|
||||
vulnerability = "deny"
|
||||
unmaintained = "warn"
|
||||
yanked = "deny"
|
||||
ignore = [
|
||||
"RUSTSEC-2020-0071", # https://rustsec.org/advisories/RUSTSEC-2020-0071 - chrono/time: Potential segfault in the time crate
|
||||
"RUSTSEC-2020-0159", # https://rustsec.org/advisories/RUSTSEC-2020-0159 - chrono/time: Potential segfault in localtime_r invocations
|
||||
"RUSTSEC-2021-0127", # https://rustsec.org/advisories/RUSTSEC-2021-0127 - https://github.com/bheisler/criterion.rs/issues/534
|
||||
]
|
||||
|
||||
[bans]
|
||||
multiple-versions = "deny"
|
||||
wildcards = "allow" # at least until https://github.com/EmbarkStudios/cargo-deny/issues/241 is fixed
|
||||
deny = [
|
||||
{ name = "openssl" }, # prefer rustls
|
||||
{ name = "openssl-sys" }, # prefer rustls
|
||||
]
|
||||
|
||||
skip-tree = [
|
||||
{ name = "criterion" }, # dev-dependency
|
||||
{ name = "glium" }, # legacy crate, lots of old dependencies
|
||||
{ name = "rfd" }, # example dependency
|
||||
{ name = "three-d" }, # example dependency
|
||||
]
|
||||
|
||||
|
||||
[licenses]
|
||||
unlicensed = "deny"
|
||||
allow-osi-fsf-free = "neither"
|
||||
confidence-threshold = 0.92 # We want really high confidence when inferring licenses from text
|
||||
copyleft = "deny"
|
||||
allow = [
|
||||
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
|
||||
"BSD-2-Clause", # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd)
|
||||
"BSD-3-Clause", # https://tldrlegal.com/license/bsd-3-clause-license-(revised)
|
||||
"BSL-1.0", # https://tldrlegal.com/license/boost-software-license-1.0-explained
|
||||
"CC0-1.0", # https://creativecommons.org/publicdomain/zero/1.0/
|
||||
"ISC", # https://tldrlegal.com/license/-isc-license
|
||||
"LicenseRef-UFL-1.0", # https://tldrlegal.com/license/ubuntu-font-license,-1.0 - no official SPDX, see https://github.com/emilk/egui/issues/2321
|
||||
"MIT", # https://tldrlegal.com/license/mit-license
|
||||
"MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/FAQ/ - see Q11
|
||||
"OFL-1.1", # https://spdx.org/licenses/OFL-1.1.html
|
||||
"OpenSSL", # https://www.openssl.org/source/license.html
|
||||
"Unicode-DFS-2016", # https://spdx.org/licenses/Unicode-DFS-2016.html
|
||||
"Zlib", # https://tldrlegal.com/license/zlib-libpng-license-(zlib)
|
||||
]
|
||||
|
||||
[[licenses.clarify]]
|
||||
name = "webpki"
|
||||
expression = "ISC"
|
||||
license-files = [{ path = "LICENSE", hash = 0x001c7e6c }]
|
||||
|
||||
[[licenses.clarify]]
|
||||
name = "ring"
|
||||
expression = "MIT AND ISC AND OpenSSL"
|
||||
license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
|
||||
|
||||
@@ -18,81 +18,112 @@ Then for each trait that is required a new struct is required that can have the
|
||||
|
||||
Main controller:
|
||||
|
||||
For a very simple controller that doesn't need exclusive access you can clone across threads
|
||||
|
||||
```rust
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlAnime {
|
||||
<things the controller requires>
|
||||
config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
// This is the task trait used for such things as file watches, or logind
|
||||
// notifications (boot/suspend/shutdown etc)
|
||||
impl crate::CtrlTask for CtrlAnime {}
|
||||
|
||||
// The trait to easily add the controller to Zbus to enable the zbus derived functions
|
||||
// to be polled, run, react etc.
|
||||
impl crate::ZbusAdd for CtrlAnime {}
|
||||
|
||||
impl CtrlAnime {}
|
||||
```
|
||||
|
||||
Otherwise, you will need to share the controller via mutex
|
||||
|
||||
```rust
|
||||
pub struct CtrlAnime {
|
||||
<things the controller requires>
|
||||
}
|
||||
// Like this
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlAnimeTask(Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
impl CtrlAnime {
|
||||
<functions the controller exposes>
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlAnimeZbus(Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
impl CtrlAnime {}
|
||||
```
|
||||
|
||||
The task trait. There are three ways to implement this:
|
||||
The task trait:
|
||||
|
||||
```rust
|
||||
// Mutex should always be async mutex
|
||||
pub struct CtrlAnimeTask(Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
impl crate::CtrlTask for CtrlAnimeTask {
|
||||
// This will run once only
|
||||
fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
if let Ok(lock) = self.inner.try_lock() {
|
||||
<some action>
|
||||
}
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let lock self.inner.lock().await;
|
||||
<some action>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This will run until the notification stream closes (which in most cases will be never)
|
||||
fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
let connection = Connection::system().await.unwrap();
|
||||
let manager = ManagerProxy::new(&connection).await.unwrap();
|
||||
|
||||
let inner = self.inner.clone();
|
||||
executor
|
||||
.spawn(async move {
|
||||
// A notification from logind dbus interface
|
||||
if let Ok(p) = manager.receive_prepare_for_sleep().await {
|
||||
// A stream that will continuously output events
|
||||
p.for_each(|_| {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
// Do stuff here
|
||||
}
|
||||
})
|
||||
.await;
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let inner1 = self.inner.clone();
|
||||
let inner2 = self.inner.clone();
|
||||
let inner3 = self.inner.clone();
|
||||
let inner4 = self.inner.clone();
|
||||
// This is a free method on CtrlTask trait
|
||||
self.create_sys_event_tasks(
|
||||
// Loop is required to try an attempt to get the mutex *without* blocking
|
||||
// other threads - it is possible to end up with deadlocks otherwise.
|
||||
move || loop {
|
||||
if let Some(lock) = inner1.try_lock() {
|
||||
run_action(true, lock, inner1.clone());
|
||||
break;
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
// This task will run every 500 milliseconds
|
||||
fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
|
||||
let inner = self.inner.clone();
|
||||
// This is a provided free trait to help set up a repeating task
|
||||
self.repeating_task(500, executor, move || {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
// Do stuff here
|
||||
}
|
||||
})
|
||||
},
|
||||
move || loop {
|
||||
if let Some(lock) = inner2.try_lock() {
|
||||
run_action(false, lock, inner2.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Some(lock) = inner3.try_lock() {
|
||||
run_action(true, lock, inner3.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
move || loop {
|
||||
if let Some(lock) = inner4.try_lock() {
|
||||
run_action(false, lock, inner4.clone());
|
||||
break;
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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>
|
||||
}
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
let lock = self.inner.lock().await;
|
||||
<some action>
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The Zbus requirements:
|
||||
|
||||
```rust
|
||||
pub struct CtrlAnimeZbus(Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
@@ -106,10 +137,9 @@ impl crate::ZbusAdd for CtrlAnimeZbus {
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlAnimeZbus {
|
||||
fn <zbus method>() {
|
||||
if let Ok(lock) = self.inner.try_lock() {
|
||||
<some action>
|
||||
}
|
||||
async fn <zbus method>() {
|
||||
let lock = self.inner.lock().await;
|
||||
<some action>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "rog_anime"
|
||||
version = "1.3.5"
|
||||
license = "MPL-2.0"
|
||||
version.workspace = true
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||
@@ -9,26 +9,30 @@ homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||
documentation = "https://docs.rs/rog-anime"
|
||||
description = "Types useful for translating images and other data for display on the ASUS AniMe Matrix display"
|
||||
keywords = ["ROG", "ASUS", "AniMe"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
exclude = ["data"]
|
||||
|
||||
[features]
|
||||
default = ["dbus", "detect"]
|
||||
dbus = ["zvariant", "zbus"]
|
||||
dbus = ["zbus"]
|
||||
detect = ["sysfs-class"]
|
||||
|
||||
[dependencies]
|
||||
png_pong = "^0.8.0"
|
||||
pix = "0.13"
|
||||
gif = "^0.11.2"
|
||||
log = "*"
|
||||
png_pong.workspace = true
|
||||
pix.workspace = true
|
||||
gif.workspace = true
|
||||
log.workspace = true
|
||||
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
|
||||
glam = { version = "^0.21.2", features = ["serde"] }
|
||||
glam.workspace = true
|
||||
|
||||
zvariant = { version = "^3.0", optional = true }
|
||||
zbus = { version = "^2.2", optional = true }
|
||||
zbus = { workspace = true, optional = true }
|
||||
|
||||
sysfs-class = { version = "^0.1", optional = true }
|
||||
sysfs-class = { workspace = true, optional = true }
|
||||
|
||||
uhid-virt = "^0.0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
cargo-husky.workspace = true
|
||||
@@ -1,20 +1,17 @@
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use log::info;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[cfg(feature = "dbus")]
|
||||
use zvariant::Type;
|
||||
use zbus::zvariant::Type;
|
||||
|
||||
use crate::{
|
||||
error::{AnimeError, Result},
|
||||
AnimTime, AnimeGif,
|
||||
};
|
||||
use crate::error::{AnimeError, Result};
|
||||
use crate::{AnimTime, AnimeGif};
|
||||
|
||||
/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and `USB_PREFIX2`
|
||||
/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and
|
||||
/// `USB_PREFIX2`
|
||||
const BLOCK_START: usize = 7;
|
||||
/// *Not* inclusive, the byte before this is the final for each "pane"
|
||||
const BLOCK_END: usize = 634;
|
||||
@@ -29,7 +26,7 @@ const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
|
||||
const USB_PREFIX3: [u8; 7] = [0x5e, 0xc0, 0x02, 0xe7, 0x04, 0x73, 0x02];
|
||||
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
|
||||
pub struct AnimePowerStates {
|
||||
pub brightness: u8,
|
||||
pub enabled: bool,
|
||||
@@ -47,8 +44,7 @@ impl AnimeType {
|
||||
/// The width of diagonal images
|
||||
pub fn width(&self) -> usize {
|
||||
match self {
|
||||
AnimeType::GA401 => 74,
|
||||
AnimeType::GA402 => 74,
|
||||
AnimeType::GA401 | AnimeType::GA402 => 74,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +99,8 @@ impl AnimeDataBuffer {
|
||||
|
||||
/// Create from a vector of bytes
|
||||
///
|
||||
/// # Panics
|
||||
/// Will panic if the vector length is not `ANIME_DATA_LEN`
|
||||
/// # Errors
|
||||
/// Will error if the vector length is not `ANIME_DATA_LEN`
|
||||
#[inline]
|
||||
pub fn from_vec(anime: AnimeType, data: Vec<u8>) -> Result<Self> {
|
||||
if data.len() != anime.data_length() {
|
||||
@@ -144,13 +140,12 @@ impl TryFrom<AnimeDataBuffer> for AnimePacketType {
|
||||
}
|
||||
}
|
||||
|
||||
/// This runs the animations as a blocking loop by using the `callback` to write data
|
||||
/// This runs the animations as a blocking loop by using the `callback` to write
|
||||
/// data
|
||||
///
|
||||
/// If `callback` is `Ok(true)` then `run_animation` will exit the animation loop early.
|
||||
pub fn run_animation(
|
||||
frames: &AnimeGif,
|
||||
callback: &dyn Fn(AnimeDataBuffer) -> Result<bool>,
|
||||
) -> Result<()> {
|
||||
/// If `callback` is `Ok(true)` then `run_animation` will exit the animation
|
||||
/// loop early.
|
||||
pub fn run_animation(frames: &AnimeGif, callback: &dyn Fn(AnimeDataBuffer) -> Result<bool>) {
|
||||
let mut count = 0;
|
||||
let start = Instant::now();
|
||||
|
||||
@@ -215,9 +210,10 @@ pub fn run_animation(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Log this error
|
||||
if matches!(callback(output), Ok(true)) {
|
||||
info!("rog-anime: frame-loop callback asked to exit early");
|
||||
return Ok(());
|
||||
info!("rog-anime: animation frame-loop callback asked to exit early");
|
||||
return;
|
||||
}
|
||||
|
||||
if timed && Instant::now().duration_since(start) > run_time {
|
||||
@@ -232,5 +228,4 @@ pub fn run_animation(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::{path::Path, time::Duration};
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{
|
||||
data::AnimeDataBuffer,
|
||||
error::{AnimeError, Result},
|
||||
AnimeType,
|
||||
};
|
||||
use crate::data::AnimeDataBuffer;
|
||||
use crate::error::{AnimeError, Result};
|
||||
use crate::AnimeType;
|
||||
|
||||
/// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images)
|
||||
/// Mostly intended to be used with ASUS gifs, but can be used for other
|
||||
/// purposes (like images)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AnimeDiagonal(AnimeType, Vec<Vec<u8>>, Option<Duration>);
|
||||
|
||||
@@ -25,7 +25,8 @@ impl AnimeDiagonal {
|
||||
&mut self.1
|
||||
}
|
||||
|
||||
/// Get a full diagonal row where `x` `y` is the starting point and `len` is the length of data.
|
||||
/// Get a full diagonal row where `x` `y` is the starting point and `len`
|
||||
/// is the length of data.
|
||||
fn get_row(&self, x: usize, y: usize, len: usize) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(len);
|
||||
for i in 0..len {
|
||||
@@ -36,8 +37,9 @@ impl AnimeDiagonal {
|
||||
buf
|
||||
}
|
||||
|
||||
/// Generate the base image from inputs. The result can be displayed as is or
|
||||
/// updated via scale, position, or angle then displayed again after `update()`.
|
||||
/// Generate the base image from inputs. The result can be displayed as is
|
||||
/// or updated via scale, position, or angle then displayed again after
|
||||
/// `update()`.
|
||||
#[inline]
|
||||
pub fn from_png(
|
||||
path: &Path,
|
||||
@@ -52,39 +54,43 @@ impl AnimeDiagonal {
|
||||
|
||||
let mut matrix = AnimeDiagonal::new(anime_type, duration);
|
||||
|
||||
match raster {
|
||||
match &raster {
|
||||
png_pong::PngRaster::Gray8(ras) => {
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, true)
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, true);
|
||||
}
|
||||
png_pong::PngRaster::Graya8(ras) => {
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, true)
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, true);
|
||||
}
|
||||
png_pong::PngRaster::Rgb8(ras) => {
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, false)
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, false);
|
||||
}
|
||||
png_pong::PngRaster::Rgba8(ras) => {
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, false)
|
||||
Self::pixels_from_8bit(ras, &mut matrix, bright, false);
|
||||
}
|
||||
png_pong::PngRaster::Gray16(ras) => {
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, true)
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, true);
|
||||
}
|
||||
png_pong::PngRaster::Rgb16(ras) => {
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, false)
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, false);
|
||||
}
|
||||
png_pong::PngRaster::Graya16(ras) => {
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, true)
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, true);
|
||||
}
|
||||
png_pong::PngRaster::Rgba16(ras) => {
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, false)
|
||||
Self::pixels_from_16bit(ras, &mut matrix, bright, false);
|
||||
}
|
||||
_ => return Err(AnimeError::Format),
|
||||
png_pong::PngRaster::Palette(..) => return Err(AnimeError::Format),
|
||||
};
|
||||
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn pixels_from_8bit<P>(ras: pix::Raster<P>, matrix: &mut AnimeDiagonal, bright: f32, grey: bool)
|
||||
where
|
||||
fn pixels_from_8bit<P>(
|
||||
ras: &pix::Raster<P>,
|
||||
matrix: &mut AnimeDiagonal,
|
||||
bright: f32,
|
||||
grey: bool,
|
||||
) where
|
||||
P: pix::el::Pixel<Chan = pix::chan::Ch8>,
|
||||
{
|
||||
let width = ras.width();
|
||||
@@ -105,7 +111,7 @@ impl AnimeDiagonal {
|
||||
}
|
||||
|
||||
fn pixels_from_16bit<P>(
|
||||
ras: pix::Raster<P>,
|
||||
ras: &pix::Raster<P>,
|
||||
matrix: &mut AnimeDiagonal,
|
||||
bright: f32,
|
||||
grey: bool,
|
||||
@@ -131,14 +137,14 @@ impl AnimeDiagonal {
|
||||
#[inline]
|
||||
pub fn into_data_buffer(&self, anime_type: AnimeType) -> Result<AnimeDataBuffer> {
|
||||
match anime_type {
|
||||
AnimeType::GA401 => self.into_ga401_packets(),
|
||||
AnimeType::GA402 => self.into_ga402_packets(),
|
||||
AnimeType::GA401 => self.to_ga401_packets(),
|
||||
AnimeType::GA402 => self.to_ga402_packets(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Do conversion from the nested Vec in AnimeMatrix to the two required
|
||||
/// Do conversion from the nested Vec in `AnimeMatrix` to the two required
|
||||
/// packets suitable for sending over USB
|
||||
fn into_ga401_packets(&self) -> Result<AnimeDataBuffer> {
|
||||
fn to_ga401_packets(&self) -> Result<AnimeDataBuffer> {
|
||||
let mut buf = vec![0u8; AnimeType::GA401.data_length()];
|
||||
|
||||
buf[1..=32].copy_from_slice(&self.get_row(0, 3, 32));
|
||||
@@ -200,12 +206,12 @@ impl AnimeDiagonal {
|
||||
AnimeDataBuffer::from_vec(crate::AnimeType::GA401, buf)
|
||||
}
|
||||
|
||||
fn into_ga402_packets(&self) -> Result<AnimeDataBuffer> {
|
||||
fn to_ga402_packets(&self) -> Result<AnimeDataBuffer> {
|
||||
let mut buf = vec![0u8; AnimeType::GA402.data_length()];
|
||||
let mut start_index: usize = 0;
|
||||
|
||||
fn copy_slice(
|
||||
buf: &mut Vec<u8>,
|
||||
buf: &mut [u8],
|
||||
anime: &AnimeDiagonal,
|
||||
x: usize,
|
||||
y: usize,
|
||||
@@ -286,7 +292,8 @@ impl AnimeDiagonal {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{convert::TryFrom, path::PathBuf};
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{AnimeDiagonal, AnimePacketType, AnimeType};
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use gif::DecodingError;
|
||||
use png_pong::decode::Error as PngError;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
use gif::DecodingError;
|
||||
use png_pong::decode::Error as PngError;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, AnimeError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -12,7 +13,8 @@ pub enum AnimeError {
|
||||
Png(PngError),
|
||||
Gif(DecodingError),
|
||||
Format,
|
||||
/// 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),
|
||||
Dbus(String),
|
||||
Udev(String, std::io::Error),
|
||||
@@ -26,7 +28,7 @@ pub enum AnimeError {
|
||||
|
||||
impl fmt::Display for AnimeError {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AnimeError::NoFrames => write!(f, "No frames in PNG"),
|
||||
AnimeError::Io(e) => write!(f, "Could not open: {}", e),
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use glam::Vec2;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::{fs::File, path::Path, time::Duration};
|
||||
|
||||
use crate::error::AnimeError;
|
||||
use crate::{error::Result, AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel};
|
||||
use crate::error::{AnimeError, Result};
|
||||
use crate::{AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AnimeFrame {
|
||||
/// Precomputed data for the frame. This can be transferred directly to the
|
||||
/// the `asusd` daemon over dbus or converted to USB packet with `AnimePacketType::from(buffer)`
|
||||
/// the `asusd` daemon over dbus or converted to USB packet with
|
||||
/// `AnimePacketType::from(buffer)`
|
||||
data: AnimeDataBuffer,
|
||||
delay: Duration,
|
||||
}
|
||||
@@ -33,7 +37,8 @@ impl AnimeFrame {
|
||||
pub enum AnimTime {
|
||||
/// Time in milliseconds for animation to run
|
||||
Time(Duration),
|
||||
/// How many full animation loops to run or how many seconds if image is static
|
||||
/// How many full animation loops to run or how many seconds if image is
|
||||
/// static
|
||||
Count(u32),
|
||||
/// Run for infinite time
|
||||
Infinite,
|
||||
@@ -169,8 +174,8 @@ impl AnimeGif {
|
||||
Ok(Self(frames, duration))
|
||||
}
|
||||
|
||||
/// Create an animation using a gif of any size. This method must precompute the
|
||||
/// result.
|
||||
/// Create an animation using a gif of any size. This method must precompute
|
||||
/// the result.
|
||||
#[inline]
|
||||
pub fn from_gif(
|
||||
file_name: &Path,
|
||||
@@ -243,9 +248,10 @@ impl AnimeGif {
|
||||
Ok(Self(frames, duration))
|
||||
}
|
||||
|
||||
/// Make a static gif out of a greyscale png. If no duration is specified then the default
|
||||
/// will be 1 second long. If `AnimTime::Cycles` is specified for `duration` then this can
|
||||
/// be considered how many seconds the image will show for.
|
||||
/// Make a static gif out of a greyscale png. If no duration is specified
|
||||
/// then the default will be 1 second long. If `AnimTime::Cycles` is
|
||||
/// specified for `duration` then this can be considered how many
|
||||
/// seconds the image will show for.
|
||||
#[inline]
|
||||
pub fn from_png(
|
||||
file_name: &Path,
|
||||
|
||||
@@ -93,7 +93,7 @@ impl AnimeGrid {
|
||||
impl TryFrom<AnimeGrid> for AnimeDataBuffer {
|
||||
type Error = AnimeError;
|
||||
|
||||
/// Do conversion from the nested Vec in AniMeMatrix to the two required
|
||||
/// Do conversion from the nested Vec in anime matrix to the two required
|
||||
/// packets suitable for sending over USB
|
||||
fn try_from(anime: AnimeGrid) -> Result<Self> {
|
||||
let mut buf = vec![0u8; anime.anime_type.data_length()];
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use std::{convert::TryFrom, path::Path};
|
||||
use std::convert::TryFrom;
|
||||
use std::path::Path;
|
||||
|
||||
pub use glam::Vec2;
|
||||
use glam::{Mat3, Vec3};
|
||||
|
||||
use crate::{
|
||||
data::AnimeDataBuffer,
|
||||
error::{AnimeError, Result},
|
||||
AnimeType,
|
||||
};
|
||||
use crate::data::AnimeDataBuffer;
|
||||
use crate::error::{AnimeError, Result};
|
||||
use crate::AnimeType;
|
||||
|
||||
/// A single greyscale + alpha pixel in the image
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -29,8 +28,8 @@ impl Default for Pixel {
|
||||
/// A single LED position and brightness. The intention of this struct
|
||||
/// is to be used to sample an image and set the LED brightness.
|
||||
///
|
||||
/// The position of the Led in `LedPositions` determines the placement in the final
|
||||
/// data packets when written to the AniMe.
|
||||
/// The position of the Led in `LedPositions` determines the placement in the
|
||||
/// final data packets when written to the `AniMe`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Led(f32, f32, u8);
|
||||
|
||||
@@ -58,7 +57,7 @@ impl Led {
|
||||
|
||||
/// Container of `Led`, each of which specifies a position within the image
|
||||
/// The main use of this is to position and sample colours for the final image
|
||||
/// to show on AniMe
|
||||
/// to show on `AniMe`
|
||||
pub struct AnimeImage {
|
||||
pub scale: Vec2,
|
||||
/// Angle in radians
|
||||
@@ -73,8 +72,9 @@ pub struct AnimeImage {
|
||||
img_pixels: Vec<Pixel>,
|
||||
/// width of the image
|
||||
width: u32,
|
||||
/// The type of the display. The GA401 and GA402 use the same controller and therefore same ID,
|
||||
/// so the identifier must be by laptop model in `AnimeType`.
|
||||
/// The type of the display. The GA401 and GA402 use the same controller and
|
||||
/// therefore same ID, so the identifier must be by laptop model in
|
||||
/// `AnimeType`.
|
||||
anime_type: AnimeType,
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ impl AnimeImage {
|
||||
width: u32,
|
||||
anime_type: AnimeType,
|
||||
) -> Result<Self> {
|
||||
if bright < 0.0 || bright > 1.0 {
|
||||
if !(0.0..=1.0).contains(&bright) {
|
||||
return Err(AnimeError::InvalidBrightness(bright));
|
||||
}
|
||||
|
||||
@@ -108,9 +108,9 @@ impl AnimeImage {
|
||||
|
||||
/// Scale ratio in CM
|
||||
///
|
||||
/// This is worked out by measuring the physical width of the display from pixel center to
|
||||
/// center, then dividing by `<horizontal LED count> + 0.5`, where the LED count is
|
||||
/// first/longest row.
|
||||
/// This is worked out by measuring the physical width of the display from
|
||||
/// pixel center to center, then dividing by `<horizontal LED count> +
|
||||
/// 0.5`, where the LED count is first/longest row.
|
||||
///
|
||||
/// For GA401 this is `26.8 / (33 + 0.5) = 0.8`
|
||||
/// For GA402 this is `27.4 / (35 + 0.5) = 0.77`
|
||||
@@ -123,9 +123,9 @@ impl AnimeImage {
|
||||
|
||||
/// Scale ratio in CM
|
||||
///
|
||||
/// This is worked out by measuring the physical height of the display from pixel center to
|
||||
/// pixel center, then dividing by `<vertical LED count> + 1.0`, where the LED count is
|
||||
/// first/longest row.
|
||||
/// This is worked out by measuring the physical height of the display from
|
||||
/// pixel center to pixel center, then dividing by `<vertical LED
|
||||
/// count> + 1.0`, where the LED count is first/longest row.
|
||||
///
|
||||
/// For GA401 this is `16.5 / (54.0 + 1.0) = 0.3`
|
||||
/// For GA402 this is `17.3 / (61.0) = 0.283`
|
||||
@@ -136,11 +136,13 @@ impl AnimeImage {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the starting X position for the data we actually require when writing
|
||||
/// it out to LEDs.
|
||||
/// Get the starting X position for the data we actually require when
|
||||
/// writing it out to LEDs.
|
||||
///
|
||||
/// In relation to the display itself you should think of it as a full
|
||||
/// square grid, so `first_x` is the x position on that grid where the
|
||||
/// LED is actually positioned in relation to the Y.
|
||||
///
|
||||
/// In relation to the display itself you should think of it as a full square grid, so `first_x`
|
||||
/// is the x position on that grid where the LED is actually positioned in relation to the Y.
|
||||
/// ```text
|
||||
/// +------------+
|
||||
/// | |
|
||||
@@ -251,8 +253,8 @@ impl AnimeImage {
|
||||
&mut self.img_pixels
|
||||
}
|
||||
|
||||
/// Generate a list of LED positions. These are then used to sample the Image data,
|
||||
/// and will contain their resulting brightness.
|
||||
/// Generate a list of LED positions. These are then used to sample the
|
||||
/// Image data, and will contain their resulting brightness.
|
||||
#[inline]
|
||||
pub fn generate_image_positioning(anime_type: AnimeType) -> Vec<Option<Led>> {
|
||||
(0..AnimeImage::height(anime_type))
|
||||
@@ -274,8 +276,8 @@ impl AnimeImage {
|
||||
/// samples, the result can then been transformed to the appropriate data
|
||||
/// for displaying.
|
||||
///
|
||||
/// The internal for loop iterates over the LED positions, skipping the blank/dead
|
||||
/// pixels if any.
|
||||
/// The internal for loop iterates over the LED positions, skipping the
|
||||
/// blank/dead pixels if any.
|
||||
#[inline]
|
||||
pub fn update(&mut self) {
|
||||
let width = self.width as i32;
|
||||
@@ -294,8 +296,8 @@ impl AnimeImage {
|
||||
let x0 = led_from_px.mul_vec3(pos + Vec3::new(0.0, -0.5, 0.0));
|
||||
|
||||
const GROUP: [f32; 4] = [0.0, 0.5, 1.0, 1.5];
|
||||
for u in GROUP.iter() {
|
||||
for v in GROUP.iter() {
|
||||
for u in &GROUP {
|
||||
for v in &GROUP {
|
||||
let sample = x0 + *u * du + *v * dv;
|
||||
|
||||
let x = sample.x as i32;
|
||||
@@ -343,7 +345,7 @@ impl AnimeImage {
|
||||
}
|
||||
last_was_led = true;
|
||||
} else if last_was_led {
|
||||
//ends.push(idx);
|
||||
// ends.push(idx);
|
||||
last_was_led = false;
|
||||
}
|
||||
}
|
||||
@@ -382,8 +384,9 @@ impl AnimeImage {
|
||||
led_from_px.inverse()
|
||||
}
|
||||
|
||||
/// Generate the base image from inputs. The result can be displayed as is or
|
||||
/// updated via scale, position, or angle then displayed again after `update()`.
|
||||
/// Generate the base image from inputs. The result can be displayed as is
|
||||
/// or updated via scale, position, or angle then displayed again after
|
||||
/// `update()`.
|
||||
#[inline]
|
||||
pub fn from_png(
|
||||
path: &Path,
|
||||
@@ -399,7 +402,7 @@ impl AnimeImage {
|
||||
let png_pong::Step { raster, delay: _ } = decoder.last().ok_or(AnimeError::NoFrames)??;
|
||||
|
||||
let width;
|
||||
let pixels = match raster {
|
||||
let pixels = match &raster {
|
||||
png_pong::PngRaster::Gray8(ras) => {
|
||||
width = ras.width();
|
||||
Self::pixels_from_8bit(ras, true)
|
||||
@@ -432,7 +435,7 @@ impl AnimeImage {
|
||||
width = ras.width();
|
||||
Self::pixels_from_16bit(ras, false)
|
||||
}
|
||||
_ => return Err(AnimeError::Format),
|
||||
png_pong::PngRaster::Palette(..) => return Err(AnimeError::Format),
|
||||
};
|
||||
|
||||
let mut matrix = AnimeImage::new(
|
||||
@@ -449,7 +452,7 @@ impl AnimeImage {
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn pixels_from_8bit<P>(ras: pix::Raster<P>, grey: bool) -> Vec<Pixel>
|
||||
fn pixels_from_8bit<P>(ras: &pix::Raster<P>, grey: bool) -> Vec<Pixel>
|
||||
where
|
||||
P: pix::el::Pixel<Chan = pix::chan::Ch8>,
|
||||
{
|
||||
@@ -468,7 +471,7 @@ impl AnimeImage {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn pixels_from_16bit<P>(ras: pix::Raster<P>, grey: bool) -> Vec<Pixel>
|
||||
fn pixels_from_16bit<P>(ras: &pix::Raster<P>, grey: bool) -> Vec<Pixel>
|
||||
where
|
||||
P: pix::el::Pixel<Chan = pix::chan::Ch16>,
|
||||
{
|
||||
@@ -491,8 +494,8 @@ impl AnimeImage {
|
||||
impl TryFrom<&AnimeImage> for AnimeDataBuffer {
|
||||
type Error = AnimeError;
|
||||
|
||||
/// Do conversion from the nested Vec in AnimeDataBuffer to the two required
|
||||
/// packets suitable for sending over USB
|
||||
/// Do conversion from the nested Vec in `AnimeDataBuffer` to the two
|
||||
/// required packets suitable for sending over USB
|
||||
fn try_from(leds: &AnimeImage) -> Result<Self> {
|
||||
let mut l: Vec<u8> = leds
|
||||
.led_pos
|
||||
@@ -511,9 +514,11 @@ impl TryFrom<&AnimeImage> for AnimeDataBuffer {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{convert::TryFrom, path::PathBuf};
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{image::*, AnimTime, AnimeGif, AnimePacketType};
|
||||
use crate::image::*;
|
||||
use crate::{AnimTime, AnimeGif, AnimePacketType};
|
||||
|
||||
#[test]
|
||||
fn led_positions() {
|
||||
|
||||
@@ -7,12 +7,12 @@ pub use data::*;
|
||||
mod grid;
|
||||
pub use grid::*;
|
||||
|
||||
/// Transform a PNG image for displaying on AniMe matrix display
|
||||
/// Transform a PNG image for displaying on `AniMe` matrix display
|
||||
mod image;
|
||||
pub use image::*;
|
||||
|
||||
/// A grid of data that is intended to be read out and displayed on the ANiMe as
|
||||
/// a diagonal
|
||||
/// A grid of data that is intended to be read out and displayed on the `AniMe`
|
||||
/// as a diagonal
|
||||
mod diagonal;
|
||||
pub use diagonal::*;
|
||||
|
||||
@@ -21,8 +21,8 @@ pub use diagonal::*;
|
||||
mod gif;
|
||||
pub use crate::gif::*;
|
||||
|
||||
/// A container of images/grids/gifs/pauses which can be iterated over to generate
|
||||
/// cool effects
|
||||
/// A container of images/grids/gifs/pauses which can be iterated over to
|
||||
/// generate cool effects
|
||||
mod sequencer;
|
||||
pub use sequencer::*;
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use glam::Vec2;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
|
||||
use crate::{
|
||||
error::Result, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType,
|
||||
};
|
||||
use crate::error::Result;
|
||||
use crate::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType};
|
||||
|
||||
/// All the possible AniMe actions that can be used. This enum is intended to be
|
||||
/// a helper for loading up `ActionData`.
|
||||
/// All the possible `AniMe` actions that can be used. This enum is intended to
|
||||
/// be a helper for loading up `ActionData`.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum ActionLoader {
|
||||
/// Full gif sequence. Immutable.
|
||||
@@ -23,7 +24,8 @@ pub enum ActionLoader {
|
||||
time: AnimTime,
|
||||
brightness: f32,
|
||||
},
|
||||
/// Animated gif. If the file is a png a static gif is created using the `time` properties
|
||||
/// Animated gif. If the file is a png a static gif is created using the
|
||||
/// `time` properties
|
||||
ImageAnimation {
|
||||
file: PathBuf,
|
||||
scale: f32,
|
||||
@@ -44,13 +46,14 @@ pub enum ActionLoader {
|
||||
Pause(Duration),
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// 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, Clone, Deserialize, Serialize)]
|
||||
pub enum ActionData {
|
||||
/// Full gif sequence. Immutable.
|
||||
Animation(AnimeGif),
|
||||
/// Basic image, can have properties changed and image updated via those properties
|
||||
/// Basic image, can have properties changed and image updated via those
|
||||
/// properties
|
||||
Image(Box<AnimeDataBuffer>),
|
||||
/// A pause to be used between sequences
|
||||
Pause(Duration),
|
||||
@@ -174,8 +177,8 @@ impl Sequences {
|
||||
Self(Vec::new(), anime_type)
|
||||
}
|
||||
|
||||
/// Use a base `AnimeAction` to generate the precomputed data and insert in to
|
||||
/// the run buffer
|
||||
/// Use a base `AnimeAction` to generate the precomputed data and insert in
|
||||
/// to the run buffer
|
||||
#[inline]
|
||||
pub fn insert(&mut self, index: usize, action: &ActionLoader) -> Result<()> {
|
||||
self.0
|
||||
@@ -183,9 +186,9 @@ impl Sequences {
|
||||
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.
|
||||
/// 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() {
|
||||
@@ -194,7 +197,7 @@ impl Sequences {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> ActionIterator {
|
||||
pub fn iter(&self) -> ActionIterator<'_> {
|
||||
ActionIterator {
|
||||
actions: self,
|
||||
next_idx: 0,
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
//! Utils for writing to the AniMe USB device
|
||||
//! Utils for writing to the `AniMe` USB device
|
||||
//!
|
||||
//! Use of the device requires a few steps:
|
||||
//! 1. Initialise the device by writing the two packets from `get_init_packets()`
|
||||
//! 2. Write data from `AnimePacketType`
|
||||
//! 3. Write the packet from `get_flush_packet()`, which tells the device to display the data from step 2
|
||||
//! 1. Initialise the device by writing the two packets from
|
||||
//! `get_init_packets()` 2. Write data from `AnimePacketType`
|
||||
//! 3. Write the packet from `get_flush_packet()`, which tells the device to
|
||||
//! display the data from step 2
|
||||
//!
|
||||
//! Step 1 need to applied only on fresh system boot.
|
||||
|
||||
use crate::{error::AnimeError, AnimeType};
|
||||
use crate::error::AnimeError;
|
||||
use crate::AnimeType;
|
||||
|
||||
const INIT_STR: [u8; 15] = [
|
||||
0x5e, b'A', b'S', b'U', b'S', b' ', b'T', b'e', b'c', b'h', b'.', b'I', b'n', b'c', b'.',
|
||||
@@ -17,8 +19,9 @@ const DEV_PAGE: u8 = 0x5e;
|
||||
pub const VENDOR_ID: u16 = 0x0b05;
|
||||
pub const PROD_ID: u16 = 0x193b;
|
||||
|
||||
/// `get_anime_type` is very broad, matching on part of the laptop board name only. For this
|
||||
/// reason `find_node()` must be used also to verify if the USB device is available.
|
||||
/// `get_anime_type` is very broad, matching on part of the laptop board name
|
||||
/// only. For this reason `find_node()` must be used also to verify if the USB
|
||||
/// device is available.
|
||||
///
|
||||
/// The currently known USB device is `19b6`.
|
||||
#[inline]
|
||||
@@ -26,9 +29,7 @@ pub fn get_anime_type() -> Result<AnimeType, AnimeError> {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
let board_name = dmi.board_name()?;
|
||||
|
||||
if board_name.contains("GA401I") {
|
||||
return Ok(AnimeType::GA401);
|
||||
} else if board_name.contains("GA401Q") {
|
||||
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
|
||||
return Ok(AnimeType::GA401);
|
||||
} else if board_name.contains("GA402R") {
|
||||
return Ok(AnimeType::GA402);
|
||||
@@ -36,8 +37,8 @@ pub fn get_anime_type() -> Result<AnimeType, AnimeError> {
|
||||
Err(AnimeError::UnsupportedDevice)
|
||||
}
|
||||
|
||||
/// Get the two device initialization packets. These are required for device start
|
||||
/// after the laptop boots.
|
||||
/// Get the two device initialization packets. These are required for device
|
||||
/// start after the laptop boots.
|
||||
#[inline]
|
||||
pub const fn pkts_for_init() -> [[u8; PACKET_SIZE]; 2] {
|
||||
let mut packets = [[0; PACKET_SIZE]; 2];
|
||||
@@ -65,7 +66,7 @@ pub const fn pkt_for_flush() -> [u8; PACKET_SIZE] {
|
||||
}
|
||||
|
||||
/// Get the packet required for setting the device to on, on boot. Requires
|
||||
/// pkt_for_apply()` to be written after.
|
||||
/// `pkt_for_apply()` to be written after.
|
||||
#[inline]
|
||||
pub const fn pkt_for_set_boot(status: bool) -> [u8; PACKET_SIZE] {
|
||||
let mut pkt = [0; PACKET_SIZE];
|
||||
@@ -76,8 +77,8 @@ pub const fn pkt_for_set_boot(status: bool) -> [u8; PACKET_SIZE] {
|
||||
pkt
|
||||
}
|
||||
|
||||
/// Get the packet required for setting the device to on. Requires `pkt_for_apply()`
|
||||
/// to be written after.
|
||||
/// Get the packet required for setting the device to on. Requires
|
||||
/// `pkt_for_apply()` to be written after.
|
||||
#[inline]
|
||||
pub const fn pkt_for_set_on(on: bool) -> [u8; PACKET_SIZE] {
|
||||
let mut pkt = [0; PACKET_SIZE];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "rog_aura"
|
||||
version = "1.3.3"
|
||||
license = "MPL-2.0"
|
||||
version.workspace = true
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
repository = "https://gitlab.com/asus-linux/asusctl"
|
||||
@@ -9,18 +9,25 @@ 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"
|
||||
edition = "2021"
|
||||
exclude = ["data"]
|
||||
|
||||
[features]
|
||||
default = ["dbus", "toml"]
|
||||
dbus = ["zvariant"]
|
||||
default = ["dbus", "ron"]
|
||||
dbus = ["zbus"]
|
||||
|
||||
[dependencies]
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
toml = { version = "^0.5", optional = true }
|
||||
zvariant = { version = "^3.0", optional = true }
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
zbus = { workspace = true, optional = true }
|
||||
|
||||
# cli and logging
|
||||
log.workspace = true
|
||||
|
||||
# Device control
|
||||
sysfs-class.workspace = true # used for backlight control and baord ID
|
||||
|
||||
ron = { version = "*", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "^1.0"
|
||||
cargo-husky.workspace = true
|
||||
@@ -0,0 +1,246 @@
|
||||
# rog-aura
|
||||
|
||||
## What is it?
|
||||
|
||||
rog-aura is a helper crate for interacting with the RGB keyboards found on many ASUS ROG gaming laptops such as the Zephyrus, Strix, TUF, and a few others.
|
||||
|
||||
The crate is primarily used in the asusctl suite of tools.
|
||||
|
||||
The majority of the crate deals with converting from the API to USB packets suitable for sending raw to the USB device.
|
||||
|
||||
## Features
|
||||
|
||||
- Detect USB keyboard type, or if the kayboard is an I2C connected one (typical on TUF)
|
||||
- Set various basic modes
|
||||
- Set various basic zones
|
||||
- Set advanced/direct addressing of:
|
||||
+ Single zone
|
||||
+ Multizone
|
||||
+ Per-key
|
||||
- Physical layout mapping
|
||||
|
||||
## Config files
|
||||
|
||||
The crate includes config files for helping to determine what laptop models support what feature. This is heavily dependant on folks testing and contributing data.
|
||||
|
||||
It also includes layouts for some laptops. Also heavily dependant on contributions.
|
||||
|
||||
# Support list
|
||||
|
||||
`aura_support.ron` is the support listing file. It functions as a database of which models support which features.
|
||||
|
||||
```ron
|
||||
(
|
||||
board_name: "G513QR",
|
||||
layout_name: "g513i-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
```
|
||||
|
||||
in the above example the board name is found from `cat /sys/devices/virtual/dmi/id/board_name`. In some model ranges the last letter (which is likely the dGPU/feature variant) can be ommited. `layout_name` is the first part of a related filename for the layout as described in the next section - the filename should be postfixed with a locale such as `g513i_US.ron`.
|
||||
|
||||
`basic_modes` are the default inbuilt modes the keyboard supports. Not all keyboards have the same set of modes. `basic_zones` is a secondary part of `basic_modes` where this lists which zones can be set as part of the basic mode. Each zone reauires a full basic mode setting. The zones supported here are
|
||||
|
||||
- `Key1`
|
||||
- `Key2`
|
||||
- `Key3`
|
||||
- `Key4`
|
||||
- `Logo`
|
||||
- `BarLeft`
|
||||
- `BarRight`
|
||||
|
||||
note that the zone support seems to have changed with new generations of keyboards and is shifted to `advanced_type`. The `advanced_type` field is taken in to account when setting advanced effects. It can be combined with the keyboard layout also to be used in a GUI.
|
||||
|
||||
`advanced_type` can be one of:
|
||||
|
||||
- `None`, no advanced aura at all
|
||||
- `PerKey`, can use any of `LedCode` except for the `Zoned` items below which work in a different way
|
||||
- `Zoned`, takes an array such as:
|
||||
+ `Zoned([SingleZone])`, only one zone
|
||||
+ `Zoned([ ... ]),`, array with any combination of:
|
||||
- `ZonedKbLeft` // keyboard left
|
||||
- `ZonedKbLeftMid` // keyboard left-middle
|
||||
- `ZonedKbRightMid` // etc
|
||||
- `ZonedKbRight`
|
||||
- `LightbarRight`
|
||||
- `LightbarRightCorner`
|
||||
- `LightbarRightBottom`
|
||||
- `LightbarLeftBottom`
|
||||
- `LightbarLeftCorner`
|
||||
- `LightbarLeft`
|
||||
|
||||
# Layouts
|
||||
|
||||
The layout structure is kept in a `.ron`, which is "rusty object notation". The way this works is best demonstrated:
|
||||
|
||||
```ron
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
// This is a regular LED spot, it has a size (width x height), and padding around each edge.
|
||||
// The final size should be (width + pad_left + pad_right, height + pad_top + pad_bottom)
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
// There is nothing in this space but it takes up room
|
||||
"func_space": Blank(
|
||||
width: 0.2,
|
||||
height: 0.0,
|
||||
),
|
||||
// This backspace button is composed of 3 individual LED
|
||||
"backspace1": Led(
|
||||
width: 0.65,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.0,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backspace2": Led(
|
||||
width: 0.7,
|
||||
height: 1.0,
|
||||
pad_left: 0.0,
|
||||
pad_right: 0.0,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backspace3": Led(
|
||||
width: 0.65,
|
||||
height: 1.0,
|
||||
pad_left: 0.0,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
// Padding generally isn't required but is available just in case
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
// Each row is a horizontal row of keys of the keyboard
|
||||
row: [
|
||||
// Declare a tuple of `Key`, and the String name to use from the hashmap above
|
||||
(Spacing, "rog_spacer"),
|
||||
(VolDown, "rog_row"),
|
||||
(VolUp, "rog_row"),
|
||||
(MicMute, "rog_row"),
|
||||
(Rog, "rog_row"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
row: [
|
||||
(Esc, "func_key"),
|
||||
// There are two non-led types, `Blocking` which is intended to block something like a row-laser
|
||||
(Blocking, "esc_func_spacing"),
|
||||
(F1, "func_key"),
|
||||
(F2, "func_key"),
|
||||
(F3, "func_key"),
|
||||
(F4, "func_key"),
|
||||
// and `Spacing` which is intended to act like a non-visible LED
|
||||
(Spacing, "func_space"),
|
||||
(F5, "func_key"),
|
||||
(F6, "func_key"),
|
||||
(F7, "func_key"),
|
||||
(F8, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "func_key"),
|
||||
(F10, "func_key"),
|
||||
(F11, "func_key"),
|
||||
(F12, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(Del, "func_key"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace3_1, "backspace1"),
|
||||
(Backspace3_2, "backspace2"),
|
||||
(Backspace3_3, "backspace3"),
|
||||
(Spacing, "func_space"),
|
||||
(Home, "regular"),
|
||||
],
|
||||
),
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
**There are two types of layouts to be considered when building one; per-key, and zoned.**
|
||||
|
||||
A zoned keyboard layout includes single zoned + no zones (but not per-key). The layout for this is fairly freeform, and can be built using regular keys from `LedCode` but can not include these per-key specific codes:
|
||||
|
||||
- `LidLogo`
|
||||
- `LidLeft`
|
||||
- `LidRight`
|
||||
|
||||
it can include regular keys and:
|
||||
|
||||
- `SingleZone`, if this is used then the `ZonedKb*` should not be used
|
||||
- `ZonedKbLeft`
|
||||
- `ZonedKbLeftMid`
|
||||
- `ZonedKbRightMid`
|
||||
- `ZonedKbRight`
|
||||
- `LightbarRight`
|
||||
- `LightbarRightCorner`
|
||||
- `LightbarRightBottom`
|
||||
- `LightbarLeftBottom`
|
||||
- `LightbarLeftCorner`
|
||||
- `LightbarLeft`
|
||||
|
||||
#### `Key`
|
||||
|
||||
Every `Key` in the enum maps to a USB packet + RGB index in that packet. The raw mapping is seen in `per_key_raw_bytes.ods` in the data dir, for example there is a single LED backspace, and a 3-LED backspace.
|
||||
|
||||
#### `key_shapes`
|
||||
|
||||
This is a hashmap of `String`:`ShapeType`, as shown by the previous example such as:
|
||||
|
||||
```
|
||||
// This is a regular LED spot, it has a size (width x height), and padding around each edge.
|
||||
// The final size should be (width + pad_left + pad_right, height + pad_top + pad_bottom)
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
```
|
||||
|
||||
"regular" being the key used by the keys in each key row.
|
||||
|
||||
# Testing
|
||||
|
||||
When working with Rog Control Center you can test layouts by starting the app on CLI with options:
|
||||
|
||||
```
|
||||
-h, --help print help message
|
||||
-v, --version show program version number
|
||||
-b, --board-name set board name for testing, this will make ROGCC show only the keyboard page
|
||||
-l, --layout-viewing put ROGCC in layout viewing mode - this is helpful for finding existing layouts that might match your laptop
|
||||
```
|
||||
534
rog-aura/data/aura_support.ron
Normal file
@@ -0,0 +1,534 @@
|
||||
([
|
||||
(
|
||||
board_name: "FA506I",
|
||||
layout_name: "fa506i",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "FA506Q",
|
||||
layout_name: "fa506i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "FA507",
|
||||
layout_name: "fa507",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "FX505D",
|
||||
layout_name: "fx505d",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "FX506HC",
|
||||
layout_name: "fa506i",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "FX506LH",
|
||||
layout_name: "fa506i",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "FX516P",
|
||||
layout_name: "fa506i",
|
||||
basic_modes: [Static, Breathe, Strobe],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G512",
|
||||
layout_name: "g512",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G512LI",
|
||||
layout_name: "gl503",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G512LV",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G513IC",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]),
|
||||
),
|
||||
(
|
||||
board_name: "G513IH",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G513IM",
|
||||
layout_name: "g513i-per-key",
|
||||
basic_modes: [Flash, Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G513QE",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G513QM",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G513QR",
|
||||
layout_name: "g513i-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G513QY",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G513RC",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]),
|
||||
),
|
||||
(
|
||||
board_name: "G513RM",
|
||||
layout_name: "g513i",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]),
|
||||
),
|
||||
(
|
||||
board_name: "G531",
|
||||
layout_name: "g513i-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G531",
|
||||
layout_name: "g513i-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G531GD",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G531GT",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G531GU",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G531GV",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G531GW",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G532",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G533Q",
|
||||
layout_name: "g533q-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G533Z",
|
||||
layout_name: "g533q-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G712LI",
|
||||
layout_name: "gl503",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G712LV",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G712LW",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G713IC",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G713QM",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G713QR",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G713RM",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G713RS",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G713RW",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G731",
|
||||
layout_name: "g533q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G731GT",
|
||||
layout_name: "g533q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G731GU",
|
||||
layout_name: "g533q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G731GV",
|
||||
layout_name: "g533q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G731GW",
|
||||
layout_name: "g533q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "G733Q",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "G733Z",
|
||||
layout_name: "g513i-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GA401Q",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GA402R",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GA503Q",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GA503QE",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GA503R",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GL504G",
|
||||
layout_name: "gl503",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4, Logo, BarLeft, BarRight],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GL531",
|
||||
layout_name: "g512",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GL553VE",
|
||||
layout_name: "g533q",
|
||||
basic_modes: [Static, Breathe, Strobe],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GL703G",
|
||||
layout_name: "gl503",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GM501G",
|
||||
layout_name: "fa507",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GU502",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GU502G",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GU502L",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GU502LU",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GU603H",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: Zoned([SingleZone]),
|
||||
),
|
||||
(
|
||||
board_name: "GU603Z",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: Zoned([SingleZone]),
|
||||
),
|
||||
(
|
||||
board_name: "GU604V",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: Zoned([SingleZone]),
|
||||
),
|
||||
(
|
||||
board_name: "GV301Q",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GV301V",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GV301VIC",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GV601R",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GV604V",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Strobe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GX502",
|
||||
layout_name: "gx502",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GX531",
|
||||
layout_name: "gx531-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [Key1, Key2, Key3, Key4],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GX550L",
|
||||
layout_name: "gx531-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GX551Q",
|
||||
layout_name: "gx531-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GX650P",
|
||||
layout_name: "gx531-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GX701",
|
||||
layout_name: "gx531-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: PerKey,
|
||||
),
|
||||
(
|
||||
board_name: "GX703H",
|
||||
layout_name: "gx531-per-key",
|
||||
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GZ301V",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
(
|
||||
board_name: "GZ301VIC",
|
||||
layout_name: "ga401q",
|
||||
basic_modes: [Static, Breathe, Pulse],
|
||||
basic_zones: [],
|
||||
advanced_type: None,
|
||||
),
|
||||
])
|
||||
317
rog-aura/data/layouts/fa506i_US.ron
Normal file
@@ -0,0 +1,317 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular2": Led(
|
||||
width: 1.0,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"func_key": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.0,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.5,
|
||||
height: 0.0,
|
||||
),
|
||||
"esc_func_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"bkslash": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 1.9,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.3,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.5,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 2.9,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.7,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.2,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 1.9,
|
||||
pad_right: 1.4,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.0,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 14.5,
|
||||
height: 0.0,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: -0.4,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"numpad_tall": Led(
|
||||
width: 1.0,
|
||||
height: 2.2,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: -1.2,
|
||||
),
|
||||
"numpad_wide": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
row: [
|
||||
(Esc, "func_key"),
|
||||
(Spacing, "esc_func_spacing"),
|
||||
(F1, "func_key"),
|
||||
(F2, "func_key"),
|
||||
(F3, "func_key"),
|
||||
(F4, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "func_key"),
|
||||
(F6, "func_key"),
|
||||
(F7, "func_key"),
|
||||
(F8, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "func_key"),
|
||||
(F10, "func_key"),
|
||||
(F11, "func_key"),
|
||||
(F12, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(Del, "func_key"),
|
||||
(NumPadPause, "func_key"),
|
||||
(NumPadPrtSc, "func_key"),
|
||||
(NumPadHome, "func_key"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(Spacing, "func_space"),
|
||||
(NumLock, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Star, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "bkslash"),
|
||||
(Spacing, "func_space"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(NumPadPlus, "numpad_tall"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(Spacing, "func_space"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(Spacing, "func_space"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(NumPadEnter, "numpad_tall"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular2"),
|
||||
(Meta, "regular2"),
|
||||
(LAlt, "regular2"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular2"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Up, "up_arrow"),
|
||||
(Spacing, "func_space"),
|
||||
(N0, "numpad_wide"),
|
||||
(NumPadDel, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
334
rog-aura/data/layouts/fa507_US.ron
Normal file
@@ -0,0 +1,334 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"rog_spacer": Blank(
|
||||
width: 2.5,
|
||||
height: 0.0,
|
||||
),
|
||||
"rog_row": Led(
|
||||
width: 1.0,
|
||||
height: 0.8,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.2,
|
||||
pad_bottom: 0.5,
|
||||
),
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular2": Led(
|
||||
width: 1.0,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"func_key": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.0,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.5,
|
||||
height: 0.0,
|
||||
),
|
||||
"esc_func_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"bkslash": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 1.9,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.3,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.5,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 2.9,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.7,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.2,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 1.9,
|
||||
pad_right: 1.4,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.0,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 14.5,
|
||||
height: 0.0,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: -0.4,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"numpad_tall": Led(
|
||||
width: 1.0,
|
||||
height: 2.2,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: -1.2,
|
||||
),
|
||||
"numpad_wide": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
row: [
|
||||
(Spacing, "rog_spacer"),
|
||||
(VolDown, "rog_row"),
|
||||
(VolUp, "rog_row"),
|
||||
(MicMute, "rog_row"),
|
||||
(RogApp, "rog_row"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
row: [
|
||||
(Esc, "func_key"),
|
||||
(Spacing, "esc_func_spacing"),
|
||||
(F1, "func_key"),
|
||||
(F2, "func_key"),
|
||||
(F3, "func_key"),
|
||||
(F4, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "func_key"),
|
||||
(F6, "func_key"),
|
||||
(F7, "func_key"),
|
||||
(F8, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "func_key"),
|
||||
(F10, "func_key"),
|
||||
(F11, "func_key"),
|
||||
(F12, "func_key"),
|
||||
(Del, "func_key"),
|
||||
(NumPadPause, "func_key"),
|
||||
(NumPadPrtSc, "func_key"),
|
||||
(NumPadHome, "func_key"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(NumLock, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Star, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "bkslash"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(NumPadPlus, "numpad_tall"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(NumPadEnter, "numpad_tall"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular2"),
|
||||
(Meta, "regular2"),
|
||||
(LAlt, "regular2"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular2"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Up, "up_arrow"),
|
||||
(N0, "numpad_wide"),
|
||||
(NumPadDel, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
281
rog-aura/data/layouts/fx505d_US.ron
Normal file
@@ -0,0 +1,281 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular2": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: -0.2,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"func_key": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.0,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.5,
|
||||
height: 0.0,
|
||||
),
|
||||
"esc_func_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"bkslash": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 1.9,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.3,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.5,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.7,
|
||||
height: 1.3,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 16.6,
|
||||
height: 0.0,
|
||||
),
|
||||
"numpad_tall": Led(
|
||||
width: 1.0,
|
||||
height: 2.2,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: -1.2,
|
||||
),
|
||||
"right_wide": Led(
|
||||
width: 2.9,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_top: 0.1,
|
||||
row: [
|
||||
(Esc, "func_key"),
|
||||
(Spacing, "esc_func_spacing"),
|
||||
(F1, "func_key"),
|
||||
(F2, "func_key"),
|
||||
(F3, "func_key"),
|
||||
(F4, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "func_key"),
|
||||
(F6, "func_key"),
|
||||
(F7, "func_key"),
|
||||
(F8, "func_key"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "func_key"),
|
||||
(F10, "func_key"),
|
||||
(F11, "func_key"),
|
||||
(F12, "func_key"),
|
||||
(Del, "func_key"),
|
||||
(NumPadPause, "func_key"),
|
||||
(NumPadPrtSc, "func_key"),
|
||||
(NumPadHome, "func_key"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(NumLock, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Star, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "bkslash"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(NumPadPlus, "numpad_tall"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "right_wide"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(NumPadEnter, "numpad_tall"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular"),
|
||||
(Meta, "regular"),
|
||||
(LAlt, "regular"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular"),
|
||||
(RAlt, "regular"),
|
||||
(RAlt, "regular"),
|
||||
(RCtrl, "right_wide"),
|
||||
(Up, "regular"),
|
||||
(N0, "regular"),
|
||||
(NumPadDel, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "regular2"),
|
||||
(Down, "regular2"),
|
||||
(Right, "regular2"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
312
rog-aura/data/layouts/g512_US.ron
Normal file
@@ -0,0 +1,312 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"rog_row": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.6,
|
||||
),
|
||||
"rog_row_blocking": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.6,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backslash": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 3.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.8,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 1.1,
|
||||
pad_right: 1.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 15.0,
|
||||
height: 0.0,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: -0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"row_end_spacing": Blank(
|
||||
width: 0.4,
|
||||
height: 0.0,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(VolDown, "rog_row"),
|
||||
(VolUp, "rog_row"),
|
||||
(MicMute, "rog_row"),
|
||||
(RogFan, "rog_row"),
|
||||
(RogApp, "rog_row"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Esc, "regular"),
|
||||
(Spacing, "regular_spacing"),
|
||||
(F1, "regular"),
|
||||
(F2, "regular"),
|
||||
(F3, "regular"),
|
||||
(F4, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "regular"),
|
||||
(F6, "regular"),
|
||||
(F7, "regular"),
|
||||
(F8, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "regular"),
|
||||
(F10, "regular"),
|
||||
(F11, "regular"),
|
||||
(F12, "regular"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(Del, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(Home, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "backslash"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(PgUp, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(PgDn, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(End, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular"),
|
||||
(Meta, "regular"),
|
||||
(LAlt, "regular"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular"),
|
||||
(PrtSc, "regular"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Up, "up_arrow"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(PrtSc, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,161 +0,0 @@
|
||||
matches = [
|
||||
'G513',
|
||||
]
|
||||
|
||||
locale = "US"
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'NormalSpacer',
|
||||
'FuncSpacer',
|
||||
'VolDown',
|
||||
'VolUp',
|
||||
'MicMute',
|
||||
'Fan',
|
||||
'Rog',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'Esc',
|
||||
'FuncSpacer',
|
||||
'F1',
|
||||
'F2',
|
||||
'F3',
|
||||
'F4',
|
||||
'FuncSpacer',
|
||||
'F5',
|
||||
'F6',
|
||||
'F7',
|
||||
'F8',
|
||||
'FuncSpacer',
|
||||
'F9',
|
||||
'F10',
|
||||
'F11',
|
||||
'F12',
|
||||
'RowEndSpacer',
|
||||
'NumPadDel',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Tilde',
|
||||
'N1',
|
||||
'N2',
|
||||
'N3',
|
||||
'N4',
|
||||
'N5',
|
||||
'N6',
|
||||
'N7',
|
||||
'N8',
|
||||
'N9',
|
||||
'N0',
|
||||
'Hyphen',
|
||||
'Equals',
|
||||
'BkSpc',
|
||||
'RowEndSpacer',
|
||||
'Home',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Tab',
|
||||
'Q',
|
||||
'W',
|
||||
'E',
|
||||
'R',
|
||||
'T',
|
||||
'Y',
|
||||
'U',
|
||||
'I',
|
||||
'O',
|
||||
'P',
|
||||
'LBracket',
|
||||
'RBracket',
|
||||
'BackSlash',
|
||||
'RowEndSpacer',
|
||||
'PgUp',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Caps',
|
||||
'A',
|
||||
'S',
|
||||
'D',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'SemiColon',
|
||||
'Quote',
|
||||
'Return',
|
||||
'RowEndSpacer',
|
||||
'PgDn',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'LShift',
|
||||
'Z',
|
||||
'X',
|
||||
'C',
|
||||
'V',
|
||||
'B',
|
||||
'N',
|
||||
'M',
|
||||
'Comma',
|
||||
'Period',
|
||||
'FwdSlash',
|
||||
'Rshift',
|
||||
'RowEndSpacer',
|
||||
'End',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.2
|
||||
row = [
|
||||
'LCtrl',
|
||||
'LFn',
|
||||
'Meta',
|
||||
'LAlt',
|
||||
'Space',
|
||||
'RAlt',
|
||||
'PrtSc',
|
||||
'RCtrl',
|
||||
'ArrowSpacer',
|
||||
'Up',
|
||||
'ArrowSpacer',
|
||||
'RowEndSpacer',
|
||||
'RFn',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'ArrowSpacer',
|
||||
'Left',
|
||||
'Down',
|
||||
'Right',
|
||||
'ArrowSpacer',
|
||||
]
|
||||
366
rog-aura/data/layouts/g513i-per-key_US.ron
Normal file
@@ -0,0 +1,366 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"rog_row": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.6,
|
||||
),
|
||||
"rog_row_blocking": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.6,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backslash": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 3.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.8,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 1.1,
|
||||
pad_right: 1.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 15.0,
|
||||
height: 0.0,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: -0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"row_end_spacing": Blank(
|
||||
width: 0.4,
|
||||
height: 0.0,
|
||||
),
|
||||
"lightbar_left": Led(
|
||||
width: 0.4,
|
||||
height: 3.0,
|
||||
pad_left: -1.0,
|
||||
pad_right: 0.1,
|
||||
pad_top: -2.7,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_corner_left": Led(
|
||||
width: 0.4,
|
||||
height: 0.4,
|
||||
pad_left: -0.5,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.5,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_bottom": Led(
|
||||
width: 10.1,
|
||||
height: 0.4,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.5,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_corner_right": Led(
|
||||
width: 0.4,
|
||||
height: 0.4,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.5,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_right": Led(
|
||||
width: 0.4,
|
||||
height: 3.0,
|
||||
pad_left: -0.5,
|
||||
pad_right: 0.1,
|
||||
pad_top: -2.7,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(VolDown, "rog_row"),
|
||||
(VolUp, "rog_row"),
|
||||
(MicMute, "rog_row"),
|
||||
(RogFan, "rog_row"),
|
||||
(RogApp, "rog_row"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Esc, "regular"),
|
||||
(Spacing, "regular_spacing"),
|
||||
(F1, "regular"),
|
||||
(F2, "regular"),
|
||||
(F3, "regular"),
|
||||
(F4, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "regular"),
|
||||
(F6, "regular"),
|
||||
(F7, "regular"),
|
||||
(F8, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "regular"),
|
||||
(F10, "regular"),
|
||||
(F11, "regular"),
|
||||
(F12, "regular"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(Del, "regular"), // Should be super/insert
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaPlay, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "backslash"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaStop, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaNext, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaPrev, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular"),
|
||||
(Meta, "regular"),
|
||||
(LAlt, "regular"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular"),
|
||||
(PrtSc, "regular"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Up, "up_arrow"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(PrtSc, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LightbarLeft, "lightbar_left"),
|
||||
(LightbarLeftCorner, "lightbar_corner_left"),
|
||||
(LightbarLeftBottom, "lightbar_bottom"),
|
||||
(LightbarRightBottom, "lightbar_bottom"),
|
||||
(LightbarRightCorner, "lightbar_corner_right"),
|
||||
(LightbarRight, "lightbar_right"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
366
rog-aura/data/layouts/g513i_US.ron
Normal file
@@ -0,0 +1,366 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"rog_row": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.6,
|
||||
),
|
||||
"rog_row_blocking": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.6,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backslash": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 3.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.8,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 1.1,
|
||||
pad_right: 1.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 15.0,
|
||||
height: 0.0,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 0.8,
|
||||
height: 0.8,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: -0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"row_end_spacing": Blank(
|
||||
width: 0.4,
|
||||
height: 0.0,
|
||||
),
|
||||
"lightbar_left": Led(
|
||||
width: 0.4,
|
||||
height: 3.0,
|
||||
pad_left: -1.0,
|
||||
pad_right: 0.1,
|
||||
pad_top: -2.7,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_corner_left": Led(
|
||||
width: 0.4,
|
||||
height: 0.4,
|
||||
pad_left: -0.5,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.5,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_bottom": Led(
|
||||
width: 10.1,
|
||||
height: 0.4,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.5,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_corner_right": Led(
|
||||
width: 0.4,
|
||||
height: 0.4,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.5,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lightbar_right": Led(
|
||||
width: 0.4,
|
||||
height: 3.0,
|
||||
pad_left: -0.5,
|
||||
pad_right: 0.1,
|
||||
pad_top: -2.7,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(VolDown, "rog_row"),
|
||||
(VolUp, "rog_row"),
|
||||
(MicMute, "rog_row"),
|
||||
(RogFan, "rog_row"),
|
||||
(RogApp, "rog_row"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Esc, "regular"),
|
||||
(Spacing, "regular_spacing"),
|
||||
(F1, "regular"),
|
||||
(F2, "regular"),
|
||||
(F3, "regular"),
|
||||
(F4, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "regular"),
|
||||
(F6, "regular"),
|
||||
(F7, "regular"),
|
||||
(F8, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "regular"),
|
||||
(F10, "regular"),
|
||||
(F11, "regular"),
|
||||
(F12, "regular"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(Del, "regular"), // Should be super/insert
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaPlay, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "backslash"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaStop, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaNext, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(MediaPrev, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular"),
|
||||
(Meta, "regular"),
|
||||
(LAlt, "regular"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular"),
|
||||
(PrtSc, "regular"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Up, "up_arrow"),
|
||||
(Spacing, "row_end_spacing"),
|
||||
(PrtSc, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LightbarLeft, "lightbar_left"),
|
||||
(LightbarLeftCorner, "lightbar_corner_left"),
|
||||
(LightbarLeftBottom, "lightbar_bottom"),
|
||||
(LightbarRightBottom, "lightbar_bottom"),
|
||||
(LightbarRightCorner, "lightbar_corner_right"),
|
||||
(LightbarRight, "lightbar_right"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,135 +0,0 @@
|
||||
matches = [
|
||||
'G533',
|
||||
]
|
||||
|
||||
locale = "US"
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'NormalSpacer',
|
||||
'FuncSpacer',
|
||||
'VolDown',
|
||||
'VolUp',
|
||||
'MicMute',
|
||||
'Fan',
|
||||
'Rog',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'Esc',
|
||||
'FuncSpacer',
|
||||
'F1',
|
||||
'F2',
|
||||
'F3',
|
||||
'F4',
|
||||
'FuncSpacer',
|
||||
'F5',
|
||||
'F6',
|
||||
'F7',
|
||||
'F8',
|
||||
'FuncSpacer',
|
||||
'F9',
|
||||
'F10',
|
||||
'F11',
|
||||
'F12',
|
||||
'Del',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Tilde',
|
||||
'N1',
|
||||
'N2',
|
||||
'N3',
|
||||
'N4',
|
||||
'N5',
|
||||
'N6',
|
||||
'N7',
|
||||
'N8',
|
||||
'N9',
|
||||
'N0',
|
||||
'Hyphen',
|
||||
'Equals',
|
||||
'BkSpc',
|
||||
'MediaPlay',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Tab',
|
||||
'Q',
|
||||
'W',
|
||||
'E',
|
||||
'R',
|
||||
'T',
|
||||
'Y',
|
||||
'U',
|
||||
'I',
|
||||
'O',
|
||||
'P',
|
||||
'LBracket',
|
||||
'RBracket',
|
||||
'BackSlash',
|
||||
'MediaStop',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Caps',
|
||||
'A',
|
||||
'S',
|
||||
'D',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'SemiColon',
|
||||
'Quote',
|
||||
'Return',
|
||||
'MediaPrev',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'LShift',
|
||||
'Z',
|
||||
'X',
|
||||
'C',
|
||||
'V',
|
||||
'B',
|
||||
'N',
|
||||
'M',
|
||||
'Comma',
|
||||
'Period',
|
||||
'FwdSlash',
|
||||
'RshiftSmall',
|
||||
'UpRegular',
|
||||
'MediaNext',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'LCtrlMed',
|
||||
'LFn',
|
||||
'Meta',
|
||||
'LAlt',
|
||||
'Space',
|
||||
'RAlt',
|
||||
'PrtSc',
|
||||
'RCtrl',
|
||||
'ArrowRegularSpacer',
|
||||
'LeftRegular',
|
||||
'DownRegular',
|
||||
'RightRegular',
|
||||
]
|
||||
|
||||
293
rog-aura/data/layouts/g533q-per-key_US.ron
Normal file
@@ -0,0 +1,293 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"rog_row": Led(
|
||||
width: 1.0,
|
||||
height: 0.7,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.6,
|
||||
),
|
||||
"rog_row_blocking": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.6,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backslash": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 1.8,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.8,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrow_space": Blank(
|
||||
width: 0.8,
|
||||
height: 0.0,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(VolDown, "rog_row"),
|
||||
(VolUp, "rog_row"),
|
||||
(MicMute, "rog_row"),
|
||||
(RogFan, "rog_row"),
|
||||
(RogApp, "rog_row"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Esc, "regular"),
|
||||
(Spacing, "regular_spacing"),
|
||||
(F1, "regular"),
|
||||
(F2, "regular"),
|
||||
(F3, "regular"),
|
||||
(F4, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "regular"),
|
||||
(F6, "regular"),
|
||||
(F7, "regular"),
|
||||
(F8, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "regular"),
|
||||
(F10, "regular"),
|
||||
(F11, "regular"),
|
||||
(F12, "regular"),
|
||||
(Del, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(MediaPlay, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "backslash"),
|
||||
(MediaStop, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(MediaPrev, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(Up, "up_arrow"),
|
||||
(MediaNext, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular"),
|
||||
(Meta, "regular"),
|
||||
(LAlt, "regular"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular"),
|
||||
(PrtSc, "regular"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Spacing, "arrow_space"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
294
rog-aura/data/layouts/g533q_US.ron
Normal file
@@ -0,0 +1,294 @@
|
||||
(
|
||||
locale: "US",
|
||||
key_shapes: {
|
||||
"regular": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"regular_spacing": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"rog_row_blocking": Blank(
|
||||
width: 1.2,
|
||||
height: 0.0,
|
||||
),
|
||||
"func_space": Blank(
|
||||
width: 0.6,
|
||||
height: 0.0,
|
||||
),
|
||||
"backspace": Led(
|
||||
width: 2.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"tab": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"backslash": Led(
|
||||
width: 1.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"capsplonk": Led(
|
||||
width: 2.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"return": Led(
|
||||
width: 2.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lshift": Led(
|
||||
width: 2.6,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rshift": Led(
|
||||
width: 3.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"lctrl": Led(
|
||||
width: 1.4,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"spacebar": Led(
|
||||
width: 5.8,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"rctrl": Led(
|
||||
width: 1.2,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"up_arrow": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 1.0,
|
||||
pad_right: 1.0,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
"arrows_spacer": Blank(
|
||||
width: 14.7,
|
||||
height: 0.0,
|
||||
),
|
||||
"arrows": Led(
|
||||
width: 1.0,
|
||||
height: 1.0,
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
),
|
||||
},
|
||||
key_rows: [
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(Blocking, "rog_row_blocking"),
|
||||
(VolDown, "regular"),
|
||||
(VolUp, "regular"),
|
||||
(MicMute, "regular"),
|
||||
(RogFan, "regular"),
|
||||
(RogApp, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Esc, "regular"),
|
||||
(Spacing, "regular_spacing"),
|
||||
(F1, "regular"),
|
||||
(F2, "regular"),
|
||||
(F3, "regular"),
|
||||
(F4, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F5, "regular"),
|
||||
(F6, "regular"),
|
||||
(F7, "regular"),
|
||||
(F8, "regular"),
|
||||
(Spacing, "func_space"),
|
||||
(F9, "regular"),
|
||||
(F10, "regular"),
|
||||
(F11, "regular"),
|
||||
(F12, "regular"),
|
||||
(Del, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tilde, "regular"),
|
||||
(N1, "regular"),
|
||||
(N2, "regular"),
|
||||
(N3, "regular"),
|
||||
(N4, "regular"),
|
||||
(N5, "regular"),
|
||||
(N6, "regular"),
|
||||
(N7, "regular"),
|
||||
(N8, "regular"),
|
||||
(N9, "regular"),
|
||||
(N0, "regular"),
|
||||
(Hyphen, "regular"),
|
||||
(Equals, "regular"),
|
||||
(Backspace, "backspace"),
|
||||
(Home, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Tab, "tab"),
|
||||
(Q, "regular"),
|
||||
(W, "regular"),
|
||||
(E, "regular"),
|
||||
(R, "regular"),
|
||||
(T, "regular"),
|
||||
(Y, "regular"),
|
||||
(U, "regular"),
|
||||
(I, "regular"),
|
||||
(O, "regular"),
|
||||
(P, "regular"),
|
||||
(LBracket, "regular"),
|
||||
(RBracket, "regular"),
|
||||
(BackSlash, "backslash"),
|
||||
(PgUp, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Caps, "capsplonk"),
|
||||
(A, "regular"),
|
||||
(S, "regular"),
|
||||
(D, "regular"),
|
||||
(F, "regular"),
|
||||
(G, "regular"),
|
||||
(H, "regular"),
|
||||
(J, "regular"),
|
||||
(K, "regular"),
|
||||
(L, "regular"),
|
||||
(SemiColon, "regular"),
|
||||
(Quote, "regular"),
|
||||
(Return, "return"),
|
||||
(PgDn, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LShift, "lshift"),
|
||||
(Z, "regular"),
|
||||
(X, "regular"),
|
||||
(C, "regular"),
|
||||
(V, "regular"),
|
||||
(B, "regular"),
|
||||
(N, "regular"),
|
||||
(M, "regular"),
|
||||
(Comma, "regular"),
|
||||
(Period, "regular"),
|
||||
(FwdSlash, "regular"),
|
||||
(Rshift, "rshift"),
|
||||
(End, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(LCtrl, "lctrl"),
|
||||
(LFn, "regular"),
|
||||
(Meta, "regular"),
|
||||
(LAlt, "regular"),
|
||||
(Spacebar, "spacebar"),
|
||||
(RAlt, "regular"),
|
||||
(PrtSc, "regular"),
|
||||
(RCtrl, "rctrl"),
|
||||
(Up, "up_arrow"),
|
||||
(RFn, "regular"),
|
||||
],
|
||||
),
|
||||
(
|
||||
pad_left: 0.1,
|
||||
pad_right: 0.1,
|
||||
pad_top: 0.1,
|
||||
pad_bottom: 0.1,
|
||||
row: [
|
||||
(Spacing, "arrows_spacer"),
|
||||
(Left, "arrows"),
|
||||
(Down, "arrows"),
|
||||
(Right, "arrows"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,154 +0,0 @@
|
||||
matches = [
|
||||
'GA401',
|
||||
'GA402',
|
||||
'GU603',
|
||||
'GV301',
|
||||
'GA502',
|
||||
'GA503',
|
||||
]
|
||||
|
||||
locale = "US"
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'NormalSpacer',
|
||||
'FuncSpacer',
|
||||
'VolDown',
|
||||
'VolUp',
|
||||
'MicMute',
|
||||
'Rog',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'Esc',
|
||||
'FuncSpacer',
|
||||
'F1',
|
||||
'F2',
|
||||
'F3',
|
||||
'F4',
|
||||
'FuncSpacer',
|
||||
'F5',
|
||||
'F6',
|
||||
'F7',
|
||||
'F8',
|
||||
'FuncSpacer',
|
||||
'F9',
|
||||
'F10',
|
||||
'F11',
|
||||
'F12',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Tilde',
|
||||
'N1',
|
||||
'N2',
|
||||
'N3',
|
||||
'N4',
|
||||
'N5',
|
||||
'N6',
|
||||
'N7',
|
||||
'N8',
|
||||
'N9',
|
||||
'N0',
|
||||
'Hyphen',
|
||||
'Equals',
|
||||
'BkSpc',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Tab',
|
||||
'Q',
|
||||
'W',
|
||||
'E',
|
||||
'R',
|
||||
'T',
|
||||
'Y',
|
||||
'U',
|
||||
'I',
|
||||
'O',
|
||||
'P',
|
||||
'LBracket',
|
||||
'RBracket',
|
||||
'BackSlash',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'Caps',
|
||||
'A',
|
||||
'S',
|
||||
'D',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'SemiColon',
|
||||
'Quote',
|
||||
'Return',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.0
|
||||
row = [
|
||||
'LShift',
|
||||
'Z',
|
||||
'X',
|
||||
'C',
|
||||
'V',
|
||||
'B',
|
||||
'N',
|
||||
'M',
|
||||
'Comma',
|
||||
'Period',
|
||||
'FwdSlash',
|
||||
'Rshift',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 1.2
|
||||
row = [
|
||||
'LCtrl',
|
||||
'LFn',
|
||||
'Meta',
|
||||
'LAlt',
|
||||
'Space',
|
||||
'RAlt',
|
||||
'PrtSc',
|
||||
'RCtrl',
|
||||
'ArrowSpacer',
|
||||
'Up',
|
||||
'ArrowSpacer',
|
||||
]
|
||||
|
||||
[[rows]]
|
||||
height = 0.8
|
||||
row = [
|
||||
'FuncSpacer',
|
||||
'FuncSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'NormalSpacer',
|
||||
'Left',
|
||||
'Down',
|
||||
'Right',
|
||||
'ArrowSpacer',
|
||||
]
|
||||
|
||||