Compare commits

...

329 Commits

Author SHA1 Message Date
rforced
0d9d42fb19 Merge branch 'fix-z13-2025-1' into 'devel'
Fixes for Asus z13 2025

See merge request asus-linux/asusctl!245
2026-01-27 20:26:13 -05:00
Denis Benato
99ec1e8bcf feat: improve the UI 2026-01-27 01:42:19 +01:00
Denis Benato
c2a3310891 fix: move keyboard power 2026-01-27 01:09:02 +01:00
Denis Benato
024d41727f feat: support TUF lighting power 2026-01-26 22:38:07 +01:00
Denis Benato
7d55a2675b feat: reorder CLI parameters 2026-01-26 20:49:41 +01:00
Denis Benato
37fad1741e fix: name the correct power profile 2026-01-26 02:49:30 +01:00
Denis Benato
8867749e0e feat: improve GPU selection 2026-01-26 00:28:26 +01:00
Denis Benato
d890461777 Merge branch 'devel' into 'devel'
feat: add pulse mode to G835L and format file

See merge request asus-linux/asusctl!252
2026-01-24 20:12:56 +00:00
Denis Benato
bcdbc45931 feat: make notifications disappear after 5 seconds from last action 2026-01-24 21:10:44 +01:00
Ghoul
b97242981c feat: add pulse to G835L LED modes 2026-01-24 22:48:48 +05:00
Denis Benato
1d10f99e77 chore: updated CHANGELOG.md 2026-01-24 18:06:18 +01:00
Denis Benato
5901a4b4d9 fix: aura CLI interface 2026-01-24 17:58:54 +01:00
Denis Benato
9cd14d108c wip: reload current settings in rogcc for LEDs 2026-01-24 17:26:42 +01:00
Denis Benato
5d4b164b3b fix: LEDs managfement in rogcc 2026-01-24 16:49:48 +01:00
Denis Benato
bbd8e775f1 Merge branch 'main' into 'devel'
Add custom image and gif support for Scar 2025 (G635L/G835L) with other minor fixes

See merge request asus-linux/asusctl!249
2026-01-24 02:43:54 +00:00
Ghoul
90af90850a Feat: anime matrix gets custom image and gif support for Scar 2025 with other minor fixes 2026-01-24 02:43:53 +00:00
Denis Benato
58db410ba4 fix: restore TDP values 2026-01-24 03:08:06 +01:00
Denis Benato
fc75b88fab chore: update CHANGELOG.md 2026-01-24 02:42:40 +01:00
Denis Benato
1727bf5f45 chore: Update CHANGELOG.md 2026-01-24 02:42:23 +01:00
Denis Benato
01ed547374 Merge branch 'ga402nv-matrix' into 'devel'
Enable support for GA402N board

See merge request asus-linux/asusctl!251
2026-01-24 01:41:07 +00:00
Ghoul
20d343a984 feat: add new board for GA401 - GA401N 2026-01-24 05:05:51 +05:00
Denis Benato
2ea2cec172 Merge branch 'rogcc_ui_update' into 'devel'
ROGCC UI update

See merge request asus-linux/asusctl!250
2026-01-23 19:46:16 +00:00
Mykola Shevchenko
269041a7c6 ROGCC UI update 2026-01-23 19:46:15 +00:00
Denis Benato
6e83884c0a feat: GUI rework 2026-01-19 02:20:53 +01:00
Denis Benato
7edb77b41f fix: make the linter happy again 2026-01-18 23:43:22 +01:00
Denis Benato
737ffa522c chore: update CHANGELOG.md 2026-01-18 23:41:26 +01:00
Denis Benato
0311cfb1f9 fix: improve handling of different attribute types 2026-01-18 23:38:45 +01:00
Denis Benato
b0ee27fb74 Merge branch 'rogcc_toast_look_update' into 'devel'
rog-control-center toast message update

See merge request asus-linux/asusctl!248
2026-01-18 22:15:02 +00:00
Mykola Shevchenko
d4eca0c93e feat: improve toast message for rogcc 2026-01-18 22:15:02 +00:00
Denis Benato
a9f4aac875 Release: 6.3.1 2026-01-18 15:44:30 +01:00
Denis Benato
8377056580 chore: add Quiet/LowPower entry to CHANGELOG.md 2026-01-18 15:39:50 +01:00
Denis Benato
d541581012 fix: do not write unavailable settings to the config file 2026-01-18 15:38:41 +01:00
Denis Benato
72ef6dea07 chore: update README.md and use rust-toolchain file 2026-01-17 16:46:02 +01:00
Denis Benato
bfadc39400 Merge branch 'g615lr-rgb' into 'devel'
feat: add support for G615LR to aura_support.ron

See merge request asus-linux/asusctl!247
2026-01-17 15:39:43 +00:00
Burak
754d82d031 feat: add support for G615LR to aura_support.ron 2026-01-17 18:09:43 +03:00
Denis Benato
8ae072ea82 chore: update README.md for translation 2026-01-17 15:16:35 +01:00
Denis Benato
cec2168591 Merge branch 'rogcc_ukrainian_translations' into 'devel'
rog-control-center Ukrainian language added

See merge request asus-linux/asusctl!246
2026-01-17 14:08:02 +00:00
Mykola Shevchenko
8d6acc5975 rog-control-center Ukrainian language added 2026-01-17 14:02:04 +02:00
Josh Dariano
f471f340d4 Fix fan controls on z13 2026-01-16 16:37:15 -05:00
Josh Dariano
8095ac34ed Fix formatting 2026-01-16 15:48:02 -05:00
Josh Dariano
9d629b62ca Fix aura backlight for z13 2026-01-16 15:33:30 -05:00
Josh Dariano
5282c56f59 Merge remote-tracking branch 'rforced/fix-z13-2025' 2026-01-16 14:13:45 -05:00
Josh Dariano
0d2cd4eb10 Fix keyboard light 2026-01-16 13:57:35 -05:00
Denis Benato
b20ecf5378 chore: README.md edits 2026-01-16 19:53:58 +01:00
Denis Benato
ade839e981 chore: Update README.md 2026-01-16 19:18:15 +01:00
Denis Benato
d625c279a6 fix: G835LW doesn't have pulse available in windows 2026-01-16 19:13:00 +01:00
Denis Benato
5ea14be3fa chore: add extra/index.html: docs landing redirect to asusctl docs 2026-01-14 14:25:13 +01:00
Denis Benato
64c2e55db4 chore: prepare for a new version 2026-01-14 02:27:39 +01:00
Denis Benato
5303bfc1ad Release: 6.3.0 2026-01-14 02:16:22 +01:00
Denis Benato
635f1dc9b9 Feat: add support for G835L 2026-01-14 02:13:30 +01:00
Denis Benato
33a4dba8fe fix: rogcc not starting in rog ally 2026-01-14 02:10:03 +01:00
Denis Benato
e4680c9543 Merge branch 'remove_supergfxctl' into devel 2026-01-14 02:02:26 +01:00
Denis Benato
60c4818381 fix: implement Display instead of ToString 2026-01-14 02:00:59 +01:00
Denis Benato
9cd48dc101 chore: edit CHANGELOG.md 2026-01-14 01:59:03 +01:00
Denis Benato
8d954c16fa fix: cargo clippy --fix 2026-01-14 01:57:48 +01:00
Denis Benato
3665d9cc8e feat: improve the cli interface 2026-01-14 01:56:58 +01:00
Denis Benato
d7ddee246a feat: refactor the cli battery interface 2026-01-14 01:45:56 +01:00
Denis Benato
e85938b34d feat: refactor cli options for leds 2026-01-14 01:32:10 +01:00
Denis Benato
b7d480dd39 fix: help strings 2026-01-14 01:14:53 +01:00
Denis Benato
77640d1637 feat: improve profile cli usage 2026-01-14 01:05:35 +01:00
Denis Benato
32da2a2da0 feat: make easier to use armoury subcommand 2026-01-14 00:31:13 +01:00
Denis Benato
7981a85ff5 feat: improve cmdline 2026-01-14 00:06:34 +01:00
Denis Benato
e3035adf98 chore: change the text in about page 2026-01-13 23:55:52 +01:00
Denis Benato
be17e0b388 feat: remove references to graphic switching 2026-01-13 23:53:23 +01:00
Denis Benato
20cbddb6fa feat: refactor cli interface 2026-01-13 23:50:31 +01:00
Denis Benato
e9c5315bda Feat: Remove supergfxctl notification daemon 2026-01-13 22:05:34 +01:00
Denis Benato
b521a9ffc1 Fix: avoid using deprecated functions 2026-01-13 21:49:14 +01:00
Denis Benato
5e48923db1 Feat: update dependencies 2026-01-13 21:29:58 +01:00
Denis Benato
392436808d Fix text of armoury usage 2026-01-13 20:54:53 +01:00
Denis Benato
3d9a08d7e0 Silence the server 2026-01-13 20:18:49 +01:00
Denis Benato
ff103f98af Chore: change text of an error 2026-01-13 20:14:45 +01:00
Denis Benato
d05182ae64 chore: make the settings save code prettier 2026-01-13 19:29:37 +01:00
Denis Benato
a4957a6eeb Modify changelog and cargo fmt 2026-01-10 13:58:09 +01:00
Denis Benato
dda750cf33 Merge branch 'Support_additional_ga403_2025' into 'devel'
Add slash support for additional ga403 2025 models

See merge request asus-linux/asusctl!238
2026-01-10 12:54:01 +00:00
James Lademann
0b5e04393a Add slash support for additional ga403 2025 models 2026-01-10 12:54:01 +00:00
Denis Benato
c9c9a022a4 Merge branch 'fix/one-shot-charge-persistence' into 'devel'
fix: one-shot charging loses original charge limit after restart

See merge request asus-linux/asusctl!242
2026-01-10 12:51:30 +00:00
bitr8
aa063c20fd fix: persist base_charge_control_end_threshold for one-shot charging
base_charge_control_end_threshold was marked #[serde(skip)] so it only
lived in memory. triggering one-shot charge then restarting asusd would
permanently lose the original charge limit.

- remove #[serde(skip)] so the field gets persisted
- add serde default of 0 for backwards compat (skips restore for
  upgraded configs missing the field)
- add comments explaining Default vs serde default asymmetry
2026-01-05 17:23:59 +11:00
Denis Benato
8551908452 Merge branch 'devel' into 'devel'
slashctl: Add "static" LED profile

See merge request asus-linux/asusctl!240
2025-12-24 00:09:19 +00:00
Denis Benato
5ecb174b8f Merge branch 'main' into 'devel'
feat (rog-aura): Add support to FA617NT and FA617XT and update layout_name on FA617NS and FA617XS models

See merge request asus-linux/asusctl!241
2025-12-23 23:48:32 +00:00
Denis Benato
fa266bff5b Merge branch 'main' into 'devel'
Add G614JU support

See merge request asus-linux/asusctl!239
2025-12-23 23:43:41 +00:00
Seom1177
f53f1f360f Feat: update layout_name for FA617NS and FA617XS models in aura_support.ron 2025-12-22 09:06:06 -05:00
Seom1177
da19216b78 Feat: add support for FA617NT and FA617XT models to aura_support.ron 2025-12-22 09:02:25 -05:00
Some Otters
46efd4190f slashctl: Add "static" LED profile
See https://gitlab.com/asus-linux/reverse-engineering/-/blob/master/slash-bar/packets.txt?ref_type=heads . Tested working on a GU605CR
2025-12-22 10:59:17 +00:00
Hamidreza Khorsand
ed3022e25e Add G614JU support 2025-12-19 01:21:16 +03:30
Denis Benato
7c10d6c6d9 Fix: fans control for LowPower and Quiet 2025-12-18 21:53:42 +01:00
Denis Benato
af5f3a5c71 Fix: memorize last applied brightness settings 2025-12-18 15:07:14 +01:00
Denis Benato
7d5ec5f2c7 Update CHANGELOG.md 2025-12-18 03:40:03 +01:00
Denis Benato
1c8acf6de3 Feat: implement keyboard control for TUFs via asus-armoury 2025-12-18 02:10:45 +01:00
Denis Benato
7b644e7ad6 Merge branch 'main' into 'devel'
fix: add systemd scriptlets to restart asusd on package upgrade

See merge request asus-linux/asusctl!237
2025-12-15 18:12:29 +00:00
Denis Benato
0f02fe868c Fix: re-add G835L 2025-12-15 19:11:09 +01:00
Ali Abdelaal
abd3100e30 Merge upstream main, keep systemd scriptlets 2025-12-15 15:47:18 +00:00
Ali Abdelaal
6f651c2b85 Add systemd scriptlets to restart asusd on upgrade 2025-12-15 15:36:45 +00:00
Denis Benato
93ec5d1bce Feat: improve anime matrix detection 2025-12-14 15:05:10 +01:00
Denis Benato
5aea7f51c0 Chore: fix CHANGELOG.md styling 2025-12-14 15:00:51 +01:00
Denis Benato
d03d8ce67f Release: v6.2.0 2025-12-13 14:41:12 +01:00
Denis Benato
ae3693e0d9 Feat: add aura support for G614F models 2025-12-13 14:17:49 +01:00
Denis Benato
c8b9248eda Chore: update CHANGELOG.md 2025-12-13 13:56:46 +01:00
Denis Benato
22098794fe Fix: ensure upper/lower case doesn't fail the match 2025-12-13 13:48:33 +01:00
Denis Benato
10d49f4fc8 Fix: rever silly change in anime type detection 2025-12-13 13:46:29 +01:00
Denis Benato
5aba2854b0 Feat: add support for GU605C* models 2025-12-13 13:45:55 +01:00
Denis Benato
ea32ad6e0a Feat: add support for FX607V 2025-12-13 13:36:46 +01:00
Denis Benato
ee0e612c04 Feat: add AniMe support for G835LW 2025-12-13 13:35:56 +01:00
Denis Benato
e565ce748a Feat: GA403WR -> GA403W 2025-12-13 13:21:58 +01:00
Denis Benato
7024941663 Chore: fix changelog styling 2025-12-13 13:14:37 +01:00
Denis Benato
817a0165b5 Merge branch 'ga403wr' into 'devel'
add support for ga403wr, zephyrus g14 2025

See merge request asus-linux/asusctl!235
2025-12-13 12:14:19 +00:00
Denis Benato
efcd038f40 Merge branch 'main' into 'devel'
Fix: restore spec file for fedora copr builds

See merge request asus-linux/asusctl!236
2025-12-13 12:06:36 +00:00
Ali
375d99b8fc Fix: restore spec file for fedora copr builds 2025-12-13 12:06:36 +00:00
Ali Abdelaal
3a206eb76f Add asusctl as dependency for rog-gui subpackage 2025-12-11 23:49:24 +00:00
Ali Abdelaal
4449838282 Fix: remove cargo_prep which deletes Cargo.lock 2025-12-11 22:55:49 +00:00
Ali Abdelaal
58d740f77a Fix: use direct cargo build instead of cargo_build macro 2025-12-11 22:52:46 +00:00
Ali Abdelaal
f0488d9750 Build with --locked for reproducible builds 2025-12-11 22:47:00 +00:00
Ali Abdelaal
f1b9ae6f71 Fix: rewrite install section to handle Fedora rpm target dir 2025-12-11 21:48:40 +00:00
Ali Abdelaal
db5de3b854 Fix: add asusctl dir to files, remove duplicate aura_support.ron 2025-12-11 21:17:00 +00:00
Ali Abdelaal
7a3d39b8f1 Add fontconfig BuildRequires for Fedora COPR build 2025-12-11 21:01:16 +00:00
Ali Abdelaal
7a5d6325c0 Restore distro-packaging spec file for Fedora COPR builds 2025-12-11 20:46:03 +00:00
rustysec
574b954866 add support for ga403wr, zephyrus g14 2025 2025-11-29 23:49:24 -08:00
Denis Benato
a811f20f65 Release: v6.1.22 2025-11-29 02:57:34 +01:00
Denis Benato
0c9c263be6 Chore: update CHANGELOG.md 2025-11-29 02:52:27 +01:00
Denis Benato
6571c04bfe Merge branch 'devel' 2025-11-29 02:51:29 +01:00
Denis Benato
e48acbb8a2 Chore: update CHANGELOG.md 2025-11-29 02:51:16 +01:00
Denis Benato
f33496ef68 Merge branch 'main' into 'main'
Support the ROG Strix G18 (2025) G815

See merge request asus-linux/asusctl!234
2025-11-29 01:50:33 +00:00
Denis Benato
cd3176b565 Feat: improve a debug message 2025-11-29 02:48:22 +01:00
Denis Benato
7595613d7e Fix: add EXPERTBOOK to udev rules 2025-11-29 02:00:23 +01:00
Adam Bierman
b8d0245e7a Support G815L 2025-11-27 03:20:26 +00:00
Adam Bierman
54bd2ec800 Update file aura_support.ron 2025-11-27 02:44:30 +00:00
Denis Benato
b6c8566565 Feat: Treat dGPU attributes the same as PPT attributes for power-profile 2025-11-23 17:12:55 +01:00
Denis Benato
052c096014 Fix: use the correct name for nv_tgp 2025-11-23 16:56:47 +01:00
Denis Benato
81cbe3c522 Chore(Makefile): install cargo-vendor-filterer 2025-11-20 14:04:35 +01:00
Denis Benato
09f7492bec Release: fuck fedora 2025-11-20 02:59:41 +01:00
Denis Benato
6adfb2cf48 Fix: Release process 2025-11-18 23:03:58 +01:00
Denis Benato
a2a56792a8 Chore: changelog for 6.1.20 2025-11-18 22:56:42 +01:00
Denis Benato
317daf4ed1 Release: 6.1.20 2025-11-18 22:50:35 +01:00
Denis Benato
eb0d9514b5 Merge branch 'devel' 2025-11-18 22:36:27 +01:00
LucaP
d324b1bce5 Feat: Added support for G635L* models. Lightbar, Logo, Matrix 2025-11-18 22:32:49 +01:00
Denis Benato
d1c7385146 Merge branch 'main' into 'main'
Feat: Added support for G635L* models. Lightbar, Logo, Matrix

See merge request asus-linux/asusctl!233
2025-11-18 21:31:13 +00:00
Denis Benato
48a4935fc7 Fix: don't spam the console 2025-11-18 21:36:48 +01:00
LucaP
7e917b91a5 Feat: Added support for G635L* models. Lightbar, Logo, Matrix 2025-11-17 20:12:30 +02:00
Denis Benato
45f8b8ffb0 Chore: attempt another CI fix 2025-11-16 14:43:40 +01:00
Denis Benato
031a36242b Chore: Spare memory on CI 2025-11-16 14:17:24 +01:00
Denis Benato
8ad26ad136 Fix: CI testing 2025-11-15 18:57:14 +01:00
Denis Benato
907d4694f3 Merge branch 'devel' 2025-11-15 18:17:38 +01:00
Denis Benato
1dcc4ff502 Update CHANGELOG.md 2025-11-15 18:15:55 +01:00
Denis Benato
cf232047b0 Merge branch 'patch-1' into 'main'
Add aura support for G614FR (ROG Strix G16 2025)

See merge request asus-linux/asusctl!232
2025-11-15 15:08:19 +00:00
Henry Zhang
ff99ec9a39 Add aura support for G614FR (ROG Strix G16 2025) 2025-11-15 16:13:38 +08:00
Denis Benato
8a19374a41 Merge branch 'aura-support-fa617xs' into 'main'
Add aura support for ASUS TUF Gaming A16 (FA617XS, AMD Advantage Edition)

Closes #696

See merge request asus-linux/asusctl!231
2025-11-14 06:56:21 +00:00
AB
4cec1f49b4 Add FA617XS (TUF A16 AMD Advantage Edition) support to aura_support.ron 2025-11-12 16:29:38 +05:30
Denis Benato
01aae200f3 Fix: do not crash if no battery is present 2025-11-11 22:41:54 +01:00
Denis Benato
4c6db9f0a9 Chore: ignore push-blocking features that would make older rust toolchains error 2025-11-11 22:21:32 +01:00
Denis Benato
7207d3287a Chore: avoid rebuilding after make 2025-11-11 22:03:45 +01:00
Denis Benato
1b2d8d83fc Chore: prepare for 6.1.18 release 2025-11-11 21:55:42 +01:00
Denis Benato
6d8db91583 Chore: reduce trace logging from libraries 2025-11-11 21:49:00 +01:00
Denis Benato
20c3628476 Chore: update dependencies 2025-11-11 21:44:27 +01:00
Denis Benato
4edecfce1c Merge commit '34699a7021a85e1c0ba3d6ac0876c6beb8ae394f' 2025-11-11 21:39:01 +01:00
Denis Benato
34699a7021 Fix: notifications not respecting settings 2025-11-06 02:57:20 +01:00
Denis Benato
ef311689ec Fix: do not stall the boot process 2025-11-06 00:55:20 +01:00
Denis Benato
8ee0281b4f Fix: fedora build 2025-11-05 22:40:58 +01:00
Denis Benato
d8504b5430 Changelog for 6.1.17 2025-11-05 21:14:21 +01:00
Denis Benato
5c4d833fbd Prepare for 6.1.17 2025-11-05 21:09:18 +01:00
Denis Benato
698999e828 cargo fmt and README.md restyle 2025-11-05 20:02:43 +01:00
Denis Benato
0eae9e55c6 Merge branch 'devel' 2025-11-05 19:54:21 +01:00
Denis Benato
07171888a1 Merge branch 'main' into 'main'
feat: Allow setting default profile for ac and battery

See merge request asus-linux/asusctl!229
2025-11-05 18:53:53 +00:00
matszwe02
9321fde6af feat: Allow setting default profile for ac and battery 2025-11-05 01:44:31 +01:00
Denis Benato
f90d0a6673 Merge branch 'devel' into 'devel'
Add install-data-asusd_user to install-data in Makefile

See merge request asus-linux/asusctl!228
2025-10-29 18:49:50 +00:00
Synby
bbd03c128d Edit Makefile
add install-data-asusd_user to install-data
2025-10-29 17:23:29 +00:00
Denis Benato
132a2f3665 Chore: complete the switch back to stable 2025-10-23 14:50:40 +02:00
Denis Benato
180566e5f1 Fix: share a single HID device
Avoid opening multiple handles to the same device whenever possible.
2025-10-22 22:05:17 +02:00
Denis Benato
c9e76f3273 Chore: prepare for 6.1.16 release 2025-10-20 19:15:36 +02:00
Denis Benato
2997ae83ff Merge branch 'devel' 2025-10-20 04:08:20 +02:00
Denis Benato
151d681e16 feat: expose MCU Powersave toggle on rogcc 2025-10-20 03:47:09 +02:00
Denis Benato
90b3f43a36 Chore: add more debugging 2025-10-20 02:49:47 +02:00
Denis Benato
a345b09ce1 Chore: type abttery -> battery 2025-10-20 02:46:07 +02:00
Denis Benato
f26b0d8de5 Merge branch 'profile-match' into 'main'
Allow flexible profile cli input for LowPower

See merge request asus-linux/asusctl!226
2025-10-20 00:40:54 +00:00
yanganto
9366b0ec04 Allow flexible profile cli input for LowPower 2025-10-20 00:40:54 +00:00
Denis Benato
415712143b Feat: add screen_auto_brightness 2025-10-20 02:08:59 +02:00
Denis Benato
60fce30a06 Chore: flush out requirement for nightly 2025-10-20 00:39:17 +02:00
Denis Benato
d8f06230fa Chore: Added support for FX607J 2025-10-19 23:02:45 +02:00
Denis Benato
834464a527 Fix: fixed ac_command/bat_command 2025-10-19 23:00:23 +02:00
Denis Benato
4faa96298a Chore: Added supprot for G614JIR 2025-10-19 22:32:05 +02:00
Denis Benato
78c574b761 chore_ add supprot for GU605CR 2025-10-19 21:27:33 +02:00
Denis Benato
9785eafd53 Modified to README.md to not mislead users attempting to compile it 2025-10-19 20:45:49 +02:00
Denis Benato
51cad9ea7e chore: make the startup more verbose 2025-10-16 15:17:27 +02:00
Denis Benato
319373faea chore: Prepare for 6.1.15 release 2025-10-14 01:57:03 +02:00
Denis Benato
f6aa3e3d01 Merge branch 'devel' 2025-10-14 01:50:20 +02:00
Denis Benato
d11fc20bab feat: apply the proper configuration depending on the plug status 2025-10-13 21:36:01 +02:00
Denis Benato
b0e1b21e4b chore: cargo clippy fix 2025-10-12 22:34:20 +02:00
Denis Benato
1c1daaa6d2 chore: reimplement default for FanCurveCPU 2025-10-12 19:47:26 +02:00
HiFiPhile
c3b5de843f Add TX Air rule 2025-10-12 19:44:30 +02:00
Denis Benato
09dcfb4065 Fix multiple warnings 2025-10-12 19:43:07 +02:00
Denis Benato
b2e7211bbe chore: cargo fmt 2025-10-12 19:43:05 +02:00
Denis Benato
1ab1adf937 Merge branch 'tx_air' into 'main'
Add TX Air (TUF Chinese version) udev rule

See merge request asus-linux/asusctl!227
2025-10-12 17:42:09 +00:00
HiFiPhile
a21bf779b0 Add TX Air rule 2025-10-12 13:20:07 +02:00
Denis Benato
0dba22529c feat: change limits dynamically 2025-10-11 20:51:57 +02:00
Denis Benato
180d63620b Fix multiple warnings 2025-10-08 01:19:38 +02:00
Denis Benato
daea1f538c chore: cargo fmt 2025-10-08 01:01:43 +02:00
Denis Benato
f5e2484797 chore: release 6.1.14 2025-10-08 00:56:25 +02:00
Denis Benato
7105ae40c6 chore: attempt to fix tests 2025-10-08 00:35:09 +02:00
Denis Benato
33f9900ef9 chore: fix formatting 2025-10-08 00:19:43 +02:00
Denis Benato
1aa1c62e40 chore: update spec file version to 6.1.13 2025-10-07 23:47:09 +02:00
Denis Benato
3a18ef4c7b chore: Prepare for 6.1.13 release 2025-10-07 23:47:02 +02:00
Denis Benato
9dcce77302 chore: fix a warning 2025-10-06 19:37:30 +02:00
Denis Benato
995df9b51b fix: fix building due to a double-borrow 2025-10-06 19:29:29 +02:00
Denis Benato
84c8babdb7 fix: make the startup path more robust 2025-10-06 19:19:31 +02:00
Denis Benato
1014f97b6f fix: apply panel overdrive and other properties on asusd startup 2025-10-05 23:13:41 +02:00
Denis Benato
3c023be57d chore: update changelog for the upcoming release 2025-10-05 17:29:51 +02:00
Denis Benato
eff20c84d6 chore: add ubuntu install instructions 2025-10-05 17:29:12 +02:00
Denis Benato
f8984eb7e9 chore: update crates 2025-10-05 17:18:24 +02:00
Denis Benato
2ffd2a1e1f chore: compile packages on make install 2025-10-05 16:58:03 +02:00
Denis Benato
341bd081f8 chore: fix makefile 2025-10-05 16:45:29 +02:00
Denis Benato
52af4203a1 Merge remote-tracking branch 'github/main' 2025-10-05 16:15:36 +02:00
Denis Benato
e5a6088392 Merge pull request #84 from evertvorster/patch-1
Update asusd.rules to have absolute path
2025-10-05 16:15:20 +02:00
Denis Benato
6ee5dfb352 chore: require power-profile-daemon on fedora 2025-10-05 16:07:58 +02:00
Evert Vorster
3f8336fc5e Update asusd.rules
Added the absolute path for systemctl. No modern distrobution installs it anywhere else.
2025-10-05 16:02:48 +02:00
Denis Benato
8fc7e8f3a7 Merge remote-tracking branch 'gitlab/main' 2025-10-05 16:02:08 +02:00
Denis Benato
098b1f2668 chore: add *.patch to gitignore 2025-10-05 15:57:20 +02:00
Denis Benato
20df3ad2f2 Merge remote-tracking branch 'github/main' 2025-10-05 15:52:50 +02:00
Denis Benato
7aaadad6da Merge pull request #39 from rashadgasimli/main
Add Azerbaijani language
2025-10-05 15:48:37 +02:00
Luke Jones
be60c1ba02 Merge pull request #69 from kxxt/tx
Add udev match for TX Gaming
2025-06-10 12:28:47 +12:00
kxxt
698a8e8677 Add udev match for TX Gaming 2025-05-29 20:38:05 +08:00
fluke
ce6420eeac Merge branch 'aura-support-fx706heb' into 'main'
Add AURA support definition for 2021 TUF F17

See merge request asus-linux/asusctl!225
2025-05-19 08:53:03 +00:00
fluke
f5f5e4f720 Edit FX706HEB to become FX706H and match more models 2025-05-19 08:52:11 +00:00
Brandon Tolbird
c08503826b Add AURA support definition for 2021 TUF F17
(FX706HEB)
2025-05-18 22:20:42 +00:00
Luke Jones
685345d656 chore: update spec file version to 6.1.12 2025-04-06 13:51:55 +12:00
Luke Jones
59aab24a4a Fix unbouneded loop and prep new version 2025-04-06 13:26:53 +12:00
Luke Jones
c3f0e61ebc chore: update spec file version to 6.1.11 2025-04-05 21:51:35 +13:00
Luke Jones
c143536cd0 Prep new release 2025-04-06 07:55:06 +12:00
Luke Jones
2a168e93d3 chore: update translations 2025-04-06 07:36:21 +12:00
Luke Jones
c3570a23f1 feature: add UI controls fro screenpad 2025-04-06 07:36:21 +12:00
Luke Jones
9db6cb5545 feature: watch primary backlight and sync screenpad to it 2025-04-06 02:41:46 +12:00
Luke Jones
836575c0a8 feature: screenpad settings config store 2025-04-06 02:09:45 +13:00
Luke Jones
61f2216c25 fix: minor clippy fix 2025-04-06 01:04:03 +13:00
Luke Jones
7f5b3ef376 feature: add support for screenpad brightness 2025-04-06 01:04:03 +13:00
fluke
257471a36c Merge branch 'fix/anime-flicker' into 'main'
Fix anime flickering when repeatedly setting images in a tight loop

See merge request asus-linux/asusctl!223
2025-03-27 21:13:25 +00:00
I-Al-Istannen
568f3e848f Fix anime flickering when repeatedly setting images in a tight loop 2025-03-27 21:05:23 +01:00
fluke
0c9b58755f Merge branch 'pt_BR-translation' into 'main'
Include pt_BR translations file.

See merge request asus-linux/asusctl!222
2025-03-25 01:18:33 +00:00
PabloKiryu
1b47fb7873 Include pt_BR translations file. 2025-03-18 00:32:25 -03:00
Denis Benato
df93209839 chore: Install LICENSE file 2025-03-13 01:28:06 +01:00
Denis Benato
11ee7827e9 chore: Add packaging instructions for deb
This commits adds .deb packaging support for all applications in this repository.
2025-03-12 18:18:08 +00:00
Denis Benato
c337de5139 chore(Makefile): split up install by package 2025-03-12 16:54:35 +01:00
Luke Jones
d55c2befed chore: update spec file version to 6.1.10 2025-03-04 09:21:53 +13:00
Luke Jones
4cd9918e1a asusd: single line fix for profile switching 2025-03-04 09:21:52 +13:00
Luke Jones
3a900f23fe ROGCC: better handling of fan curve profile 2025-03-03 20:20:09 +13:00
Luke Jones
aee465aced chore: update spec file version to 6.1.9 2025-03-03 19:58:37 +13:00
Luke Jones
192e5ccaa3 ROGCC: better handling of platform profile 2025-03-03 18:22:26 +13:00
Luke Jones
f164583792 ROGCC: fix fancurve quiet fans incorrect enablement 2025-03-02 20:50:57 +13:00
Luke Jones
b4d657b866 ROGCC: fix PPT sliders 2025-03-02 20:39:16 +13:00
Luke Jones
f7bf7aeef9 ROGCC: fix displaying ppt-toggle switch 2025-03-02 16:24:17 +13:00
Luke Jones
2cd4c4850f Extra debug output in ROGCC 2025-03-02 15:15:06 +13:00
Luke Jones
805ccfe451 Merge pull request #51 from sergik776/main
Added translation files for rog-control-center (RU)
2025-03-01 19:47:04 +13:00
Luke Jones
5655f63dff Cleanup 2025-03-01 16:27:50 +13:00
sergik776
a2795e4d78 Full translation into Russian 2025-02-26 10:51:33 +02:00
sergik776
0684c16bf5 Full translation into Russian 2025-02-26 10:24:17 +02:00
Luke Jones
a08ca3af98 chore: update spec file version to 6.1.8 2025-02-22 12:45:20 +13:00
Luke Jones
efa379e778 Add opensuse CI 2025-02-21 17:12:47 +13:00
Luke Jones
5cbf0816fe chore: update translations 2025-02-18 22:12:56 +13:00
Luke Jones
2951d3926c Update git hooks 2025-02-18 22:12:54 +13:00
Luke Jones
eb19d59d52 Update distro packaging 2025-02-18 22:12:53 +13:00
guylamar2006
3e4d594b05 Fix thread 'main' panicked at asusctl/src/main.rs:85:14: 2025-02-17 21:13:42 +00:00
Luke Jones
ae8ce83583 Fix slash enable 2025-02-17 11:38:29 +13:00
Luke Jones
5c3348a9f5 Add small env fixes for Ally
Signed-off-by: Luke Jones <luke@ljones.dev>
2025-02-16 23:18:58 +13:00
Luke Jones
f299ffeb6e Disable skia again, new release 2025-02-16 21:46:04 +13:00
Luke Jones
21c468cf02 Update supergfx
Signed-off-by: Luke Jones <luke@ljones.dev>
2025-02-16 11:50:56 +13:00
Luke Jones
7f12f62ad5 Temp 2025-02-16 09:38:33 +13:00
Luke Jones
5fb0e26331 Fix git losing the last set of fixes. Prep new release
Signed-off-by: Luke Jones <luke@ljones.dev>
2025-02-14 22:23:11 +13:00
Luke Jones
4dd29952c8 Fix the handling of of the kernel change from "quiet" to "low-power"
A coming kernel change will convert "quiet" to "low-power" due to how
platform_profile can now have multiple registered handlers.
(kernel 6.14 est)

Fixes #609
2025-02-14 20:02:08 +13:00
Luke Jones
2c006699f2 Reformat with trailing comma 2025-02-14 20:00:11 +13:00
Luke Jones
0bdf0474c9 Small error message fix 2025-02-14 20:00:11 +13:00
Kamo Kuma
66196ceb17 systemctl is-enabled can return 'linked' even if service is enabled. 2025-02-10 21:00:21 -05:00
Luke Jones
b2726f3a67 Fix: charge control 2025-02-10 22:18:34 +13:00
Luke Jones
663f87d5e2 Checkpoint 2025-02-10 13:56:26 +13:00
Luke Jones
377bb4d6ad Merge branch 'private/Rohitrajak1807/G513RW-ledfix' into 'main'
Add ROG G513RW led cfgs

See merge request asus-linux/asusctl!217
2025-02-10 00:55:33 +00:00
Rohit Rajak
98e60db2da Add ROG G513RW led cfgs 2025-02-10 00:55:33 +00:00
Luke Jones
11ac46df11 Edit README.md 2025-02-08 02:39:30 +00:00
Luke Jones
05bec93644 Edit README.md 2025-02-08 02:33:08 +00:00
Luke Jones
c77e7cf1ce Fix: correction to wrong matching function used for aura data find
Closes #607
2025-02-07 09:45:05 +13:00
Luke Jones
d30f7dc2ea Merge branch 'main' into 'main'
feat (rog-aura): ASUS TUF FA617NS AURA Support

See merge request asus-linux/asusctl!214
2025-02-05 02:58:05 +00:00
Luke Jones
759606fca3 Merge branch 'aura' into 'main'
Update 'led-mode' -> 'aura' in example command.

See merge request asus-linux/asusctl!215
2025-02-05 02:57:38 +00:00
Luke Jones
25ed8bdeed Fix spelling mistake 2025-02-05 14:35:17 +13:00
Luke Jones
de61a15b7a Prep 6.1.0 2025-02-04 18:52:55 +13:00
Luke Jones
16700e55f4 ROGCC: refactor many more parts of the PPT settings 2025-02-04 18:50:48 +13:00
Luke Jones
5833a011ce Merge branch 'g513rc-zonefix' into 'main'
Add basic zones for G513RC

See merge request asus-linux/asusctl!216
2025-02-03 04:08:29 +00:00
loystonpais
62577ee0e4 Add basic zones for G513RC 2025-02-03 07:36:32 +05:30
Luke Jones
dac35996b1 Enable use of GAMESCOPE_WAYLAND_DISPLAY 2025-02-02 20:02:51 +13:00
Luke Jones
5c2bcad7c6 Various UI fixes 2025-02-01 20:31:09 +13:00
sergik776
a206591e97 Added translation files for rog-control-center (RU) 2025-01-28 20:09:20 +02:00
armdebug
81f6c18a24 Update 'led-mode' -> 'aura' in example command.
led-mode is renamed to aura in 19ffcf3376
2025-01-28 02:18:56 +05:30
riarumoda
bcc3d42789 feat (rog-aura): ASUS TUF FA617NS AURA Support 2025-01-23 15:14:52 +08:00
Luke Jones
36c34cb3dd Merge branch 'fix/anime-animation-crash' into 'main'
fix: Use spawn instead of spawn_local in anime animation callback

Closes #588

See merge request asus-linux/asusctl!213
2025-01-22 02:05:04 +00:00
I-Al-Istannen
9b82b875f1 fix: Use spawn instead of spawn_local in anime animation callback
Closes #588
2025-01-21 21:04:20 +01:00
Luke D. Jones
bddccc696f Update deps 2025-01-21 19:49:20 +13:00
Luke D. Jones
51e9f10087 Prep 6.1.0-rc7 2025-01-21 16:44:58 +13:00
Luke D. Jones
911ff8690e feature: rework PPT tuning handling more
1. Per profile, per-ac/dc
2. Do not apply unless group is enabled
3. Better reset/disable handling
4. Selecting a profile defaults PPT to off/disabled
2025-01-21 16:39:34 +13:00
Luke D. Jones
25823dc6b7 asusd: anime: don't cause async deadlocks damnit
Same old song, an async mutex lock being held for a wide scope.
In particular being held for a scope that includes a function call which
also tries to get the lock.

Fix it by copy/clone of the config interior values required.

Fixes #588
2025-01-21 12:24:24 +13:00
Luke D. Jones
cba8e1a473 Add extra debug logging to anime path 2025-01-20 13:43:38 +13:00
Luke D. Jones
fb98827a1a Prep 6.1.0-rc6 2025-01-19 23:35:32 +13:00
Luke D. Jones
b9296862df Move entirely to using only platform-profile
throttle_thermal_policy is not ideal anymore and may be
removed from kernel in the future.
2025-01-19 21:52:32 +13:00
Luke D. Jones
450205f9a9 Bug fix: correctly set charge limit from UI 2025-01-19 17:29:36 +13:00
Luke D. Jones
82431ee25b Prep 6.1.0-rc5 2025-01-19 16:11:48 +13:00
Luke D. Jones
f11aea02a8 Add help and reset to UI for ppt values 2025-01-19 16:01:57 +13:00
Luke D. Jones
2d6d669c22 PPT restor defaults (WIP) 2025-01-19 12:02:22 +13:00
Luke D. Jones
f9cebf9221 Per-AC/DC per-profile tunings enabled 2025-01-19 11:33:48 +13:00
Luke D. Jones
a00808313e Prep 6.1.0-rc4 2025-01-18 23:11:46 +13:00
Luke D. Jones
3426591d32 Finalise per-profile PPT settings 2025-01-18 22:46:50 +13:00
Luke D. Jones
ef3b6636f5 Allow each performance profile to have different PPT values 2025-01-18 21:54:37 +13:00
Luke D. Jones
ee9e0a1e31 Fix: ROGCC: fix anime matrix settings 2025-01-18 21:27:57 +13:00
Luke D. Jones
9e84997cbf Fix: ROGCC: don't crash out if no tray area available 2025-01-18 20:54:25 +13:00
Luke D. Jones
2b22f82b72 Cleanup unsafe sysfs interfaces. Bugfixes for UI 2025-01-16 23:56:12 +13:00
Luke D. Jones
7a1b45071d Correct changelog rc3 tag 2025-01-15 22:25:24 +13:00
Luke D. Jones
ad63c429cb Bugfix: urgent small fixes 2025-01-15 22:19:46 +13:00
Luke D. Jones
a790d9a499 Remove dangerous use of ppt* in platform, add use of ppt_pl3_fppt in asus_armoury handler 2025-01-13 23:18:19 +13:00
Luke D. Jones
be51a1ab77 Disable strip in Makefile 2025-01-13 22:38:30 +13:00
Luke D. Jones
d9a88e7cc3 Notify user via message in UI if asus-armoury not loaded 2025-01-13 14:32:13 +13:00
Luke D. Jones
d785e17f95 Allow version in makefile to have '-rc*' 2025-01-12 18:52:45 +13:00
Luke D. Jones
efe64119c6 Prep 6.1.0-rc2 2025-01-12 17:53:32 +13:00
Luke D. Jones
128bc3fce1 Update readme, slash configs 2025-01-12 17:51:43 +13:00
Luke D. Jones
2123f369ad Small clippy cleanups 2025-01-04 20:04:07 +13:00
Luke D. Jones
2b7a2a5be3 Remove typeshare use 2025-01-03 16:37:22 +13:00
Luke D. Jones
1d9e89ef3d Update deps 2025-01-02 19:08:48 +13:00
Luke D. Jones
4011b3ebd4 ROGCC: begin using the new asus_armoury API 2025-01-01 14:47:08 +13:00
Luke D. Jones
f7456f0144 Allow changing of platform values with cli 2024-12-29 12:03:50 +13:00
Luke D. Jones
2ed2d82e03 Better print of firmware attributes in CLI 2024-12-29 11:36:22 +13:00
Luke D. Jones
d40f4733e2 Fix: prevent event loop error in ROGCC
Leftover code from parts of the refactor and tray crate change were
causing the app to crash due to the UI trying to issue a command on the
slint thread when the slint thread had not been created yet.

Closes #579
2024-12-28 22:06:16 +13:00
Luke Jones
98dc155e41 Merge branch 'feat/add-g533qs' into 'main'
feat(rog-aura): 🎸 Add G533QS aura support

See merge request asus-linux/asusctl!210
2024-12-28 04:32:17 +00:00
Luke D. Jones
fd3384decc Minor test of platform attributes 2024-12-28 10:56:34 +13:00
Luke D. Jones
a1a9c7077a Rename dbus. Add asus_armoury client source 2024-12-26 21:36:07 +13:00
Luke D. Jones
62aa1fe04f Add initial dbus draft of asus_armoury attrs 2024-12-26 16:41:17 +13:00
kamack38
72c0b24ead feat(rog-aura): 🎸 Add G533QS aura support 2024-12-23 00:18:46 +01:00
Rəşad Qasımlı
c5c5a9ac67 Update rog-control-center.mo 2024-07-20 14:35:45 +04:00
Rəşad Qasımlı
b84bc61f3d Update the information about translator 2024-07-20 00:59:47 +04:00
Rəşad Qasımlı
b4e38e0814 Add Azerbaijani language 2024-07-19 23:47:41 +04:00
155 changed files with 15987 additions and 6133 deletions

53
.cargo-husky/hooks/post-commit Executable file
View File

@@ -0,0 +1,53 @@
#!/bin/sh
set -e
ROOT_DIR=$(git rev-parse --show-toplevel)
AURA_DATA="${ROOT_DIR}/rog-aura/data/aura_support.ron"
SPEC_FILE="${ROOT_DIR}/distro-packaging/asusctl.spec"
TRANSLATION="${ROOT_DIR}/rog-control-center/translations/en/rog-control-center.po"
VERSION=$(grep -Pm1 'version = "(\d+.\d+.\d+.*)"' "${ROOT_DIR}/Cargo.toml" | cut -d'"' -f2)
if [ -z "$VERSION" ]; then
echo "Error: Could not extract version from Cargo.toml"
exit 1
fi
if [ ! -f "$SPEC_FILE" ]; then
echo "Error: Spec file not found at ${SPEC_FILE}"
exit 1
fi
# Update spec file
sed -i "s/^%define version.*/%define version ${VERSION}/" "$SPEC_FILE"
if git diff --quiet "$SPEC_FILE"; then
echo "No changes to spec file"
else
git add "$SPEC_FILE"
git commit --no-verify -m "chore: update spec file version to ${VERSION}"
echo "Updated spec file version to ${VERSION}"
fi
# Update translations only if UI files changed
if git diff-tree -r HEAD@{1} HEAD --name-only | grep -q "^rog-control-center/ui/"; then
echo 'find -name \*.slint | xargs slint-tr-extractor -o ${TRANSLATION}'
find -name \*.slint | xargs slint-tr-extractor -o $TRANSLATION
if git diff --quiet "$TRANSLATION"; then
echo "No changes to translation file"
else
git add "$TRANSLATION"
git commit --no-verify -m "chore: update translations"
echo "Updated ${TRANSLATION}"
fi
else
echo "No changes in rog-control-center/ui/, skipping translation update"
fi
# Update aura data
cargo test --package rog_aura --lib -- aura_detection::tests::check_data_file_parse --exact
cargo test --package rog_aura --lib -- aura_detection::tests::find_data_file_groups --exact
if git diff --quiet "$AURA_DATA"; then
echo "No changes to aura data file"
else
git add "$AURA_DATA"
git commit --no-verify -m "chore: update aura data"
echo "Updated $AURA_DATA"
fi

View File

@@ -1,18 +1,6 @@
#!/bin/sh
set -e
echo 'find -name \*.slint | xargs slint-tr-extractor -o rog-control-center/translations/en/rog-control-center.po'
find -name \*.slint | xargs slint-tr-extractor -o rog-control-center/translations/en/rog-control-center.po
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 -- --test-threads=1
echo '+cargo cranky'
cargo cranky
echo '+cargo fmt --all -- --check'
cargo fmt --all -- --check
git add -u

View File

@@ -2,8 +2,8 @@
set -e
echo '+cargo +nightly fmt --all -- --check'
cargo +nightly fmt --all -- --check
echo '+cargo fmt --all -- --check'
cargo fmt --all -- --check
echo '+cargo clippy --all -- -D warnings'
cargo clippy --all -- -D warnings
echo '+cargo cranky'

View File

@@ -8,6 +8,9 @@ indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
[*.slint]
indent_size = 4
[*.md]
trim_trailing_whitespace = false

6
.gitignore vendored
View File

@@ -9,6 +9,7 @@ vendor_*
.vscode
.~lock.*
*.ods#
*.patch
# gnome extension
node-modules
@@ -19,3 +20,8 @@ desktop-extensions/gnome*/@types/gir-generated
desktop-extensions/gnome*/node_modules
desktop-extensions/gnome*/schemas/gschemas.compiled
desktop-extensions/gnome*/*.zip
# agents and reference
CLAUDE.md
AGENTS.md
/reference

View File

@@ -1,22 +1,26 @@
image: rust:latest
# Use shallow clone to reduce checkout size
variables:
GIT_DEPTH: "1"
# Put cargo home and target under project dir so we can clean them easily
CARGO_HOME: "$CI_PROJECT_DIR/.cargo"
CARGO_TARGET_DIR: "$CI_PROJECT_DIR/ci-target"
GIT_SUBMODULE_STRATEGY: normal
# Cache only cargo registries/git metadata to speed dependency fetches.
# Avoid caching compiled `target` artifacts which are large and easily fill disk.
.rust_cache: &rust_cache
cache:
# key: $CI_COMMIT_REF_SLUG
key: "$CI_JOB_NAME-$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
- .cargo/registry
- .cargo/git
before_script:
- df -h
- echo "Cleaning stale targets to free space if present"
- rm -rf "$CI_PROJECT_DIR/target" "$CI_PROJECT_DIR/ci-target" || true
- apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev grep llvm clang libclang-dev libsdl2-dev libsdl2-gfx-dev
stages:
@@ -31,20 +35,24 @@ format:
- tags
<<: *rust_cache
script:
- echo "nightly" > rust-toolchain
- rustup component add rustfmt
- rustup component add rustfmt || true
- cargo fmt --check
after_script:
- du -sh "$CI_PROJECT_DIR/ci-target" || true
- rm -rf "$CI_PROJECT_DIR/ci-target" || true
check:
except:
- tags
<<: *rust_cache
script:
- rustup component add clippy
- cargo check
- rustup component add clippy || true
- cargo check --locked --workspace
# deny currently catches too much
#- cargo install cargo-deny && cargo deny
- cargo install cargo-cranky && cargo cranky
after_script:
- rm -rf "$CI_PROJECT_DIR/ci-target" || true
test:
except:
@@ -52,7 +60,9 @@ test:
<<: *rust_cache
script:
- mkdir -p .git/hooks > /dev/null
- cargo test --all -- --test-threads=1
- cargo test --locked --all
after_script:
- rm -rf "$CI_PROJECT_DIR/ci-target" || true
release:
only:
@@ -60,11 +70,15 @@ release:
<<: *rust_cache
script:
- cargo install cargo-vendor-filterer
- make && make vendor
- cargo fetch
- make FROZEN=1 && make vendor
artifacts:
paths:
- vendor_asusctl*.tar.xz
- cargo-config
expire_in: 1 week
after_script:
- rm -rf vendor vendor_asusctl*.tar.xz "$CI_PROJECT_DIR/ci-target" || true
pages:
stage: deploy
@@ -72,14 +86,14 @@ pages:
- tags
<<: *rust_cache
script:
- cargo doc --document-private-items --no-deps --workspace
- cargo doc --locked --document-private-items --no-deps --workspace
- rm -rf public
- mkdir public
- cp -R target/doc/* public
- cp extra/index.html public
- cp -R ci-target/doc/* public
- if [ -f extra/index.html ]; then cp extra/index.html public; else echo "no extra/index.html to copy"; fi
artifacts:
paths:
- public
variables:
GIT_SUBMODULE_STRATEGY: normal
expire_in: 1 week
after_script:
- rm -rf "$CI_PROJECT_DIR/ci-target" || true

View File

@@ -1,6 +1,221 @@
# Changelog
## [Unreleased]
## [6.3.2]
### Changes
- Improve the notification area, @shevchenko0013 strikes again!
- Improve firmware attributes handling
- Very good looking UI restyling from @shevchenko0013
- Added support for GA402NV matrix: thanks @Ghoul4500
- Fixed aura CLI interface
- Fixed LEDs handling in rogcc
## [6.3.1]
### Changes
- Removed a lighting mode that is unavailable in windows to G835L: thanks to @shevchenko0013 again!
- Added translations for Ukranian language, thanks @shevchenko0013!
- Added LEDs definition for G615LR, thanks @btnrv
- Fix improper usage of Quiet when only LowPower is available
## [6.3.0]
### Changed
- Added support for TUF keyboard powerstate control
- Improved AniMe Matrix support thanks to @Seom1177 !
- Fixed a bug with one-shot battery change, thanks @bitr8 !
- Changed the CLI interface of asusctl to be less confusing
- Added support for G835L, thanks to @shevchenko0013 !
## [6.2.0]
### Changed
- Added aura support for FX607V: thanks @jomp16
- Added testing support for G835LW
- Added support for GU605C models slash lighting: thanks @Otters
- Restore fedora: thanks @ali205412
- Add support to G614F models slash lighting
## [6.1.22]
### Changed
- Allow configuration of nv_tgp
- Treat dGPU attributes as power profiles
- Add EXPERTBOOK DMI match to ensure the service is loaded
- Support G815L thanks to @solost !
## [6.1.21]
### Changed
- Kill Fedora: screw your cursed cargo bullshit
- Restore CI building
## [6.1.20]
### Changed
- Addded support for G635L: thanks @luca_pisl !
- Suppress verbose output in applications too, not just daemon
## [6.1.18]
### Changed
- Add aura support for G614FR (ROG Strix G16 2025)
- all notifications now respects the timeout
- improve udev daemon-starting rule
- reduce log noise
## [v6.1.17]
### Changed
- Fix Makefile
- Share a single HID device
## [v6.1.16]
### Changed
- Expose more properties via rog-control-center
- Add support for a few more models
## [v6.1.15]
### Changed
- Reflect the current asus-armoury status on AC plug connection status change
## [v6.1.14]
### Changed
- Fix formatting
- Attempt to fix tests
## [v6.1.13]
### Changed
- Fix a problem in reloading the service (@evertvorster)
- Add Azerbaijani language (@rashadgasimli)
- Add Ubuntu installation instructions
## [v6.1.12]
### Changed
- Fix an unbounded event loop caused by other processes causing a "modify" event on the screen backlight brightness.
## [v6.1.11]
### Changed
- Fix anime flickering issue when using custom anims (@I-Al-Istannen)
- Include pt_BR translations file (@PabloKiryu)
## Added
- Support for the screenpad brightness on some Laptops. This includes syncing to the primary screen brightness, and a gamma adjustment to set brightness scaling.
- Add asusctl CLI options
- Add UI options
- Add a fake gamma correction (`asusctl backlight --sync-screenpad-brightness`, 1.5 for example sets screenpad low brightness lower than primary, and scales upwards)
### Changed
- asusd: single line fix for profile switching
## [v6.1.9]
### Changed
- ROGCC: better handling of platform profiles
## [v6.1.8]
### Changed
- Testing CI for opensuse RPM build
- ROGCC: Fixes to showing the PPT enablement toggle
- ROGCC: Fixes to how PPT and NV sliders work and enable/disable
- RGOCC: Fix quiet fan-curves availability
## [v6.1.7]
### Changed
- Fix Slash display enable
## [v6.1.6]
### Changed
- Disable skia bindings for UI again. It causes failures in build pipelines and requires extra dependencies.
## [v6.1.5]
### Changed
- Update dependencies
- Fix fan-curve proxy type signatures
## [v6.1.4]
### Changed
- Fix git doing me a dirty
## [v6.1.3]
### Changed
- Many small bugfixes such as for platform profile switching
## [v6.1.2]
### Changed
- Try a slightly different tact to fix charge control slider
## [v6.1.1]
### Changed
- Fix aura data matching
- Fix charge control slider
## [v6.1.0]
### Changed
- Update deps
- Add support for G513RC RGB modes
- Many UI fixes
- Fixes to PPT settings in UI
## [v6.1.0-rc7]
- Refactor PPT handling more:
1. Per profile, per-ac/dc
2. Do not apply unless group is enabled
3. Better reset/disable handling
4. Selecting a profile defaults PPT to off/disabled
- Bugfix: prevent an AniMe thread async deadlock
## [v6.1.0-rc6]
### Changed
- Two small fixes, one for `low-power` profile name, and one for base gpu tdp
- Move to using platform_profile api only (no throttle_thermal_policy)
## [v6.1.0-rc5]
### Changed
- Per-AC/DC, per-profile tunings enabled (Battery vs AC power + platform profile)
- Add ability to restore PPT defaults
- Add PPT help dialogue to UI
- Bug fix: correctly set charge limit from UI
## [v6.1.0-rc4]
### Changed
- Bug fix: UI was setting incorrect value for FPPT
- Bug fix: Re-add callbacks for the throttle and epp settings in UI
- Bug fix: Fix UI settigns for AniMe Matrix display
- Bug fix: better handle missing tray (for example gnome)
- Strip out all outdated and unsafe tuning stuff
- Allow each performance profile to have different PPT settings
## [v6.1.0-rc3]
### Changed
- Bug fixes
- Partial support for per-profile CPU tunings (WIP)
## [v6.1.0-rc2]
### Added
- asus-armoury driver support. WIP, will be adjusted/changed further
- More "Slash" display controls
## [v6.1.0-rc1]

3915
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,12 @@
[workspace.package]
version = "6.1.0-rc1"
version = "6.3.1"
rust-version = "1.82"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
authors = [
"Luke <luke@ljones.dev>",
"Denis Benato <benato.denis96@gmail.com>"
]
repository = "https://gitlab.com/asus-linux/asusctl"
homepage = "https://gitlab.com/asus-linux/asusctl"
description = "Laptop feature control for ASUS ROG laptops and others"
@@ -12,48 +15,43 @@ edition = "2021"
[workspace]
resolver = "2"
members = [
"asusctl",
"asusd",
"asusd-user",
"config-traits",
"cpuctl",
"dmi-id",
"rog-platform",
"rog-dbus",
"rog-anime",
"rog-aura",
"rog-profiles",
"rog-control-center",
"rog-slash",
"simulators", "rog-scsi",
]
default-members = [
"asusctl",
"asusd",
"asusd-user",
"cpuctl",
"rog-control-center",
"asusctl",
"asusd",
"asusd-user",
"config-traits",
"dmi-id",
"rog-platform",
"rog-dbus",
"rog-anime",
"rog-aura",
"rog-profiles",
"rog-control-center",
"rog-slash",
"simulators",
"rog-scsi",
]
default-members = ["asusctl", "asusd", "asusd-user", "rog-control-center"]
[workspace.dependencies]
tokio = { version = "^1.39.0", default-features = false, features = [
"macros",
"sync",
"time",
"rt",
"rt-multi-thread",
"macros",
"sync",
"time",
"rt",
"rt-multi-thread",
] }
concat-idents = "^1.1"
dirs = "^4.0"
smol = "^2.0"
mio = "0.8.11"
zbus = "5.1"
logind-zbus = { version = "5.0.0" } #, default-features = false, features = ["non_blocking"] }
futures-util = "0.3.31"
zbus = "5.13.1"
logind-zbus = { version = "5.2.0" } #, default-features = false, features = ["non_blocking"] }
serde = { version = "^1.0", features = ["serde_derive"] }
ron = "*"
typeshare = "1.0.0"
log = "^0.4"
env_logger = "^0.10.0"
@@ -62,18 +60,18 @@ glam = { version = "^0.22", features = ["serde"] }
gumdrop = "^0.8"
udev = { version = "^0.8", features = ["mio"] }
rusb = "^0.9"
inotify = "^0.10.0"
inotify = "^0.10"
png_pong = "^0.8"
pix = "^0.13"
tinybmp = "^0.4.0"
gif = "^0.12.0"
tinybmp = "^0.4"
gif = "^0.12"
versions = "6.2"
notify-rust = { version = "4.11.0", features = ["z", "async"] }
notify-rust = { version = "4.11.5", features = ["z", "async"] }
sg = {git = "https://github.com/flukejones/sg-rs.git"}
sg = { git = "https://github.com/flukejones/sg-rs.git" }
[profile.release]
# thin = 57s, asusd = 9.0M
@@ -82,15 +80,15 @@ lto = "fat"
debug = false
opt-level = 3
panic = "abort"
codegen-units = 1
# codegen-units = 1
[profile.dev]
opt-level = 1
codegen-units = 16
# codegen-units = 1
[profile.dev.package."*"]
opt-level = 1
codegen-units = 16
# codegen-units = 1
[profile.bench]
debug = false

View File

@@ -48,7 +48,7 @@ The LED controller (e.g, aura) enables setting many of the factory modes availab
#### Supported laptops
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).
There are over 80 supported laptops as of 01-01-2023. Please see [the rog-aura crate readme for further details](/rog-aura/README.md).
### Charge control
@@ -420,13 +420,13 @@ To switch to next/previous Aura modes you will need to bind both the aura keys (
**Next**
```
asusctl led-mode -n
asusctl aura -n
```
**Previous**
```
asusctl led-mode -p
asusctl aura -p
```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.

View File

@@ -1,4 +1,4 @@
VERSION := $(shell /usr/bin/grep -Pm1 'version = "(\d+.\d+.\d+)"' 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
@@ -17,9 +17,11 @@ BIN_D := asusd
BIN_U := asusd-user
LEDCFG := aura_support.ron
DESTDIR_REALPATH = $(shell realpath $(DESTDIR))
SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
STRIP_BINARIES ?= 1
STRIP_BINARIES ?= 0
DEBUG ?= 0
ifeq ($(DEBUG),0)
@@ -35,6 +37,15 @@ ifeq ($(X11),1)
ARGS += --features "rog-control-center/x11"
endif
# Always use the versions in Cargo.lock by default
ARGS += --locked
# Allow optionally freezing the build to avoid any network access and enforce Cargo.lock strictly
FROZEN ?= 0
ifeq ($(FROZEN),1)
ARGS += --frozen
endif
VENDORED ?= 0
ifeq ($(VENDORED),1)
ARGS += --frozen
@@ -48,24 +59,38 @@ clean:
distclean:
rm -rf .cargo vendor vendor.tar.xz
install-program:
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_ROG)" "$(DESTDIR)$(bindir)/$(BIN_ROG)"
target/$(TARGET)/$(BIN_D): $(SRC)
$(MAKE) build
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
target/$(TARGET)/$(BIN_C): $(SRC)
$(MAKE) build
target/$(TARGET)/$(BIN_U): $(SRC)
$(MAKE) build
target/$(TARGET)/$(BIN_ROG): $(SRC)
$(MAKE) build
install-asusd: target/$(TARGET)/$(BIN_D)
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
install-asusctl: target/$(TARGET)/$(BIN_C)
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
install-asusd_user: target/$(TARGET)/$(BIN_U)
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)"
install-data:
install-rog_gui: target/$(TARGET)/$(BIN_ROG)
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_ROG)" "$(DESTDIR)$(bindir)/$(BIN_ROG)"
.PHONY: install-asusd install-asusctl install-asusd_user install-rog_gui
install-program: install-asusd install-asusctl install-asusd_user install-rog_gui
install-data-rog_gui:
$(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) "./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_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
cd rog-aura/data/layouts && find . -type f -name "*.ron" -exec $(INSTALL_DATA) "{}" "$(DESTDIR_REALPATH)$(datarootdir)/rog-gui/layouts/{}" \;
$(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"
@@ -81,9 +106,24 @@ install-data:
$(INSTALL_DATA) "./data/icons/scalable/gpu-vfio.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-vfio.svg"
$(INSTALL_DATA) "./data/icons/scalable/notification-reboot.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/notification-reboot.svg"
cd rog-anime/data && find "./anime" -type f -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \;
install-data-asusd:
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
$(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"
cd rog-anime/data && find "./anime" -type f -exec $(INSTALL_DATA) "{}" "$(DESTDIR_REALPATH)$(datarootdir)/asusd/{}" \;
install-data-asusd_user:
$(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
.PHONY: install-data-asusd install-data-asusd_user
install-data: install-data-asusd install-data-asusd_user install-data-rog_gui
install: install-program install-data
$(INSTALL_DATA) "./LICENSE" "$(DESTDIR)$(datarootdir)/asusctl/LICENSE"
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_ROG)"
@@ -118,16 +158,12 @@ vendor:
mv .cargo/config ./cargo-config
rm -rf .cargo
rm -rf vendor
# Ensure cargo-vendor-filterer is installed (CI installs it already)
command -v cargo-vendor-filterer >/dev/null 2>&1 || cargo install --locked cargo-vendor-filterer
cargo vendor-filterer --all-features --platform x86_64-unknown-linux-gnu vendor
tar pcfJ vendor_asusctl_$(VERSION).tar.xz vendor
rm -rf vendor
bindings:
typeshare ./rog-anime/src/ --lang=typescript --output-file=bindings/ts/anime.ts
typeshare ./rog-aura/src/ --lang=typescript --output-file=bindings/ts/aura.ts
typeshare ./rog-profiles/src/ --lang=typescript --output-file=bindings/ts/profiles.ts
typeshare ./rog-platform/src/ --lang=typescript --output-file=bindings/ts/platform.ts
translate:
find -name \*.slint | xargs slint-tr-extractor -o rog-control-center/translations/en/rog-control-center.po

View File

@@ -1,6 +1,6 @@
# `asusctl` for ASUS ROG
[Become a Patron!](https://www.patreon.com/bePatron?u=7602281) - [Asus Linux Website](https://asus-linux.org/)
[![Become a Patron!](https://github.com/codebard/patron-button-and-widgets-by-codebard/blob/master/images/become_a_patron_button.png?raw=true)](https://www.patreon.com/bePatron?u=7602281) [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/V7V5CLU67) - [Asus Linux Website](https://asus-linux.org/)
**WARNING:** Many features are developed in tandem with kernel patches. If you see a feature is missing you either need a patched kernel or latest release.
@@ -11,9 +11,9 @@ Now includes a GUI, `rog-control-center`.
## Kernel support
**The minimum supported kernel version is 6.10**, which will contain the patches from [here](https://lore.kernel.org/platform-driver-x86/20240404001652.86207-1-luke@ljones.dev/). This is especially required for 2023+ devices and possibly some late 2022 devices.
Due to on-going driver work the minimum suggested kernel version is always **the latest*, as improvements and fixes are continuous.
Z13 devices will need [these](https://lore.kernel.org/linux-input/20240416090402.31057-1-luke@ljones.dev/T/#t)
Support for TDP is tied to the new asus-armoury driver: available mainline since linux 6.19: everything older is not supported.
## X11 support
@@ -37,20 +37,20 @@ See the [rog-aura readme](./rog-aura/README.md) for more details.
## Discord
[![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/z8y99XqPb7)
[![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/B8GftRW2Hd)
## SUPPORTED LAPTOPS
Most ASUS gaming laptops that have a USB keyboard. If `lsusb` shows something similar
to this:
```
```plain
Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
```
or
```
```plain
Bus 003 Device 002: ID 0b05:19b6 ASUSTek Computer, Inc. [unknown]
```
@@ -72,43 +72,56 @@ The list is a bit outdated as many features have been enabled in the Linux kerne
- [x] Toggle bios setting for boot/POST sound
- [x] Toggle GPU MUX (g-sync, or called MUX on 2022+ laptops)
# GUI
## GUI
A gui is now in the repo - ROG Control Center. At this time it is still a WIP, but it has almost all features in place already.
**NOTE**: Xorg is not supported.
# BUILDING
## BUILDING
Rust and cargo are required, they can be installed from [rustup.rs](https://rustup.rs/) or from the distro repos if newer than 1.75.
Rust and cargo are required, they can be installed from [rustup.rs](https://rustup.rs/).
Distro packaging should work with the stable toolchain. If your distro does not provide a recent Rust toolchain, install rustup and use the stable toolchain.
**fedora:**
dnf install cmake clang-devel libxkbcommon-devel systemd-devel expat-devel pcre2-devel libzstd-devel gtk3-devel
make
sudo make install
```sh
dnf install cmake clang-devel libxkbcommon-devel systemd-devel expat-devel pcre2-devel libzstd-devel gtk3-devel
make
sudo make install
```
**openSUSE:**
Works with KDE Plasma (without GTK packages)
zypper in -t pattern devel_basis
zypper in rustup make cmake clang-devel libxkbcommon-devel systemd-devel expat-devel pcre2-devel libzstd-devel gtk3-devel
make
sudo make install
```sh
zypper in -t pattern devel_basis
zypper in rustup make cmake clang-devel libxkbcommon-devel systemd-devel expat-devel pcre2-devel libzstd-devel gtk3-devel
make
sudo make install
```
**Debian(unsuported):**
officially unsuported,but you can still try and test it by yourself(some features may not be available).
sudo apt install libclang-dev libudev-dev libfontconfig-dev build-essential cmake libxkbcommon-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
make
sudo make install
```sh
sudo apt install libclang-dev libudev-dev libfontconfig-dev build-essential cmake libxkbcommon-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
make
sudo make install
```
**Ubuntu, Popos (unsuported):**
instructions removed as outdated
```sh
sudo apt install make cargo gcc pkg-config openssl libasound2-dev cmake build-essential python3 libfreetype6-dev libexpat1-dev libxcb-composite0-dev libssl-dev libx11-dev libfontconfig1-dev curl libclang-dev libudev-dev checkinstall libseat-dev libinput-dev libxkbcommon-dev libgbm-dev
make
sudo make install
```
## Installing
@@ -126,15 +139,15 @@ You may also need to activate the service for debian install. If running Pop!\_O
If you are upgrading from a previous installed version, you will need to restart the service or reboot.
```
$ systemctl daemon-reload && systemctl restart asusd
```sh
systemctl daemon-reload && systemctl restart asusd
```
## Uninstalling
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
# Contributing
## 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`).
@@ -142,17 +155,17 @@ Generation of the bindings with `make bindings` requires `typeshare` to be insta
Dbus introsepction XML requires with `make introspection` requires `anime_sim` to be running before starting `asusd`.
# OTHER
## OTHER
## AniMe Matrix simulator
### AniMe Matrix simulator
A simulator using SDL2 can be built using `cargo build --package rog_simulators` and run with `./target/debug/anime_sim`. Once started `asusd` will need restarting to pick it up. If running this sim on a laptop _with_ the display, the simulated display will be used instead of the physical display.
## Supporting more laptops
### Supporting more laptops
Please file a support request.
# License & Trademarks
## License & Trademarks
Mozilla Public License 2 (MPL-2.0)
@@ -165,3 +178,7 @@ Reference to any ASUS products, services, processes, or other information and/or
The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops.
---
## AI Disaclaimer
Portions of this code have been written by various AI tools and reviewed by the maintainer exaclty as with every other contribution.

View File

@@ -18,10 +18,25 @@ rog_profiles = { path = "../rog-profiles" }
rog_platform = { path = "../rog-platform" }
dmi_id = { path = "../dmi-id" }
log.workspace = true
env_logger.workspace = true
ron.workspace = true
gumdrop.workspace = true
zbus.workspace = true
argh = "0.1"
[dev-dependencies]
rog_dbus = { path = "../rog-dbus" }
[package.metadata.deb]
license-file = ["../LICENSE", "4"]
extended-description = """\
An utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
["target/release/asusctl", "usr/bin/", "755"],
]

View File

@@ -0,0 +1,547 @@
//! LED scanning tool for discovering AniMe Matrix buffer-to-LED mappings.
//!
//! This tool lights up one buffer index at a time, allowing you to observe
//! which physical LED corresponds to each buffer position. This is essential
//! for mapping new device types like G835L where the exact layout is unknown.
//!
//! You might want to use it slowly, as it sometimes doesn't work properly.
//! Maybe there's better ways to make this reliable but for now it works for my use case.
//!
//! # Usage
//! ```
//! cargo run --example anime-led-scan -- [options]
//! ```
//!
//! # Controls
//! - `n` or `Enter`: Next index
//! - `p` or `Backspace`: Previous index
//! - `j` followed by number: Jump to specific index
//! - `+` / `-`: Adjust step size (default 1)
//! - `s`: Save current index to notes file
//! - `r`: Mark current index as row start
//! - `q` or `Ctrl+C`: Quit
//!
//! # Output
//! Creates a `led-scan-notes.txt` file with recorded observations.
use std::env;
use std::fs::OpenOptions;
use std::io::{self, BufRead, Write};
use rog_anime::usb::{get_anime_type, Brightness};
use rog_anime::{AnimeDataBuffer, AnimeType};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
/// Saved device state for restoration on exit
struct SavedState {
builtins_enabled: bool,
brightness: Brightness,
display_enabled: bool,
}
fn print_help(scan_len: usize, buffer_len: usize) {
println!("\n=== LED Scan Tool ===");
println!(
"Scan range: 0-{} (buffer size: {})",
scan_len - 1,
buffer_len
);
println!("Commands:");
println!(" n, Enter - Next index");
println!(" p, Backspace - Previous index");
println!(" j <num> - Jump to index");
println!(" + / - - Increase/decrease step size");
println!(" s - Save note for current index");
println!(" r - Mark as row start");
println!(" a - Auto-scan (runs through all indices)");
println!(" f - Fill all buffer bytes");
println!(" f <start> <end> - Fill range (inclusive)");
println!(" p1/p2/p3 - Fill pane 1/2/3 only (each is 627 bytes)");
println!(" hold - Hold current LED (press Enter to release)");
println!(" hold <s> <e> - Hold range (press Enter to release)");
println!(" c - Clear display");
println!(" row - Step through rows (G835L, provisional)");
println!(" row <n> - Show specific row (G835L, provisional)");
println!(" allrows - Light all rows sequentially (G835L)");
println!(" rowmap - Print the full row mapping (G835L)");
println!(" h - Show this help");
println!(" q - Quit and restore state");
println!();
}
fn save_note(index: usize, note: &str) -> io::Result<()> {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open("led-scan-notes.txt")?;
writeln!(file, "Index {}: {}", index, note)?;
Ok(())
}
fn write_single_led(
proxy: &AnimeProxyBlocking,
anime_type: AnimeType,
index: usize,
brightness: u8,
) {
let mut buffer = AnimeDataBuffer::new(anime_type);
let data = buffer.data_mut();
if index < data.len() {
data[index] = brightness;
}
if let Err(e) = proxy.write(buffer) {
eprintln!("Error writing to device: {}", e);
}
}
fn clear_display(proxy: &AnimeProxyBlocking, anime_type: AnimeType) {
let buffer = AnimeDataBuffer::new(anime_type);
let _ = proxy.write(buffer);
}
fn fill_display(proxy: &AnimeProxyBlocking, anime_type: AnimeType, brightness: u8) {
let mut buffer = AnimeDataBuffer::new(anime_type);
let data = buffer.data_mut();
for byte in data.iter_mut() {
*byte = brightness;
}
if let Err(e) = proxy.write(buffer) {
eprintln!("Error writing to device: {}", e);
}
}
/// Fill a range of LEDs. Both start and end are INCLUSIVE.
fn fill_range(
proxy: &AnimeProxyBlocking,
anime_type: AnimeType,
start: usize,
end: usize,
brightness: u8,
) {
let mut buffer = AnimeDataBuffer::new(anime_type);
let data = buffer.data_mut();
for i in start..=end.min(data.len().saturating_sub(1)) {
data[i] = brightness;
}
if let Err(e) = proxy.write(buffer) {
eprintln!("Error writing to device: {}", e);
}
}
fn fill_pane(proxy: &AnimeProxyBlocking, anime_type: AnimeType, pane: usize, brightness: u8) {
const PANE_LEN: usize = 627;
let start = pane * PANE_LEN;
let end = start + PANE_LEN - 1;
fill_range(proxy, anime_type, start, end, brightness);
}
/// G835L row pattern (PROVISIONAL - needs hardware verification):
/// - Rows 0-1: 1 LED each
/// - Rows 2-3: 2 LEDs each
/// - ... (pairs of rows with same length)
/// - Rows 26-27: 14 LEDs each
/// - Rows 28+: 15 LEDs each (constant)
///
/// Returns (start_index, end_index_inclusive, row_length)
fn g835l_row_bounds(row: usize) -> (usize, usize, usize) {
let triangle_rows = 28;
let triangle_leds = 210;
if row < triangle_rows {
let length = row / 2 + 1;
let mut start = 0usize;
for r in 0..row {
start += r / 2 + 1;
}
(start, start + length - 1, length)
} else {
let rows_after_triangle = row - triangle_rows;
let start = triangle_leds + rows_after_triangle * 15;
(start, start + 14, 15)
}
}
fn g835l_total_rows() -> usize {
28 + 40
}
fn save_state(proxy: &AnimeProxyBlocking) -> SavedState {
SavedState {
builtins_enabled: proxy.builtins_enabled().unwrap_or(false),
brightness: proxy.brightness().unwrap_or(Brightness::Med),
display_enabled: proxy.enable_display().unwrap_or(true),
}
}
fn restore_state(proxy: &AnimeProxyBlocking, state: &SavedState) {
let _ = proxy.set_builtins_enabled(state.builtins_enabled);
let _ = proxy.set_brightness(state.brightness);
let _ = proxy.set_enable_display(state.display_enabled);
let _ = proxy.run_main_loop(true);
}
fn main() {
let args: Vec<String> = env::args().collect();
let mut start_index = 0usize;
let mut brightness = 200u8;
let mut scan_limit: Option<usize> = None;
let mut i = 1;
while i < args.len() {
match args[i].as_str() {
"--start" | "-s" => {
if i + 1 < args.len() {
start_index = args[i + 1].parse().unwrap_or(0);
i += 1;
}
}
"--brightness" | "-b" => {
if i + 1 < args.len() {
brightness = args[i + 1].parse().unwrap_or(200);
i += 1;
}
}
"--limit" | "-l" => {
if i + 1 < args.len() {
scan_limit = args[i + 1].parse().ok();
i += 1;
}
}
"--help" | "-h" => {
println!("LED Scan Tool for AniMe Matrix");
println!();
println!("Usage: anime-led-scan [options]");
println!();
println!("Options:");
println!(" -s, --start <N> Start at index N (default: 0)");
println!(" -b, --brightness <N> LED brightness 0-255 (default: 200)");
println!(" -l, --limit <N> Cap scan range to N indices (e.g. 810 for G835L)");
println!(" -h, --help Show this help");
return;
}
_ => {}
}
i += 1;
}
let conn = match Connection::system() {
Ok(c) => c,
Err(e) => {
eprintln!("Failed to connect to D-Bus: {}", e);
eprintln!("Make sure asusd is running.");
return;
}
};
let proxy = match AnimeProxyBlocking::new(&conn) {
Ok(p) => p,
Err(e) => {
eprintln!("Failed to create Anime proxy: {}", e);
eprintln!("Make sure asusd supports your device.");
return;
}
};
let anime_type = get_anime_type();
let buffer_len = anime_type.data_length();
let scan_len = scan_limit.unwrap_or(buffer_len).min(buffer_len);
println!("=== LED Scan Tool ===");
println!("Device type: {:?}", anime_type);
println!("Buffer length: {} bytes", buffer_len);
println!("Scan range: 0-{}", scan_len - 1);
println!("Brightness: {}", brightness);
println!();
// Save current state for restoration
let saved_state = save_state(&proxy);
println!("Saved device state for restoration on exit.");
// Stop system animations
if let Err(e) = proxy.run_main_loop(false) {
eprintln!("Warning: Could not stop main loop: {}", e);
}
println!("Stopped system animations.");
print_help(scan_len, buffer_len);
let mut current_index = start_index.min(scan_len - 1);
let mut step = 1usize;
write_single_led(&proxy, anime_type, current_index, brightness);
println!(">>> Index: {} (step: {})", current_index, step);
let stdin = io::stdin();
let mut input = String::new();
loop {
input.clear();
print!("> ");
io::stdout().flush().unwrap();
if stdin.lock().read_line(&mut input).is_err() {
break;
}
let cmd = input.trim();
match cmd {
"q" | "quit" | "exit" => {
clear_display(&proxy, anime_type);
restore_state(&proxy, &saved_state);
println!("Restored device state. Goodbye!");
break;
}
"n" | "" => {
current_index = (current_index + step).min(scan_len - 1);
write_single_led(&proxy, anime_type, current_index, brightness);
println!(">>> Index: {} (step: {})", current_index, step);
}
"p" => {
current_index = current_index.saturating_sub(step);
write_single_led(&proxy, anime_type, current_index, brightness);
println!(">>> Index: {} (step: {})", current_index, step);
}
"+" => {
step = step.saturating_mul(2).max(1);
println!("Step size: {}", step);
}
"-" => {
step = step.saturating_div(2).max(1);
println!("Step size: {}", step);
}
"r" => {
if let Err(e) = save_note(current_index, "ROW START") {
eprintln!("Error saving note: {}", e);
} else {
println!("Saved: Index {} marked as ROW START", current_index);
}
}
"h" | "help" | "?" => {
print_help(scan_len, buffer_len);
}
cmd if cmd.starts_with('j') => {
let num_str = cmd.trim_start_matches('j').trim();
if let Ok(idx) = num_str.parse::<usize>() {
if idx < scan_len {
current_index = idx;
write_single_led(&proxy, anime_type, current_index, brightness);
println!(">>> Index: {} (step: {})", current_index, step);
} else {
println!("Index {} out of range (max: {})", idx, scan_len - 1);
}
} else {
println!("Usage: j <number>");
}
}
cmd if cmd.starts_with('s') && !cmd.starts_with("show") => {
let note = cmd.trim_start_matches('s').trim();
let note = if note.is_empty() { "observed" } else { note };
if let Err(e) = save_note(current_index, note) {
eprintln!("Error saving note: {}", e);
} else {
println!("Saved note for index {}", current_index);
}
}
"a" => {
println!("Auto-scan mode (0 to {})...", scan_len - 1);
let delay = std::time::Duration::from_millis(10);
for idx in current_index..scan_len {
write_single_led(&proxy, anime_type, idx, brightness);
print!("\rIndex: {} / {} ", idx, scan_len - 1);
io::stdout().flush().unwrap();
std::thread::sleep(delay);
current_index = idx;
}
println!();
println!("Auto-scan complete. Current index: {}", current_index);
}
"c" => {
clear_display(&proxy, anime_type);
println!("Display cleared");
}
"f" => {
fill_display(&proxy, anime_type, brightness);
println!("All buffer bytes filled at brightness {}", brightness);
}
"p1" => {
fill_pane(&proxy, anime_type, 0, brightness);
println!("Pane 1 (indices 0-626) filled");
}
"p2" => {
fill_pane(&proxy, anime_type, 1, brightness);
println!("Pane 2 (indices 627-1253) filled");
}
"p3" => {
fill_pane(&proxy, anime_type, 2, brightness);
println!("Pane 3 (indices 1254-1880) filled");
}
cmd if cmd.starts_with("f ") => {
let parts: Vec<&str> = cmd.split_whitespace().collect();
if parts.len() == 3 {
if let (Ok(start), Ok(end)) =
(parts[1].parse::<usize>(), parts[2].parse::<usize>())
{
fill_range(&proxy, anime_type, start, end, brightness);
println!("Filled indices {} to {}", start, end);
} else {
println!("Usage: f <start> <end>");
}
} else {
println!("Usage: f <start> <end>");
}
}
"show" => {
write_single_led(&proxy, anime_type, current_index, brightness);
println!(">>> Index: {} (step: {})", current_index, step);
}
"row" => {
if anime_type != AnimeType::G835L {
println!("Warning: Row commands use G835L mapping (provisional). You can add to this code to support other types. `examples/anime-led-scan.rs[402:425]`");
}
println!("Row stepping mode. Press Enter for next row, 'q' to quit.");
let total = g835l_total_rows();
for row_num in 0..total {
let (start, end, len) = g835l_row_bounds(row_num);
if end >= scan_len {
println!("Row {} exceeds scan limit, stopping.", row_num);
break;
}
println!("Row {}: indices {}-{} ({} LEDs)", row_num, start, end, len);
fill_range(&proxy, anime_type, start, end, brightness);
input.clear();
print!("(Enter=next, q=quit) > ");
io::stdout().flush().unwrap();
if stdin.lock().read_line(&mut input).is_err() {
break;
}
if input.trim() == "q" {
break;
}
clear_display(&proxy, anime_type);
}
println!("Row stepping done.");
}
cmd if cmd.starts_with("row ") => {
if anime_type != AnimeType::G835L {
println!("Warning: Row commands use G835L mapping (provisional).");
}
let row_str = cmd.trim_start_matches("row ").trim();
if let Ok(row_num) = row_str.parse::<usize>() {
let total = g835l_total_rows();
if row_num < total {
let (start, end, len) = g835l_row_bounds(row_num);
if end < scan_len {
println!("Row {}: indices {}-{} ({} LEDs)", row_num, start, end, len);
fill_range(&proxy, anime_type, start, end, brightness);
} else {
println!("Row {} exceeds scan limit", row_num);
}
} else {
println!("Row {} out of range (max: {})", row_num, total - 1);
}
} else {
println!("Usage: row <number>");
}
}
"allrows" => {
if anime_type != AnimeType::G835L {
println!("Warning: Row commands use G835L mapping (provisional).");
}
println!("Lighting all rows sequentially (200ms each)...");
let total = g835l_total_rows();
let delay = std::time::Duration::from_millis(200);
for row_num in 0..total {
let (start, end, len) = g835l_row_bounds(row_num);
if end >= scan_len {
println!("\nRow {} exceeds scan limit, stopping.", row_num);
break;
}
print!(
"\rRow {}/{}: indices {}-{} ({} LEDs) ",
row_num,
total - 1,
start,
end,
len
);
io::stdout().flush().unwrap();
fill_range(&proxy, anime_type, start, end, brightness);
std::thread::sleep(delay);
clear_display(&proxy, anime_type);
}
println!("\nDone.");
}
"rowmap" => {
if anime_type != AnimeType::G835L {
println!("Warning: Row map is for G835L (provisional).");
}
println!("G835L Row Map:");
let total = g835l_total_rows();
for row_num in 0..total {
let (start, end, len) = g835l_row_bounds(row_num);
let marker = if end >= scan_len {
" (exceeds limit)"
} else {
""
};
println!(
" Row {:2}: indices {:4}-{:4} ({:2} LEDs){}",
row_num, start, end, len, marker
);
}
}
"hold" => {
// Single write, wait for Enter to release
println!("Holding index {}. Press Enter to release...", current_index);
write_single_led(&proxy, anime_type, current_index, brightness);
input.clear();
let _ = stdin.lock().read_line(&mut input);
clear_display(&proxy, anime_type);
println!("Released.");
}
cmd if cmd.starts_with("hold ") => {
let arg = cmd.trim_start_matches("hold ").trim();
let (start, end): (usize, usize) = match arg {
"p1" | "1" => (0, 626),
"p2" | "2" => (627, 1253),
_ => {
let parts: Vec<&str> = arg.split_whitespace().collect();
if parts.len() == 2 {
if let (Ok(s), Ok(e)) = (parts[0].parse(), parts[1].parse()) {
(s, e)
} else {
println!("Usage: hold p1, hold p2, or hold <start> <end>");
continue;
}
} else {
println!("Usage: hold p1, hold p2, or hold <start> <end>");
continue;
}
}
};
println!("Holding range {}-{}. Press Enter to release...", start, end);
fill_range(&proxy, anime_type, start, end, brightness);
input.clear();
let _ = stdin.lock().read_line(&mut input);
clear_display(&proxy, anime_type);
println!("Released.");
}
_ => {
if let Ok(idx) = cmd.parse::<usize>() {
if idx < scan_len {
current_index = idx;
write_single_led(&proxy, anime_type, current_index, brightness);
println!(">>> Index: {} (step: {})", current_index, step);
} else {
println!("Index {} out of range (max: {})", idx, scan_len - 1);
}
} else {
println!("Unknown command: '{}'. Type 'h' for help.", cmd);
}
}
}
}
}

View File

@@ -1,154 +1,151 @@
use gumdrop::Options;
use rog_anime::usb::{AnimAwake, AnimBooting, AnimShutdown, AnimSleeping, Brightness};
use argh::FromArgs;
use rog_anime::usb::{AnimAwake, AnimBooting, AnimShutdown, AnimSleeping};
use rog_anime::AnimeType;
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "anime", description = "anime commands")]
pub struct AnimeCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "override the display type")]
#[argh(option, description = "override the display type")]
pub override_type: Option<AnimeType>,
#[options(meta = "", help = "enable/disable the display")]
#[argh(option, description = "enable/disable the display")]
pub enable_display: Option<bool>,
#[options(meta = "", help = "enable/disable the builtin run/powersave animation")]
pub enable_powersave_anim: Option<bool>,
#[options(
meta = "",
help = "set global base brightness value <Off, Low, Med, High>"
#[argh(
option,
description = "enable/disable the builtin run/powersave animation"
)]
pub brightness: Option<Brightness>,
#[options(help = "clear the display")]
pub enable_powersave_anim: Option<bool>,
#[argh(
option,
description = "set global base brightness value <off, low, med, high>"
)]
pub brightness: Option<rog_anime::usb::Brightness>,
#[argh(switch, description = "clear the display")]
pub clear: bool,
#[options(
no_short,
meta = "",
help = "turn the anime off when external power is unplugged"
#[argh(
option,
description = "turn the anime off when external power is unplugged"
)]
pub off_when_unplugged: Option<bool>,
#[options(
no_short,
meta = "",
help = "turn the anime off when the laptop suspends"
)]
#[argh(option, description = "turn the anime off when the laptop suspends")]
pub off_when_suspended: Option<bool>,
#[options(
no_short,
meta = "",
help = "turn the anime off when the lid is closed"
)]
#[argh(option, description = "turn the anime off when the lid is closed")]
pub off_when_lid_closed: Option<bool>,
#[options(no_short, meta = "", help = "Off with his head!!!")]
#[argh(option, description = "off with his head!!!")]
pub off_with_his_head: Option<bool>,
#[options(command)]
#[argh(subcommand)]
pub command: Option<AnimeActions>,
}
#[derive(Options)]
/// Anime subcommands (image, gif, builtins, etc.)
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum AnimeActions {
#[options(help = "display a PNG image")]
Image(AnimeImage),
#[options(help = "display a diagonal/pixel-perfect PNG")]
PixelImage(AnimeImageDiagonal),
#[options(help = "display an animated GIF")]
Gif(AnimeGif),
#[options(help = "display an animated diagonal/pixel-perfect GIF")]
PixelGif(AnimeGifDiagonal),
#[options(help = "change which builtin animations are shown")]
SetBuiltins(Builtins),
}
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(
subcommand,
name = "set-builtins",
description = "change which builtin animations are shown"
)]
pub struct Builtins {
#[options(help = "print help message")]
pub help: bool,
#[options(
meta = "",
help = "Default is used if unspecified, <default:GlitchConstruction, StaticEmergence>"
#[argh(
option,
description = "default is used if unspecified, <default:GlitchConstruction, StaticEmergence>"
)]
pub boot: AnimBooting,
#[options(
meta = "",
help = "Default is used if unspecified, <default:BinaryBannerScroll, RogLogoGlitch>"
#[argh(
option,
description = "default is used if unspecified, <default:BinaryBannerScroll, RogLogoGlitch>"
)]
pub awake: AnimAwake,
#[options(
meta = "",
help = "Default is used if unspecified, <default:BannerSwipe, Starfield>"
#[argh(
option,
description = "default is used if unspecified, <default:BannerSwipe, Starfield>"
)]
pub sleep: AnimSleeping,
#[options(
meta = "",
help = "Default is used if unspecified, <default:GlitchOut, SeeYa>"
#[argh(
option,
description = "default is used if unspecified, <default:GlitchOut, SeeYa>"
)]
pub shutdown: AnimShutdown,
#[options(meta = "", help = "set/apply the animations <true/false>")]
#[argh(option, description = "set/apply the animations <true/false>")]
pub set: Option<bool>,
}
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "image", description = "display a PNG image")]
pub struct AnimeImage {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
#[argh(option, description = "full path to the png to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "scale 1.0 == normal")]
#[argh(option, default = "1.0", description = "scale 1.0 == normal")]
pub scale: f32,
#[options(meta = "", default = "0.0", help = "x position (float)")]
#[argh(option, default = "0.0", description = "x position (float)")]
pub x_pos: f32,
#[options(meta = "", default = "0.0", help = "y position (float)")]
#[argh(option, default = "0.0", description = "y position (float)")]
pub y_pos: f32,
#[options(meta = "", default = "0.0", help = "the angle in radians")]
#[argh(option, default = "0.0", description = "the angle in radians")]
pub angle: f32,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
#[argh(option, default = "1.0", description = "brightness 0.0-1.0")]
pub bright: f32,
}
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(
subcommand,
name = "pixel-image",
description = "display a diagonal/pixel-perfect PNG"
)]
pub struct AnimeImageDiagonal {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
#[argh(option, description = "full path to the png to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
#[argh(option, default = "1.0", description = "brightness 0.0-1.0")]
pub bright: f32,
}
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "gif", description = "display an animated GIF")]
pub struct AnimeGif {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
#[argh(option, description = "full path to the gif to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "scale 1.0 == normal")]
#[argh(option, default = "1.0", description = "scale 1.0 == normal")]
pub scale: f32,
#[options(meta = "", default = "0.0", help = "x position (float)")]
#[argh(option, default = "0.0", description = "x position (float)")]
pub x_pos: f32,
#[options(meta = "", default = "0.0", help = "y position (float)")]
#[argh(option, default = "0.0", description = "y position (float)")]
pub y_pos: f32,
#[options(meta = "", default = "0.0", help = "the angle in radians")]
#[argh(option, default = "0.0", description = "the angle in radians")]
pub angle: f32,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
#[argh(option, default = "1.0", description = "brightness 0.0-1.0")]
pub bright: f32,
#[options(
meta = "",
default = "1",
help = "how many loops to play - 0 is infinite"
#[argh(
option,
default = "0",
description = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
}
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(
subcommand,
name = "pixel-gif",
description = "display an animated diagonal/pixel-perfect GIF"
)]
pub struct AnimeGifDiagonal {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
#[argh(option, description = "full path to the gif to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
#[argh(option, default = "1.0", description = "brightness 0.0-1.0")]
pub bright: f32,
#[options(
meta = "",
default = "1",
help = "how many loops to play - 0 is infinite"
#[argh(
option,
default = "0",
description = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
}

View File

@@ -1,68 +1,67 @@
use std::fmt;
use std::str::FromStr;
use gumdrop::Options;
use argh::FromArgs;
use rog_aura::error::Error;
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
#[derive(Options, Debug)]
#[derive(FromArgs, Debug, Clone)]
#[argh(
subcommand,
name = "power-tuf",
description = "aura power (old ROGs and TUF laptops)"
)]
pub struct LedPowerCommand1 {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "Control if LEDs enabled while awake <true/false>")]
#[argh(
option,
description = "control if LEDs enabled while awake <true/false>"
)]
pub awake: Option<bool>,
#[options(help = "Use with awake option, if excluded defaults to false")]
#[argh(
switch,
description = "use with awake option; if excluded defaults to false"
)]
pub keyboard: bool,
#[options(help = "Use with awake option, if excluded defaults to false")]
#[argh(
switch,
description = "use with awake option; if excluded defaults to false"
)]
pub lightbar: bool,
#[options(meta = "", help = "Control boot animations <true/false>")]
#[argh(option, description = "control boot animations <true/false>")]
pub boot: Option<bool>,
#[options(meta = "", help = "Control suspend animations <true/false>")]
#[argh(option, description = "control suspend animations <true/false>")]
pub sleep: Option<bool>,
}
#[derive(Options, Debug)]
#[derive(FromArgs, Debug, Clone)]
#[argh(subcommand, name = "power", description = "aura power")]
pub struct LedPowerCommand2 {
#[options(help = "print help message")]
pub help: bool,
#[options(command)]
#[argh(subcommand)]
pub command: Option<SetAuraZoneEnabled>,
}
#[derive(Options, Debug)]
/// Subcommands to enable/disable specific aura zones
#[derive(FromArgs, Debug, Clone)]
#[argh(subcommand)]
pub enum SetAuraZoneEnabled {
/// Applies to both old and new models
#[options(help = "")]
Keyboard(AuraPowerStates),
#[options(help = "")]
Logo(AuraPowerStates),
#[options(help = "")]
Lightbar(AuraPowerStates),
#[options(help = "")]
Lid(AuraPowerStates),
#[options(help = "")]
RearGlow(AuraPowerStates),
#[options(help = "")]
Ally(AuraPowerStates),
Keyboard(KeyboardPower),
Logo(LogoPower),
Lightbar(LightbarPower),
Lid(LidPower),
RearGlow(RearGlowPower),
Ally(AllyPower),
}
#[derive(Debug, Clone, Options)]
pub struct AuraPowerStates {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "defaults to false if option unused")]
pub boot: bool,
#[options(help = "defaults to false if option unused")]
pub awake: bool,
#[options(help = "defaults to false if option unused")]
pub sleep: bool,
#[options(help = "defaults to false if option unused")]
pub shutdown: bool,
}
#[derive(Options)]
/// Keyboard brightness argument helper
#[derive(Debug, Clone)]
pub struct LedBrightness {
level: Option<u8>,
}
impl LedBrightness {
pub fn new(level: Option<u8>) -> Self {
LedBrightness { level }
@@ -72,174 +71,429 @@ impl LedBrightness {
self.level
}
}
impl FromStr for LedBrightness {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"off" => Ok(LedBrightness { level: Some(0x00) }),
"low" => Ok(LedBrightness { level: Some(0x01) }),
"med" => Ok(LedBrightness { level: Some(0x02) }),
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
print!("Invalid argument, must be one of: off, low, med, high");
Err(Error::ParseBrightness)
}
"off" => Ok(Self::new(Some(0x00))),
"low" => Ok(Self::new(Some(0x01))),
"med" => Ok(Self::new(Some(0x02))),
"high" => Ok(Self::new(Some(0x03))),
_ => Err(Error::ParseBrightness),
}
}
}
#[allow(clippy::to_string_trait_impl)]
impl ToString for LedBrightness {
fn to_string(&self) -> String {
impl fmt::Display for LedBrightness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self.level {
Some(0x00) => "low",
Some(0x01) => "med",
Some(0x02) => "high",
Some(0x00) => "off",
Some(0x01) => "low",
Some(0x02) => "med",
Some(0x03) => "high",
_ => "unknown",
};
s.to_owned()
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, Options, Default)]
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "keyboard",
description = "set power states for keyboard zone"
)]
pub struct KeyboardPower {
#[argh(switch, description = "defaults to false if option unused")]
pub boot: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub awake: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub sleep: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub shutdown: bool,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "logo",
description = "set power states for logo zone"
)]
pub struct LogoPower {
#[argh(switch, description = "defaults to false if option unused")]
pub boot: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub awake: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub sleep: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub shutdown: bool,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "lightbar",
description = "set power states for lightbar zone"
)]
pub struct LightbarPower {
#[argh(switch, description = "enable power while device is booting")]
pub boot: bool,
#[argh(switch, description = "enable power while device is awake")]
pub awake: bool,
#[argh(switch, description = "enable power while device is sleeping")]
pub sleep: bool,
#[argh(
switch,
description = "enable power while device is shutting down or hibernating"
)]
pub shutdown: bool,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "lid",
description = "set power states for lid zone"
)]
pub struct LidPower {
#[argh(switch, description = "defaults to false if option unused")]
pub boot: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub awake: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub sleep: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub shutdown: bool,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "rear-glow",
description = "set power states for rear glow zone"
)]
pub struct RearGlowPower {
#[argh(switch, description = "defaults to false if option unused")]
pub boot: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub awake: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub sleep: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub shutdown: bool,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "ally",
description = "set power states for ally zone"
)]
pub struct AllyPower {
#[argh(switch, description = "defaults to false if option unused")]
pub boot: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub awake: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub sleep: bool,
#[argh(switch, description = "defaults to false if option unused")]
pub shutdown: bool,
}
/// Single speed-based effect
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "rainbow-cycle",
description = "single speed-based effect"
)]
pub struct SingleSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[options(
no_long,
meta = "",
help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left"
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Options, Default)]
/// Single speed effect with direction
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "rainbow-wave",
description = "single speed effect with direction"
)]
pub struct SingleSpeedDirection {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the direction: up, down, left, right")]
#[argh(option, description = "set the direction: up, down, left, right")]
pub direction: Direction,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[options(
no_long,
meta = "",
help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left"
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Default, Options)]
/// Static single-colour effect
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "static",
description = "static single-colour effect"
)]
pub struct SingleColour {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[options(
no_long,
meta = "",
help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left"
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Default, Options)]
/// Single-colour effect with speed
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "highlight",
description = "single-colour effect with speed"
)]
pub struct SingleColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[options(
no_long,
meta = "",
help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left"
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Options, Default)]
/// Two-colour breathing effect
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "breathe",
description = "two-colour breathing effect"
)]
pub struct TwoColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the first RGB value e.g, ff00ff")]
#[argh(option, description = "set the first RGB value e.g. ff00ff")]
pub colour: Colour,
#[options(no_long, meta = "", help = "set the second RGB value e.g, ff00ff")]
#[argh(option, description = "set the second RGB value e.g. ff00ff")]
pub colour2: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[options(
no_long,
meta = "",
help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left"
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Default, Options)]
pub struct MultiZone {
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour1: Colour,
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
/// Two-colour star effect (separate subcommand name)
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "stars", description = "two-colour star effect")]
pub struct StarsTwoColour {
#[argh(option, description = "set the first RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(option, description = "set the second RGB value e.g. ff00ff")]
pub colour2: Colour,
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Rain effect (single-speed, separate subcommand name)
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "rain",
description = "single speed-based rain effect"
)]
pub struct RainSingleSpeed {
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Laser (single-colour with speed) separate subcommand
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "laser",
description = "single-colour effect with speed"
)]
pub struct LaserSingleColourSpeed {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Ripple (single-colour with speed) separate subcommand
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "ripple",
description = "single-colour effect with speed"
)]
pub struct RippleSingleColourSpeed {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Pulse / Comet / Flash variants (single-colour) separate subcommands
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "pulse", description = "single-colour pulse effect")]
pub struct PulseSingleColour {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "comet", description = "single-colour comet effect")]
pub struct CometSingleColour {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "flash", description = "single-colour flash effect")]
pub struct FlashSingleColour {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Multi-zone colour settings
#[derive(FromArgs, Debug, Clone, Default)]
#[allow(dead_code)]
#[argh(description = "multi-zone colour settings")]
pub struct MultiZone {
#[argh(option, short = 'a', description = "set the RGB value e.g. ff00ff")]
pub colour1: Colour,
#[argh(option, short = 'b', description = "set the RGB value e.g. ff00ff")]
pub colour2: Colour,
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour3: Colour,
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'd', description = "set the RGB value e.g. ff00ff")]
pub colour4: Colour,
}
#[derive(Debug, Clone, Default, Options)]
/// Multi-colour with speed
#[derive(FromArgs, Debug, Clone, Default)]
#[allow(dead_code)]
#[argh(description = "multi-colour with speed")]
pub struct MultiColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'a', description = "set the RGB value e.g. ff00ff")]
pub colour1: Colour,
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'b', description = "set the RGB value e.g. ff00ff")]
pub colour2: Colour,
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour3: Colour,
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
#[argh(option, short = 'd', description = "set the RGB value e.g. ff00ff")]
pub colour4: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
}
/// 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)]
/// Builtin aura effects
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum SetAuraBuiltin {
#[options(help = "set a single static colour")]
Static(SingleColour), // 0
#[options(help = "pulse between one or two colours")]
Breathe(TwoColourSpeed), // 1
#[options(help = "strobe through all colours")]
RainbowCycle(SingleSpeed), // 2
#[options(help = "rainbow cycling in one of four directions")]
Static(SingleColour), // 0
Breathe(TwoColourSpeed), // 1
RainbowCycle(SingleSpeed), // 2
RainbowWave(SingleSpeedDirection), // 3
#[options(help = "rain pattern mimicking raindrops")]
Stars(TwoColourSpeed), // 4
#[options(help = "rain pattern of three preset colours")]
Rain(SingleSpeed), // 5
#[options(help = "pressed keys are highlighted to fade")]
Highlight(SingleColourSpeed), // 6
#[options(help = "pressed keys generate horizontal laser")]
Laser(SingleColourSpeed), // 7
#[options(help = "pressed keys ripple outwards like a splash")]
Ripple(SingleColourSpeed), // 8
#[options(help = "set a rapid pulse")]
Pulse(SingleColour), // 10
#[options(help = "set a vertical line zooming from left")]
Comet(SingleColour), // 11
#[options(help = "set a wide vertical line zooming from left")]
Flash(SingleColour), // 12
Stars(StarsTwoColour), // 4
Rain(RainSingleSpeed), // 5
Highlight(SingleColourSpeed), // 6
Laser(LaserSingleColourSpeed), // 7
Ripple(RippleSingleColourSpeed), // 8
Pulse(PulseSingleColour), // 10
Comet(CometSingleColour), // 11
Flash(FlashSingleColour), // 12
}
impl Default for SetAuraBuiltin {
@@ -301,6 +555,79 @@ impl From<&SingleSpeedDirection> for AuraEffect {
}
}
impl From<&StarsTwoColour> for AuraEffect {
fn from(aura: &StarsTwoColour) -> Self {
Self {
colour1: aura.colour,
colour2: aura.colour2,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&RainSingleSpeed> for AuraEffect {
fn from(aura: &RainSingleSpeed) -> Self {
Self {
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&LaserSingleColourSpeed> for AuraEffect {
fn from(aura: &LaserSingleColourSpeed) -> Self {
Self {
colour1: aura.colour,
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&RippleSingleColourSpeed> for AuraEffect {
fn from(aura: &RippleSingleColourSpeed) -> Self {
Self {
colour1: aura.colour,
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&PulseSingleColour> for AuraEffect {
fn from(aura: &PulseSingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&CometSingleColour> for AuraEffect {
fn from(aura: &CometSingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&FlashSingleColour> for AuraEffect {
fn from(aura: &FlashSingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&SetAuraBuiltin> for AuraEffect {
fn from(aura: &SetAuraBuiltin) -> Self {
match aura {

View File

@@ -1,5 +1,5 @@
use gumdrop::Options;
use rog_platform::platform::ThrottlePolicy;
use argh::FromArgs;
use rog_platform::platform::PlatformProfile;
use crate::anime_cli::AnimeCommand;
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
@@ -7,117 +7,321 @@ use crate::fan_curve_cli::FanCurveCommand;
use crate::scsi_cli::ScsiCommand;
use crate::slash_cli::SlashCommand;
#[derive(Default, Options)]
#[derive(FromArgs, Default, Debug)]
/// asusctl command-line options
pub struct CliStart {
#[options(help_flag, help = "print help message")]
pub help: bool,
#[options(help = "show program version number")]
pub version: bool,
#[options(help = "show supported functions of this laptop")]
pub show_supported: bool,
#[options(meta = "", help = "<off, low, med, high>")]
pub kbd_bright: Option<LedBrightness>,
#[options(help = "Toggle to next keyboard brightness")]
pub next_kbd_bright: bool,
#[options(help = "Toggle to previous keyboard brightness")]
pub prev_kbd_bright: bool,
#[options(meta = "", help = "Set your battery charge limit <20-100>")]
pub chg_limit: Option<u8>,
#[options(help = "Toggle one-shot battery charge to 100%")]
pub one_shot_chg: bool,
#[options(command)]
pub command: Option<CliCommand>,
#[argh(subcommand)]
pub command: CliCommand,
}
#[derive(Options)]
/// Top-level subcommands for asusctl
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")]
Aura(LedModeCommand),
#[options(help = "Set the LED power states")]
AuraPowerOld(LedPowerCommand1),
#[options(help = "Set the LED power states")]
AuraPower(LedPowerCommand2),
#[options(help = "Set or select platform_profile")]
Aura(AuraCommand),
Brightness(BrightnessCommand),
Profile(ProfileCommand),
#[options(help = "Set, select, or modify fan curves if supported")]
FanCurve(FanCurveCommand),
#[options(help = "Set the graphics mode (obsoleted by supergfxctl)")]
Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")]
Anime(AnimeCommand),
#[options(name = "slash", help = "Manage Slash Ledbar")]
Slash(SlashCommand),
#[options(name = "scsi", help = "Manage SCSI external drive")]
Scsi(ScsiCommand),
#[options(help = "Change bios settings")]
Platform(PlatformCommand),
Armoury(ArmouryCommand),
Backlight(BacklightCommand),
Battery(BatteryCommand),
Info(InfoCommand),
}
#[derive(Debug, Clone, Options)]
impl Default for CliCommand {
fn default() -> Self {
CliCommand::Info(InfoCommand::default())
}
}
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "profile", description = "profile management")]
pub struct ProfileCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "toggle to next profile in list")]
pub next: bool,
#[options(help = "list available profiles")]
pub list: bool,
#[options(help = "get profile")]
pub profile_get: bool,
#[options(meta = "", help = "set the active profile")]
pub profile_set: Option<ThrottlePolicy>,
#[argh(subcommand)]
pub command: ProfileSubCommand,
}
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum ProfileSubCommand {
Next(ProfileNextCommand),
List(ProfileListCommand),
Get(ProfileGetCommand),
Set(ProfileSetCommand),
}
impl Default for ProfileSubCommand {
fn default() -> Self {
ProfileSubCommand::List(ProfileListCommand::default())
}
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "next",
description = "toggle to next profile in list"
)]
pub struct ProfileNextCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "list", description = "list available profiles")]
pub struct ProfileListCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "get", description = "get profile")]
pub struct ProfileGetCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "set", description = "set profile")]
pub struct ProfileSetCommand {
#[argh(positional, description = "profile to set")]
pub profile: PlatformProfile,
#[argh(
switch,
short = 'a',
description = "set the profile to use on AC power"
)]
pub ac: bool,
#[argh(
switch,
short = 'b',
description = "set the profile to use on battery power"
)]
pub battery: bool,
}
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "effect", description = "led mode commands")]
pub struct LedModeCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "switch to next aura mode")]
#[argh(switch, description = "switch to next aura mode")]
pub next_mode: bool,
#[options(help = "switch to previous aura mode")]
#[argh(switch, description = "switch to previous aura mode")]
pub prev_mode: bool,
#[options(command)]
#[argh(subcommand)]
pub command: Option<SetAuraBuiltin>,
}
#[derive(Options)]
pub struct GraphicsCommand {
#[options(help = "print help message")]
pub help: bool,
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "aura", description = "aura device commands")]
pub struct AuraCommand {
#[argh(subcommand)]
pub command: AuraSubCommand,
}
#[derive(Options, Debug)]
pub struct PlatformCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(
meta = "",
short = "S",
no_long,
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")]
pub post_sound_get: bool,
#[options(
meta = "",
short = "D",
no_long,
help = "Switch GPU MUX mode: 0 = Discrete, 1 = Optimus, reboot required"
)]
pub gpu_mux_mode_set: Option<u8>,
#[options(no_long, short = "d", help = "get GPU mode")]
pub gpu_mux_mode_get: bool,
#[options(
meta = "",
short = "O",
no_long,
help = "Set device panel overdrive <true/false>"
)]
pub panel_overdrive_set: Option<bool>,
#[options(no_long, short = "o", help = "get panel overdrive")]
pub panel_overdrive_get: bool,
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum AuraSubCommand {
Power(LedPowerCommand2),
PowerTuf(LedPowerCommand1),
Effect(LedModeCommand),
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "armoury",
description = "armoury / firmware attributes"
)]
pub struct ArmouryCommand {
#[argh(subcommand)]
pub command: ArmourySubCommand,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum ArmourySubCommand {
Set(ArmouryPropertySetCommand),
Get(ArmouryPropertyGetCommand),
List(ArmouryPropertyListCommand),
}
impl Default for ArmourySubCommand {
fn default() -> Self {
ArmourySubCommand::List(ArmouryPropertyListCommand::default())
}
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "set",
description = "set an asus-armoury firmware-attribute"
)]
pub struct ArmouryPropertySetCommand {
#[argh(
positional,
description = "name of the attribute to set (see asus-armoury list for available properties)"
)]
pub property: String,
#[argh(positional, description = "value to set for the given attribute")]
pub value: i32,
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "list",
description = "list all firmware-attributes supported by asus-armoury"
)]
pub struct ArmouryPropertyListCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "get",
description = "get a firmware-attribute from asus-armoury"
)]
pub struct ArmouryPropertyGetCommand {
#[argh(
positional,
description = "name of the property to get (see asus-armoury list for available properties)"
)]
pub property: String,
}
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "backlight", description = "backlight options")]
pub struct BacklightCommand {
#[argh(option, description = "set screen brightness <0-100>")]
pub screenpad_brightness: Option<i32>,
#[argh(
option,
description = "set screenpad gamma brightness 0.5 - 2.2, 1.0 == linear"
)]
pub screenpad_gamma: Option<f32>,
#[argh(
option,
description = "set screenpad brightness to sync with primary display"
)]
pub sync_screenpad_brightness: Option<bool>,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "battery", description = "battery options")]
pub struct BatteryCommand {
#[argh(subcommand)]
pub command: BatterySubCommand,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum BatterySubCommand {
Limit(BatteryLimitCommand),
OneShot(BatteryOneShotCommand),
Info(BatteryInfoCommand),
}
impl Default for BatterySubCommand {
fn default() -> Self {
BatterySubCommand::OneShot(BatteryOneShotCommand::default())
}
}
#[derive(FromArgs, Debug)]
#[argh(
subcommand,
name = "limit",
description = "set battery charge limit <20-100>"
)]
pub struct BatteryLimitCommand {
#[argh(positional, description = "charge limit percentage 20-100")]
pub limit: u8,
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "oneshot",
description = "one-shot full charge (optional percent)"
)]
pub struct BatteryOneShotCommand {
#[argh(positional, description = "optional target percent (defaults to 100)")]
pub percent: Option<u8>,
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "info",
description = "show current battery charge limit"
)]
pub struct BatteryInfoCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "info",
description = "show program version and system info"
)]
pub struct InfoCommand {
#[argh(switch, description = "show supported functions of this laptop")]
pub show_supported: bool,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "leds", description = "keyboard brightness control")]
pub struct BrightnessCommand {
#[argh(subcommand)]
pub command: BrightnessSubCommand,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum BrightnessSubCommand {
Set(BrightnessSetCommand),
Get(BrightnessGetCommand),
Next(BrightnessNextCommand),
Prev(BrightnessPrevCommand),
}
impl Default for BrightnessSubCommand {
fn default() -> Self {
BrightnessSubCommand::Get(BrightnessGetCommand::default())
}
}
#[derive(FromArgs, Debug)]
#[argh(
subcommand,
name = "set",
description = "set keyboard brightness <off, low, med, high>"
)]
pub struct BrightnessSetCommand {
#[argh(positional, description = "brightness level: off, low, med, high")]
pub level: LedBrightness,
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "get",
description = "get current keyboard brightness"
)]
pub struct BrightnessGetCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "next",
description = "toggle to next keyboard brightness"
)]
pub struct BrightnessNextCommand {}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,
name = "prev",
description = "toggle to previous keyboard brightness"
)]
pub struct BrightnessPrevCommand {}

View File

@@ -1,49 +1,44 @@
use gumdrop::Options;
use rog_platform::platform::ThrottlePolicy;
use argh::FromArgs;
use rog_platform::platform::PlatformProfile;
use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::FanCurvePU;
#[derive(Debug, Clone, Options)]
#[derive(FromArgs, Debug, Clone)]
#[argh(subcommand, name = "fan-curve", description = "fan curve commands")]
pub struct FanCurveCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "get enabled fan profiles")]
#[argh(switch, description = "get enabled fan profiles")]
pub get_enabled: bool,
#[options(help = "set the active profile's fan curve to default")]
#[argh(switch, description = "set the active profile's fan curve to default")]
pub default: bool,
#[options(
meta = "",
help = "profile to modify fan-curve for. Shows data if no options provided"
#[argh(
option,
description = "profile to modify fan-curve for. shows data if no options provided"
)]
pub mod_profile: Option<ThrottlePolicy>,
pub mod_profile: Option<PlatformProfile>,
#[options(
meta = "",
help = "enable or disable <true/false> fan all curves for a profile. `--mod_profile` \
required"
#[argh(
option,
description = "enable or disable <true/false> fan all curves for a profile; --mod_profile required"
)]
pub enable_fan_curves: Option<bool>,
#[options(
meta = "",
help = "enable or disable <true/false> a single fan curve for a profile. `--mod_profile` \
and `--fan` required"
#[argh(
option,
description = "enable or disable <true/false> a single fan curve for a profile; --mod_profile and --fan required"
)]
pub enable_fan_curve: Option<bool>,
#[options(
meta = "",
help = "select fan <cpu/gpu/mid> to modify. `--mod_profile` required"
#[argh(
option,
description = "select fan <cpu/gpu/mid> to modify; --mod_profile required"
)]
pub fan: Option<FanCurvePU>,
#[options(
meta = "",
help = "data format = 30c:1%,49c:2%,59c:3%,69c:4%,79c:31%,89c:49%,99c:56%,109c:58%. \
`--mod-profile` required. If '%' is omitted the fan range is 0-255"
#[argh(
option,
description = "data format = 30c:1%,49c:2%,...; --mod-profile required. If '%' is omitted the fan range is 0-255"
)]
pub data: Option<CurveData>,
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +1,30 @@
use gumdrop::Options;
use argh::FromArgs;
use rog_scsi::{AuraMode, Colour, Direction, Speed};
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "scsi", description = "scsi LED commands")]
pub struct ScsiCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "Enable the SCSI drive LEDs")]
#[argh(option, description = "enable the SCSI drive LEDs")]
pub enable: Option<bool>,
#[options(meta = "", help = "Set LED mode (so 'list' for all options)")]
#[argh(option, description = "set LED mode (use 'list' for all options)")]
pub mode: Option<AuraMode>,
#[options(
meta = "",
help = "Set LED mode speed <slowest, slow, med, fast, fastest> (does not apply to all)"
#[argh(
option,
description = "set LED mode speed <slowest, slow, med, fast, fastest>"
)]
pub speed: Option<Speed>,
#[options(
meta = "",
help = "Set LED mode direction <forward, reverse> (does not apply to all)"
)]
#[argh(option, description = "set LED mode direction <forward, reverse>")]
pub direction: Option<Direction>,
#[options(
meta = "",
help = "Set LED colours <hex>, specify up to 4 with repeated arg"
#[argh(
option,
description = "set LED colours <hex>, specify up to 4 with repeated arg"
)]
pub colours: Vec<Colour>,
#[options(help = "list available animations")]
#[argh(switch, description = "list available animations")]
pub list: bool,
}

View File

@@ -1,20 +1,34 @@
use gumdrop::Options;
use argh::FromArgs;
use rog_slash::SlashMode;
#[derive(Options)]
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "slash", description = "slash ledbar commands")]
pub struct SlashCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "Enable the Slash Ledbar")]
#[argh(switch, description = "enable the Slash Ledbar")]
pub enable: bool,
#[options(help = "Ddisable the Slash Ledbar")]
#[argh(switch, description = "disable the Slash Ledbar")]
pub disable: bool,
#[options(meta = "", help = "Set brightness value <0-255>")]
#[argh(option, short = 'l', description = "set brightness value <0-255>")]
pub brightness: Option<u8>,
#[options(meta = "", help = "Set interval value <0-5>")]
#[argh(option, description = "set interval value <0-5>")]
pub interval: Option<u8>,
#[options(meta = "", help = "Set SlashMode (so 'list' for all options)")]
pub slash_mode: Option<SlashMode>,
#[options(help = "list available animations")]
#[argh(option, description = "set SlashMode (use 'list' for options)")]
pub mode: Option<SlashMode>,
#[argh(switch, description = "list available animations")]
pub list: bool,
#[argh(option, short = 'B', description = "show the animation on boot")]
pub show_on_boot: Option<bool>,
#[argh(option, short = 'S', description = "show the animation on shutdown")]
pub show_on_shutdown: Option<bool>,
#[argh(option, short = 's', description = "show the animation on sleep")]
pub show_on_sleep: Option<bool>,
#[argh(option, short = 'b', description = "show the animation on battery")]
pub show_on_battery: Option<bool>,
#[argh(
option,
short = 'w',
description = "show the low-battery warning animation"
)]
pub show_battery_warning: Option<bool>,
}

View File

@@ -32,3 +32,16 @@ config-traits = { path = "../config-traits" }
zbus.workspace = true
env_logger.workspace = true
[package.metadata.deb]
license-file = ["../LICENSE", "4"]
extended-description = """\
An user utility for Linux to control fancy things on various ASUS laptops
like keyboard effects or anime matrix animation cycles."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
["target/release/asusd-user", "usr/bin/", "755"],
["../asusd_user-fakeinstall/usr/lib/systemd/user/*", "usr/lib/systemd/user/", "644"],
]

View File

@@ -151,10 +151,7 @@ impl CtrlAnime<'static> {
pub async fn add_to_server(self, server: &mut zbus::Connection) {
server
.object_server()
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.at(&ObjectPath::from_str_unchecked("/xyz/ljones/Anime"), self)
.await
.map_err(|err| {
println!("CtrlAnime: add_to_server {}", err);
@@ -170,7 +167,7 @@ impl CtrlAnime<'static> {
// - Do actions
// - Write config if required
// - Unset inner_early_return
#[interface(name = "org.asuslinux.Daemon")]
#[interface(name = "xyz.ljones.Asusd")]
impl CtrlAnime<'static> {
pub fn insert_asus_gif(
&mut self,

View File

@@ -42,7 +42,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let early_return = Arc::new(AtomicBool::new(false));
// Set up the anime data and run loop/thread
if supported.contains(&"org.asuslinux.Anime".to_string()) {
if supported.contains(&"xyz.ljones.Anime".to_string()) {
if let Some(cfg) = config.active_anime {
let anime_type = get_anime_type();
let anime_config = ConfigAnime::new().set_name(cfg).load();

View File

@@ -1,8 +1,8 @@
//! # `DBus` interface proxy for: `org.asuslinux.Daemon`
//! # `DBus` interface proxy for: `xyz.ljones.Asusd`
//!
//! 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`.
//! data. Source: `Interface '/xyz/ljones/Anime' from service
//! 'xyz.ljones.Asusd' on session bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
@@ -23,10 +23,7 @@
use zbus::proxy;
#[proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Anime"
)]
#[proxy(interface = "xyz.ljones.Asusd", default_path = "/xyz/ljones/Anime")]
trait Daemon {
/// InsertAsusGif method
fn insert_asus_gif(

View File

@@ -34,6 +34,7 @@ tokio.workspace = true
log.workspace = true
env_logger.workspace = true
futures-util.workspace = true
zbus.workspace = true
logind-zbus.workspace = true
@@ -44,3 +45,18 @@ concat-idents.workspace = true
[dev-dependencies]
cargo-husky.workspace = true
[package.metadata.deb]
license-file = ["../LICENSE", "4"]
extended-description = """\
The dbus server for asusctl and rog-control-center applications."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
["target/release/asusd", "usr/bin/", "755"],
["../asusd-fakeinstall/usr/lib/systemd/system/*", "usr/lib/systemd/system/", "644"],
["../asusd-fakeinstall/usr/lib/udev/rules.d/*", "usr/lib/udev/rules.d/", "644"],
["../asusd-fakeinstall/usr/share/asusd/*", "usr/share/share/asusd/", "644"],
["../asusd-fakeinstall/usr/share/dbus-1/system.d/*", "usr/share/dbus-1/system.d/", "644"],
]

551
asusd/src/asus_armoury.rs Normal file
View File

@@ -0,0 +1,551 @@
use std::sync::Arc;
use config_traits::StdConfig;
use log::{debug, error, info, warn};
use rog_platform::asus_armoury::{
AttrValue, Attribute, FirmwareAttribute, FirmwareAttributeType, FirmwareAttributes,
};
use rog_platform::platform::{PlatformProfile, RogPlatform};
use rog_platform::power::AsusPower;
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
use zbus::object_server::SignalEmitter;
use zbus::zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Type, Value};
use zbus::{fdo, interface, Connection};
use crate::config::Config;
use crate::error::RogError;
use crate::{Reloadable, ASUS_ZBUS_PATH};
const MOD_NAME: &str = "asus_armoury";
#[derive(Debug, Default, Clone, Deserialize, Serialize, Type, Value, OwnedValue)]
pub struct PossibleValues {
strings: Vec<String>,
nums: Vec<i32>,
}
fn dbus_path_for_attr(attr_name: &str) -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{attr_name}")).into()
}
#[derive(Clone)]
pub struct AsusArmouryAttribute {
attr: Attribute,
config: Arc<Mutex<Config>>,
/// platform control required here for access to PPD or Throttle profile
platform: RogPlatform,
power: AsusPower,
}
impl AsusArmouryAttribute {
pub fn new(
attr: Attribute,
platform: RogPlatform,
power: AsusPower,
config: Arc<Mutex<Config>>,
) -> Self {
Self {
attr,
config,
platform,
power,
}
}
pub fn attribute_name(&self) -> String {
String::from(self.attr.name())
}
fn resolve_i32_value(refreshed: Option<i32>, cached: &AttrValue) -> i32 {
refreshed
.or(match cached {
AttrValue::Integer(i) => Some(*i),
_ => None,
})
.unwrap_or(-1)
}
pub async fn emit_limits(&self, connection: &Connection) -> Result<(), RogError> {
let path = dbus_path_for_attr(self.attr.name());
let signal = SignalEmitter::new(connection, path)?;
self.min_value_changed(&signal).await?;
self.max_value_changed(&signal).await?;
self.scalar_increment_changed(&signal).await?;
self.current_value_changed(&signal).await?;
Ok(())
}
pub async fn move_to_zbus(self, connection: &Connection) -> Result<(), RogError> {
let path = dbus_path_for_attr(self.attr.name());
connection
.object_server()
.at(path.clone(), self)
.await
.map_err(|e| error!("Couldn't add server at path: {path}, {e:?}"))
.ok();
Ok(())
}
async fn watch_and_notify(
&mut self,
signal_ctxt: SignalEmitter<'static>,
) -> Result<(), RogError> {
use futures_util::StreamExt;
let name = self.name();
macro_rules! watch_value_notify {
($attr_str:expr, $fn_prop_changed:ident) => {
match self.attr.get_watcher($attr_str) {
Ok(watch) => {
let name = <&str>::from(name);
let ctrl = self.clone();
let sig = signal_ctxt.clone();
tokio::spawn(async move {
let mut buffer = [0; 32];
if let Ok(stream) = watch.into_event_stream(&mut buffer) {
stream
.for_each(|_| async {
debug!("{} changed", name);
ctrl.$fn_prop_changed(&sig).await.ok();
})
.await;
} else {
info!(
"inotify event stream failed for {} ({}). You can ignore this \
if unsupported",
name, $attr_str
);
}
});
}
Err(e) => info!(
"inotify watch failed: {}. You can ignore this if your device does not \
support the feature",
e
),
}
};
}
// "current_value", "default_value", "min_value", "max_value"
watch_value_notify!("current_value", current_value_changed);
watch_value_notify!("default_value", default_value_changed);
watch_value_notify!("min_value", min_value_changed);
watch_value_notify!("max_value", max_value_changed);
Ok(())
}
}
#[derive(Clone, Default)]
pub struct ArmouryAttributeRegistry {
attrs: Vec<AsusArmouryAttribute>,
}
impl ArmouryAttributeRegistry {
pub fn push(&mut self, attr: AsusArmouryAttribute) {
self.attrs.push(attr);
}
pub async fn emit_limits(&self, connection: &Connection) -> Result<(), RogError> {
let mut last_err: Option<RogError> = None;
for attr in &self.attrs {
if let Err(e) = attr.emit_limits(connection).await {
error!(
"Failed to emit updated limits for attribute '{}': {e:?}",
attr.attribute_name()
);
last_err = Some(e);
}
}
if let Some(err) = last_err {
Err(err)
} else {
Ok(())
}
}
}
impl crate::Reloadable for AsusArmouryAttribute {
async fn reload(&mut self) -> Result<(), RogError> {
info!("Reloading {}", self.attr.name());
let attribute: FirmwareAttribute = self.attr.name().into();
let name = self.attr.name();
let config = self.config.lock().await;
let apply_value = match attribute.property_type() {
FirmwareAttributeType::Ppt => {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default()
== 1;
let apply_value = {
config.select_tunings_ref(power_plugged, profile).and_then(
|tuning| match tuning.enabled {
true => tuning.group.get(&self.name()).copied(),
false => None,
},
)
};
apply_value.map_or(AttrValue::None, AttrValue::Integer)
}
FirmwareAttributeType::Gpu => {
info!("Reload called on GPU attribute {name}: doing nothing");
AttrValue::None
}
_ => {
info!("Reload called on firmware attribute {name}");
match config.armoury_settings.get(&attribute) {
Some(saved_value) => AttrValue::Integer(*saved_value),
None => AttrValue::None,
}
}
};
match apply_value {
AttrValue::None => {
info!(
"No saved value for attribute {}: skipping.",
self.attr.name()
);
}
_ => {
info!("Applying value {apply_value:?} to attribute {name}");
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set {name} value: {e:?}");
self.attr.base_path_exists();
e
})?;
info!("Restored asus-armoury setting {name} to {apply_value:?}");
}
}
Ok(())
}
}
/// If return is `-1` on a property then there is available value for that
/// property
#[interface(name = "xyz.ljones.AsusArmoury")]
impl AsusArmouryAttribute {
#[zbus(property)]
fn name(&self) -> FirmwareAttribute {
self.attr.name().into()
}
#[zbus(property)]
async fn available_attrs(&self) -> Vec<String> {
let mut attrs = Vec::new();
if !matches!(self.attr.default_value(), AttrValue::None) {
attrs.push("default_value".to_string());
}
if !matches!(self.attr.min_value(), AttrValue::None) {
attrs.push("min_value".to_string());
}
if !matches!(self.attr.max_value(), AttrValue::None) {
attrs.push("max_value".to_string());
}
if !matches!(self.attr.scalar_increment(), AttrValue::None) {
attrs.push("scalar_increment".to_string());
}
if !matches!(self.attr.possible_values(), AttrValue::None) {
attrs.push("possible_values".to_string());
}
// TODO: Don't unwrap, use error
if let Ok(value) = self.attr.current_value().map_err(|e| {
error!("Failed to read: {e:?}");
e
}) {
if !matches!(value, AttrValue::None) {
attrs.push("current_value".to_string());
}
}
attrs
}
/// If return is `-1` then there is no default value
#[zbus(property)]
async fn default_value(&self) -> i32 {
match self.attr.default_value() {
AttrValue::Integer(i) => *i,
_ => -1,
}
}
async fn restore_default(&self) -> fdo::Result<()> {
self.attr.restore_default()?;
if self.name().property_type() == FirmwareAttributeType::Ppt {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default();
let mut config = self.config.lock().await;
let tuning = config.select_tunings(power_plugged == 1, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
if let AttrValue::Integer(i) = self.attr.default_value() {
*tune = *i;
}
}
if tuning.enabled {
self.attr
.set_current_value(self.attr.default_value())
.map_err(|e| {
error!("Could not set value: {e:?}");
e
})?;
}
config.write();
}
Ok(())
}
#[zbus(property)]
async fn min_value(&self) -> i32 {
Self::resolve_i32_value(self.attr.refresh_min_value(), self.attr.min_value())
}
#[zbus(property)]
async fn max_value(&self) -> i32 {
Self::resolve_i32_value(self.attr.refresh_max_value(), self.attr.max_value())
}
#[zbus(property)]
async fn scalar_increment(&self) -> i32 {
Self::resolve_i32_value(
self.attr.refresh_scalar_increment(),
self.attr.scalar_increment(),
)
}
#[zbus(property)]
async fn possible_values(&self) -> Vec<i32> {
match self.attr.possible_values() {
AttrValue::EnumInt(i) => i.clone(),
_ => Vec::default(),
}
}
#[zbus(property)]
async fn current_value(&self) -> fdo::Result<i32> {
if self.name().property_type() == FirmwareAttributeType::Ppt {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default()
== 1;
let config = self.config.lock().await;
if let Some(tuning) = config.select_tunings_ref(power_plugged, profile) {
if let Some(tune) = tuning.group.get(&self.name()) {
return Ok(*tune);
}
}
if let AttrValue::Integer(i) = self.attr.default_value() {
return Ok(*i);
}
return Err(fdo::Error::Failed(
"Could not read current value".to_string(),
));
}
if let Ok(AttrValue::Integer(i)) = self.attr.current_value() {
return Ok(i);
}
Err(fdo::Error::Failed(
"Could not read current value".to_string(),
))
}
#[zbus(property)]
async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> {
let name = self.attr.name();
let apply_value = match self.name().property_type() {
FirmwareAttributeType::Ppt => {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default();
let mut config = self.config.lock().await;
let tuning = config.select_tunings(power_plugged == 1, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!("Store tuning config for {name} = {:?}", value);
}
match tuning.enabled {
true => {
debug!("Tuning is enabled: setting value to PPT property {name} = {value}");
AttrValue::Integer(value)
}
false => {
warn!("Tuning is disabled: skipping setting value to PPT property {name}");
AttrValue::None
}
}
}
_ => {
let mut settings = self.config.lock().await;
settings
.armoury_settings
.entry(self.name())
.and_modify(|setting| {
debug!("Set config for {name} = {value}");
*setting = value;
})
.or_insert_with(|| {
debug!("Adding config for {name} = {value}");
value
});
AttrValue::Integer(value)
}
};
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set value {value} to attribute {name}: {e:?}");
e
})?;
// write config after setting value
self.config.lock().await.write();
Ok(())
}
}
pub async fn start_attributes_zbus(
conn: &Connection,
platform: RogPlatform,
power: AsusPower,
attributes: FirmwareAttributes,
config: Arc<Mutex<Config>>,
) -> Result<ArmouryAttributeRegistry, RogError> {
let mut registry = ArmouryAttributeRegistry::default();
for attr in attributes.attributes() {
let mut attr = AsusArmouryAttribute::new(
attr.clone(),
platform.clone(),
power.clone(),
config.clone(),
);
let registry_attr = attr.clone();
if let Err(e) = attr.reload().await {
error!(
"Skipping attribute '{}' due to reload error: {e:?}",
attr.attr.name()
);
break;
}
let attr_name = attr.attribute_name();
let path = dbus_path_for_attr(attr_name.as_str());
match zbus::object_server::SignalEmitter::new(conn, path) {
Ok(sig) => {
if let Err(e) = attr.watch_and_notify(sig).await {
error!("Failed to start watcher for '{}': {e:?}", attr.attr.name());
}
}
Err(e) => {
error!(
"Failed to create SignalEmitter for '{}': {e:?}",
attr.attr.name()
);
}
}
if let Err(e) = attr.move_to_zbus(conn).await {
error!("Failed to register attribute '{attr_name}' on zbus: {e:?}");
continue;
}
registry.push(registry_attr);
}
Ok(registry)
}
pub async fn set_config_or_default(
attrs: &FirmwareAttributes,
config: &mut Config,
power_plugged: bool,
profile: PlatformProfile,
) {
for attr in attrs.attributes().iter() {
let name: FirmwareAttribute = attr.name().into();
if name.property_type() == FirmwareAttributeType::Ppt {
let tuning = config.select_tunings(power_plugged, profile);
if !tuning.enabled {
debug!("Tuning group is not enabled, skipping");
return;
}
if let Some(tune) = tuning.group.get(&name) {
attr.set_current_value(&AttrValue::Integer(*tune))
.map_err(|e| {
error!("Failed to set {}: {e}", <&str>::from(name));
})
.ok();
} else {
let default = attr.default_value();
attr.set_current_value(default)
.map_err(|e| {
error!("Failed to set {}: {e}", <&str>::from(name));
})
.ok();
if let AttrValue::Integer(i) = default {
tuning.group.insert(name, *i);
info!(
"Set default tuning config for {} = {:?}",
<&str>::from(name),
i
);
// config.write();
}
}
} else {
// Handle non-PPT attributes (boolean and other settings)
if let Some(saved_value) = config.armoury_settings.get(&name) {
attr.set_current_value(&AttrValue::Integer(*saved_value))
.map_err(|e| {
error!("Failed to set {}: {e}", <&str>::from(name));
})
.ok();
info!(
"Restored armoury setting for {} = {:?}",
<&str>::from(name),
saved_value
);
}
}
}
}

View File

@@ -138,38 +138,44 @@ impl AniMeConfig {
// create a default config here
AniMeConfig {
system: vec![],
boot: vec![ActionLoader::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 1.0,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
Some(Duration::from_secs(2)),
Duration::from_secs(2),
)),
}],
wake: vec![ActionLoader::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 1.0,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
Some(Duration::from_secs(2)),
Duration::from_secs(2),
)),
}],
shutdown: 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,
}],
boot: vec![
ActionLoader::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 1.0,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
Some(Duration::from_secs(2)),
Duration::from_secs(2),
)),
},
],
wake: vec![
ActionLoader::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 1.0,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
Some(Duration::from_secs(2)),
Duration::from_secs(2),
)),
},
],
shutdown: 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,
},
],
..Default::default()
}
}

View File

@@ -8,7 +8,7 @@ use std::sync::Arc;
use std::thread::sleep;
use config_traits::StdConfig;
use log::{error, info, warn};
use log::{debug, error, info, warn};
use rog_anime::usb::{
pkt_flush, pkt_set_brightness, pkt_set_enable_display, pkt_set_enable_powersave_anim,
pkts_for_init, Brightness,
@@ -16,7 +16,7 @@ use rog_anime::usb::{
use rog_anime::{ActionData, AnimeDataBuffer, AnimePacketType};
use rog_platform::hid_raw::HidRaw;
use rog_platform::usb_raw::USBRaw;
use tokio::sync::{Mutex, MutexGuard};
use tokio::sync::Mutex;
use self::config::{AniMeConfig, AniMeConfigCached};
use crate::error::RogError;
@@ -59,6 +59,8 @@ impl AniMe {
config.rename_file_old();
*config = AniMeConfig::new();
config.write();
} else {
debug!("Initialised AniMe cache");
}
} else {
error!("AniMe Matrix could not init cache")
@@ -70,11 +72,9 @@ impl AniMe {
self.do_init_cache().await;
let pkts = pkts_for_init();
self.write_bytes(&pkts[0]).await?;
self.write_bytes(&pkts[1]).await
}
pub async fn lock_config(&self) -> MutexGuard<AniMeConfig> {
self.config.lock().await
self.write_bytes(&pkts[1]).await?;
debug!("Succesfully initialised AniMe matrix display");
Ok(())
}
pub async fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
@@ -176,7 +176,7 @@ impl AniMe {
return Ok(true); // Do safe exit
}
let inner = inner.clone();
tokio::task::spawn_local(async move {
tokio::task::spawn(async move {
inner
.write_data_buffer(frame)
.await
@@ -227,10 +227,11 @@ impl AniMe {
})
.ok();
}
// A write can block for many milliseconds so lets not hold the config lock for
// the same period
let enabled = inner.config.lock().await.builtin_anims_enabled;
inner
.write_bytes(&pkt_set_enable_powersave_anim(
inner.config.lock().await.builtin_anims_enabled,
))
.write_bytes(&pkt_set_enable_powersave_anim(enabled))
.await
.map_err(|err| {
warn!("rog_anime::run_animation:callback {}", err);

View File

@@ -1,7 +1,7 @@
use std::sync::atomic::Ordering;
use config_traits::StdConfig;
use log::{error, warn};
use log::{debug, error, warn};
use logind_zbus::manager::ManagerProxy;
use rog_anime::usb::{
pkt_set_brightness, pkt_set_builtin_animations, pkt_set_enable_display,
@@ -51,8 +51,11 @@ impl AniMeZbus {
.object_server()
.at(path.clone(), self)
.await
.map_err(|e| error!("Couldn't add server at path: {path}, {e:?}"))
.ok();
.map_err(|e| {
error!("Couldn't add server at path: {path}, {e:?}");
e
})?;
debug!("start_tasks was successful");
Ok(())
}
}
@@ -60,13 +63,17 @@ impl AniMeZbus {
// 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.
#[interface(name = "org.asuslinux.Anime")]
#[interface(name = "xyz.ljones.Anime")]
impl AniMeZbus {
/// 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 bright = self.0.config.lock().await.display_brightness;
self.0.set_builtins_enabled(false, bright).await?;
if self.0.config.lock().await.builtin_anims_enabled {
// This clears the display, causing flickers if done indiscriminately on every
// write. Therefore, we guard it behind a config check.
self.0.set_builtins_enabled(false, bright).await?;
}
self.0.thread_exit.store(true, Ordering::SeqCst);
self.0.write_data_buffer(input).await.map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err);
@@ -166,10 +173,7 @@ impl AniMeZbus {
async fn set_builtin_animations(&self, settings: Animations) {
self.0
.write_bytes(&pkt_set_builtin_animations(
settings.boot,
settings.awake,
settings.sleep,
settings.shutdown,
settings.boot, settings.awake, settings.sleep, settings.shutdown,
))
.await
.map_err(|err| {
@@ -443,53 +447,60 @@ impl crate::CtrlTask for AniMeZbus {
impl crate::Reloadable for AniMeZbus {
async fn reload(&mut self) -> Result<(), RogError> {
if let Ok(config) = self.0.config.try_lock() {
let anim = &config.builtin_anims;
// Set builtins
if config.builtin_anims_enabled {
self.0
.write_bytes(&pkt_set_builtin_animations(
anim.boot,
anim.awake,
anim.sleep,
anim.shutdown,
))
.await?;
}
// Builtins enabled or na?
let AniMeConfig {
builtin_anims_enabled,
builtin_anims,
display_enabled,
display_brightness,
off_when_lid_closed,
off_when_unplugged,
..
} = *self.0.config.lock().await;
// Set builtins
if builtin_anims_enabled {
self.0
.set_builtins_enabled(config.builtin_anims_enabled, config.display_brightness)
.write_bytes(&pkt_set_builtin_animations(
builtin_anims.boot,
builtin_anims.awake,
builtin_anims.sleep,
builtin_anims.shutdown,
))
.await?;
}
// Builtins enabled or na?
self.0
.set_builtins_enabled(builtin_anims_enabled, display_brightness)
.await?;
let manager = get_logind_manager().await;
let lid_closed = manager.lid_closed().await.unwrap_or_default();
let power_plugged = manager.on_external_power().await.unwrap_or_default();
let manager = get_logind_manager().await;
let lid_closed = manager.lid_closed().await.unwrap_or_default();
let power_plugged = manager.on_external_power().await.unwrap_or_default();
let turn_off = (lid_closed && config.off_when_lid_closed)
|| (!power_plugged && config.off_when_unplugged);
let turn_off =
(lid_closed && off_when_lid_closed) || (!power_plugged && off_when_unplugged);
self.0
.write_bytes(&pkt_set_enable_display(!turn_off))
.await
.map_err(|err| {
warn!("create_sys_event_tasks::reload {}", err);
})
.ok();
if turn_off || !display_enabled {
self.0.write_bytes(&pkt_set_enable_display(false)).await?;
// early return so we don't run animation thread
return Ok(());
}
if !builtin_anims_enabled && !self.0.cache.boot.is_empty() {
self.0
.write_bytes(&pkt_set_enable_display(!turn_off))
.write_bytes(&pkt_set_enable_powersave_anim(false))
.await
.map_err(|err| {
warn!("create_sys_event_tasks::reload {}", err);
})
.ok();
if turn_off || !config.display_enabled {
self.0.write_bytes(&pkt_set_enable_display(false)).await?;
// early return so we don't run animation thread
return Ok(());
}
if !config.builtin_anims_enabled && !self.0.cache.boot.is_empty() {
self.0
.write_bytes(&pkt_set_enable_powersave_anim(false))
.await
.ok();
let action = self.0.cache.boot.clone();
self.0.run_thread(action, true).await;
}
let action = self.0.cache.boot.clone();
self.0.run_thread(action, true).await;
}
Ok(())
}

View File

@@ -33,7 +33,6 @@ pub struct AuraConfig {
}
impl StdConfig for AuraConfig {
/// Detect the keyboard type and load from default DB if data available
fn new() -> Self {
panic!("This should not be used");
}
@@ -82,8 +81,9 @@ impl AuraConfig {
config
.builtins
.insert(*n, AuraEffect::default_with_mode(*n));
if !config.support_data.basic_zones.is_empty() {
}
if !config.support_data.basic_zones.is_empty() {
for n in &config.support_data.basic_modes {
let mut default = vec![];
for (i, tmp) in config.support_data.basic_zones.iter().enumerate() {
default.push(AuraEffect {
@@ -118,14 +118,14 @@ impl AuraConfig {
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 let Some(fx_vec) = multi.get_mut(effect.mode()) {
for fx in fx_vec.iter_mut() {
if fx.zone == effect.zone {
*fx = effect;
return;
}
}
fx.push(effect);
fx_vec.push(effect);
} else {
multi.insert(*effect.mode(), vec![effect]);
}
@@ -230,6 +230,8 @@ impl AuraConfig {
#[cfg(test)]
mod tests {
use std::sync::{Mutex, MutexGuard, OnceLock};
use rog_aura::keyboard::AuraPowerState;
use rog_aura::{
AuraEffect, AuraModeNum, AuraZone, Colour, Direction, LedBrightness, PowerZones, Speed,
@@ -237,8 +239,20 @@ mod tests {
use super::AuraConfig;
// Global mutex to serialize tests that rely on process-wide environment
// variables
static TEST_MUTEX: OnceLock<Mutex<()>> = OnceLock::new();
fn test_lock() -> MutexGuard<'static, ()> {
TEST_MUTEX
.get_or_init(|| Mutex::new(()))
.lock()
.expect("TEST_MUTEX poisoned")
}
#[test]
fn set_multizone_4key_config() {
let _guard = test_lock();
std::env::set_var("BOARD_NAME", "");
let mut config = AuraConfig::new("19b6");
@@ -330,6 +344,7 @@ mod tests {
#[test]
fn set_multizone_multimode_config() {
let _guard = test_lock();
std::env::set_var("BOARD_NAME", "");
let mut config = AuraConfig::new("19b6");
@@ -378,6 +393,7 @@ mod tests {
#[test]
fn verify_0x1866_g531i() {
let _guard = test_lock();
std::env::set_var("BOARD_NAME", "G513I");
let mut config = AuraConfig::new("1866");
@@ -409,6 +425,7 @@ mod tests {
#[test]
fn verify_0x19b6_g634j() {
let _guard = test_lock();
std::env::set_var("BOARD_NAME", "G634J");
let mut config = AuraConfig::new("19b6");

View File

@@ -25,10 +25,34 @@ pub struct Aura {
impl Aura {
/// Initialise the device if required.
pub async fn do_initialization(&self) -> Result<(), RogError> {
if let Some(hid) = &self.hid {
let hid = hid.lock().await;
let init_1: [u8; 2] = [
0x5d, 0xb9,
];
let init_2 = b"]ASUS Tech.Inc.";
let init_3: [u8; 6] = [
0x5d, 0x05, 0x20, 0x31, 0, 0x1a,
];
hid.write_bytes(&init_1)?;
hid.write_bytes(init_2)?;
hid.write_bytes(&init_3)?;
let config = self.config.lock().await;
if config.support_data.device_name.contains("GZ30")
|| config.support_data.device_name.contains("Z13")
{
let z13_init: [u8; 4] = [
0x5d, 0xc0, 0x03, 0x01,
];
hid.write_bytes(&z13_init)?;
}
}
Ok(())
}
pub async fn lock_config(&self) -> MutexGuard<AuraConfig> {
pub async fn lock_config(&self) -> MutexGuard<'_, AuraConfig> {
self.config.lock().await
}
@@ -96,11 +120,7 @@ impl Aura {
if matches!(dev_type, AuraDeviceType::LaptopKeyboardTuf) {
if let Some(platform) = &self.backlight {
let buf = [
1,
mode.mode as u8,
mode.colour1.r,
mode.colour1.g,
mode.colour1.b,
1, mode.mode as u8, mode.colour1.r, mode.colour1.g, mode.colour1.b,
mode.speed as u8,
];
platform.lock().await.set_kbd_rgb_mode(&buf)?;
@@ -142,14 +162,69 @@ impl Aura {
let hid_raw = hid_raw.lock().await;
if let Some(p) = config.enabled.states.first() {
if p.zone == PowerZones::Ally {
let msg = [0x5d, 0xd1, 0x09, 0x01, p.new_to_byte() as u8, 0x0, 0x0];
let msg = [
0x5d,
0xd1,
0x09,
0x01,
p.new_to_byte() as u8,
0x0,
0x0,
];
hid_raw.write_bytes(&msg)?;
return Ok(());
}
}
let bytes = config.enabled.to_bytes(config.led_type);
let msg = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3]];
let mut enabled = config.enabled.clone();
if config.support_data.device_name.contains("GZ30")
|| config.support_data.device_name.contains("Z13")
{
let logo_state = enabled
.states
.iter()
.find(|s| s.zone == PowerZones::Logo)
.cloned();
if let Some(logo) = logo_state {
let mut lid_found = false;
let mut bar_found = false;
for s in enabled.states.iter_mut() {
if s.zone == PowerZones::Lid {
s.boot = logo.boot;
s.awake = logo.awake;
s.sleep = logo.sleep;
s.shutdown = logo.shutdown;
lid_found = true;
}
if s.zone == PowerZones::Lightbar {
s.boot = logo.boot;
s.awake = logo.awake;
s.sleep = logo.sleep;
s.shutdown = logo.shutdown;
bar_found = true;
}
}
if !lid_found {
let mut new_state = logo;
new_state.zone = PowerZones::Lid;
enabled.states.push(new_state.clone());
new_state.zone = PowerZones::Lightbar;
enabled.states.push(new_state);
} else if !bar_found {
// Lid found but not bar?
let mut new_state = logo;
new_state.zone = PowerZones::Lightbar;
enabled.states.push(new_state);
}
}
}
let bytes = enabled.to_bytes(config.led_type);
let msg = [
0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3], 0xff,
];
hid_raw.write_bytes(&msg)?;
}
Ok(())
@@ -194,7 +269,9 @@ impl Aura {
let r = row[9];
let g = row[10];
let b = row[11];
tuf.lock().await.set_kbd_rgb_mode(&[0, 0, r, g, b, 0])?;
tuf.lock().await.set_kbd_rgb_mode(&[
0, 0, r, g, b, 0,
])?;
}
}
}
@@ -206,7 +283,9 @@ impl Aura {
if let Some(hid_raw) = &self.hid {
let mut config = self.config.lock().await;
if config.ally_fix.is_none() {
let msg = [0x5d, 0xbd, 0x01, 0xff, 0xff, 0xff, 0xff];
let msg = [
0x5d, 0xbd, 0x01, 0xff, 0xff, 0xff, 0xff,
];
hid_raw.lock().await.write_bytes(&msg)?;
info!("Reset Ally power settings to base");
config.ally_fix = Some(true);

View File

@@ -14,7 +14,7 @@ use crate::error::RogError;
use crate::{CtrlTask, Reloadable};
pub const AURA_ZBUS_NAME: &str = "Aura";
pub const AURA_ZBUS_PATH: &str = "/org/asuslinux";
pub const AURA_ZBUS_PATH: &str = "/xyz/ljones";
#[derive(Clone)]
pub struct AuraZbus(Aura);
@@ -50,7 +50,7 @@ impl AuraZbus {
/// The main interface for changing, reading, or notfying
///
/// LED commands are split between Brightness, Modes, Per-Key
#[interface(name = "org.asuslinux.Aura")]
#[interface(name = "xyz.ljones.Aura")]
impl AuraZbus {
/// Return the device type for this Aura keyboard
#[zbus(property)]
@@ -71,7 +71,13 @@ impl AuraZbus {
#[zbus(property)]
async fn set_brightness(&mut self, brightness: LedBrightness) -> Result<(), ZbErr> {
if let Some(bl) = self.0.backlight.as_ref() {
return Ok(bl.lock().await.set_brightness(brightness.into())?);
let res = bl.lock().await.set_brightness(brightness.into());
if res.is_ok() {
let mut config = self.0.config.lock().await;
config.brightness = brightness;
config.write();
}
return Ok(res?);
}
Err(ZbErr::Failed("No sysfs brightness control".to_string()))
}
@@ -176,7 +182,6 @@ impl AuraZbus {
self.0.set_brightness(config.brightness.into()).await?;
config.set_builtin(effect);
config.write();
Ok(())
}
@@ -202,9 +207,10 @@ impl AuraZbus {
let mut config = self.0.config.lock().await;
for opt in options.states {
let zone = opt.zone;
for config in config.enabled.states.iter_mut() {
if config.zone == zone {
*config = opt;
for state in config.enabled.states.iter_mut() {
if state.zone == zone {
*state = opt;
break;
}
}
}
@@ -227,7 +233,7 @@ impl AuraZbus {
impl CtrlTask for AuraZbus {
fn zbus_path() -> &'static str {
"/org/asuslinux"
"/xyz/ljones"
}
async fn create_tasks(&self, _: SignalEmitter<'static>) -> Result<(), RogError> {

View File

@@ -4,6 +4,7 @@
// - Add it to Zbus server
// - If udev sees device removed then remove the zbus path
use std::collections::HashMap;
use std::sync::Arc;
use dmi_id::DMIID;
@@ -23,8 +24,9 @@ use crate::aura_scsi::trait_impls::ScsiZbus;
use crate::aura_slash::trait_impls::SlashZbus;
use crate::aura_types::DeviceHandle;
use crate::error::RogError;
use crate::ASUS_ZBUS_PATH;
pub const ASUS_ZBUS_PATH: &str = "/org/asuslinux";
const MOD_NAME: &str = "aura";
/// Returns only the Device details concatenated in a form usable for
/// adding/appending to a filename
@@ -54,26 +56,27 @@ pub fn filename_partial(parent: &Device) -> Option<OwnedObjectPath> {
fn dbus_path_for_dev(parent: &Device) -> Option<OwnedObjectPath> {
if let Some(filename) = filename_partial(parent) {
return Some(
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{filename}")).into(),
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{filename}"))
.into(),
);
}
None
}
fn dbus_path_for_tuf() -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/tuf")).into()
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/tuf")).into()
}
fn dbus_path_for_slash() -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/slash")).into()
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/slash")).into()
}
fn dbus_path_for_anime() -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/anime")).into()
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/anime")).into()
}
fn dbus_path_for_scsi(prod_id: &str) -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{prod_id}_scsi")).into()
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{prod_id}_scsi")).into()
}
fn dev_prop_matches(dev: &Device, prop: &str, value: &str) -> bool {
@@ -83,15 +86,6 @@ fn dev_prop_matches(dev: &Device, prop: &str, value: &str) -> bool {
false
}
// TODO:
// - make this the HID manager (and universal)
// - *really* need to make most of this actual kernel drivers
// - LED class
// - RGB modes (how, attribute?)
// - power features (how, attribute?)
// - what about per-key stuff?
// - how would the AniMe be exposed? Just a series of LEDs?
/// A device.
///
/// Each controller within should track its dbus path so it can be removed if
@@ -99,23 +93,46 @@ fn dev_prop_matches(dev: &Device, prop: &str, value: &str) -> bool {
pub struct AsusDevice {
device: DeviceHandle,
dbus_path: OwnedObjectPath,
hid_key: Option<String>,
}
pub struct DeviceManager {
_dbus_connection: Connection,
_hid_handles: Arc<Mutex<HashMap<String, Arc<Mutex<HidRaw>>>>>,
}
impl DeviceManager {
#[allow(clippy::type_complexity)]
async fn get_or_create_hid_handle(
handles: &Arc<Mutex<HashMap<String, Arc<Mutex<HidRaw>>>>>,
endpoint: &Device,
) -> Result<(Arc<Mutex<HidRaw>>, String), RogError> {
let dev_node = endpoint
.devnode()
.ok_or_else(|| RogError::MissingFunction("hidraw devnode missing".to_string()))?;
let key = dev_node.to_string_lossy().to_string();
if let Some(existing) = handles.lock().await.get(&key).cloned() {
return Ok((existing, key));
}
let hidraw = HidRaw::from_device(endpoint.clone())?;
let handle = Arc::new(Mutex::new(hidraw));
handles.lock().await.insert(key.clone(), handle.clone());
Ok((handle, key))
}
async fn init_hid_devices(
connection: &Connection,
device: Device,
handles: Arc<Mutex<HashMap<String, Arc<Mutex<HidRaw>>>>>,
) -> Result<Vec<AsusDevice>, RogError> {
let mut devices = Vec::new();
if let Some(usb_device) = device.parent_with_subsystem_devtype("usb", "usb_device")? {
if let Some(usb_id) = usb_device.attribute_value("idProduct") {
if let Some(vendor_id) = usb_device.attribute_value("idVendor") {
if vendor_id != "0b05" {
debug!("Not ASUS vendor ID");
debug!("Not ASUS vendor ID: {}", vendor_id.to_string_lossy());
return Ok(devices);
}
// Almost all devices are identified by the productId.
@@ -123,9 +140,10 @@ impl DeviceManager {
// 1. Generate an interface path
// 2. Create the device
// Use the top-level endpoint, not the parent
if let Ok(hidraw) = HidRaw::from_device(device) {
if let Ok((dev, hid_key)) =
Self::get_or_create_hid_handle(&handles, &device).await
{
debug!("Testing device {usb_id:?}");
let dev = Arc::new(Mutex::new(hidraw));
// SLASH DEVICE
if let Ok(dev_type) = DeviceHandle::new_slash_hid(
dev.clone(),
@@ -141,6 +159,7 @@ impl DeviceManager {
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: Some(hid_key.clone()),
});
}
}
@@ -159,6 +178,7 @@ impl DeviceManager {
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: Some(hid_key.clone()),
});
}
}
@@ -177,9 +197,12 @@ impl DeviceManager {
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: Some(hid_key),
});
}
}
} else {
warn!("Failed to initialise shared hid handle for {usb_id:?}");
}
}
}
@@ -188,7 +211,10 @@ impl DeviceManager {
}
/// To be called on daemon startup
async fn init_all_hid(connection: &Connection) -> Result<Vec<AsusDevice>, RogError> {
async fn init_all_hid(
connection: &Connection,
handles: Arc<Mutex<HashMap<String, Arc<Mutex<HidRaw>>>>>,
) -> Result<Vec<AsusDevice>, RogError> {
// track and ensure we use only one hidraw per prod_id
// let mut interfaces = HashSet::new();
let mut devices: Vec<AsusDevice> = Vec::new();
@@ -207,7 +233,7 @@ impl DeviceManager {
.scan_devices()
.map_err(|e| PlatformError::IoPath("enumerator".to_owned(), e))?
{
devices.append(&mut Self::init_hid_devices(connection, device).await?);
devices.append(&mut Self::init_hid_devices(connection, device, handles.clone()).await?);
}
Ok(devices)
@@ -220,7 +246,7 @@ impl DeviceManager {
) -> Option<AsusDevice> {
// "ID_MODEL_ID" "1932"
// "ID_VENDOR_ID" "0b05"
if dev_prop_matches(&device, "ID_VENDOR_ID", "0b05") {
if dev_prop_matches(device, "ID_VENDOR_ID", "0b05") {
if let Some(dev_node) = device.devnode() {
let prod_id = device
.property_value("ID_MODEL_ID")
@@ -235,6 +261,7 @@ impl DeviceManager {
return Some(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: None,
});
}
}
@@ -275,17 +302,20 @@ impl DeviceManager {
found.push(path);
}
} else {
warn!("No serial for SCSI device");
debug!("No serial for SCSI device: {:?}", device.devpath());
}
}
Ok(devices)
}
pub async fn find_all_devices(connection: &Connection) -> Vec<AsusDevice> {
pub async fn find_all_devices(
connection: &Connection,
handles: Arc<Mutex<HashMap<String, Arc<Mutex<HidRaw>>>>>,
) -> Vec<AsusDevice> {
let mut devices: Vec<AsusDevice> = Vec::new();
// HID first, always
if let Ok(devs) = &mut Self::init_all_hid(connection).await {
if let Ok(devs) = &mut Self::init_all_hid(connection, handles.clone()).await {
devices.append(devs);
}
// USB after, need to check if HID picked something up and if so, skip it
@@ -313,6 +343,7 @@ impl DeviceManager {
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: None,
});
}
} else {
@@ -326,11 +357,18 @@ impl DeviceManager {
if let DeviceHandle::AniMe(anime) = dev_type.clone() {
let path = dbus_path_for_anime();
let ctrl = AniMeZbus::new(anime);
ctrl.start_tasks(connection, path.clone()).await.unwrap();
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
});
if ctrl
.start_tasks(connection, path.clone())
.await
.map_err(|e| error!("Failed to start tasks: {e:?}, not adding this device"))
.is_ok()
{
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: None,
});
}
}
} else {
info!("Tested device was not AniMe Matrix");
@@ -356,6 +394,7 @@ impl DeviceManager {
devices.push(AsusDevice {
device: dev_type,
dbus_path: path,
hid_key: None,
});
}
}
@@ -371,16 +410,19 @@ impl DeviceManager {
pub async fn new(connection: Connection) -> Result<Self, RogError> {
let conn_copy = connection.clone();
let devices = Arc::new(Mutex::new(Self::find_all_devices(&conn_copy).await));
let hid_handles = Arc::new(Mutex::new(HashMap::new()));
let devices = Self::find_all_devices(&conn_copy, hid_handles.clone()).await;
info!("Found {} valid devices on startup", devices.len());
let devices = Arc::new(Mutex::new(devices));
let manager = Self {
_dbus_connection: connection,
_hid_handles: hid_handles.clone(),
};
// TODO: The /sysfs/ LEDs don't cause events, so they need to be manually
// checked for and added
// detect all plugged in aura devices (eventually)
// only USB devices are detected for here
let hid_handles_thread = hid_handles.clone();
std::thread::spawn(move || {
let mut monitor = MonitorBuilder::new()?.listen()?;
let mut poll = Poll::new()?;
@@ -409,6 +451,7 @@ impl DeviceManager {
let devices = devices.clone();
let conn_copy = conn_copy.clone();
let hid_handles = hid_handles_thread.clone();
block_on(async move {
// SCSCI devs
if subsys == "block" {
@@ -427,20 +470,20 @@ impl DeviceManager {
{
index
} else {
warn!("No device for dbus path: {path:?}");
if dev_prop_matches(&event.device(), "ID_VENDOR_ID", "0b05")
{
warn!("No device for dbus path: {path:?}");
}
return Ok(());
};
info!("removing: {path:?}");
let dev = devices.lock().await.remove(index);
let path = path.clone();
match dev.device {
DeviceHandle::Scsi(_) => {
conn_copy
.object_server()
.remove::<ScsiZbus, _>(&path)
.await?;
}
_ => {}
if let DeviceHandle::Scsi(_) = dev.device {
conn_copy
.object_server()
.remove::<ScsiZbus, _>(&path)
.await?;
}
}
} else if action == "add" {
@@ -484,6 +527,7 @@ impl DeviceManager {
// Iter in reverse so as to not screw up indexing
for index in removals.iter().rev() {
let dev = devices.lock().await.remove(*index);
let hid_key = dev.hid_key.clone();
let path = path.clone();
let res = match dev.device {
DeviceHandle::Aura(_) => {
@@ -513,14 +557,20 @@ impl DeviceManager {
_ => todo!(),
};
info!("AuraManager removed: {path:?}, {res}");
if let Some(key) = hid_key {
hid_handles.lock().await.remove(&key);
}
}
}
} else if action == "add" {
let evdev = event.device();
if let Ok(mut new_devs) =
Self::init_hid_devices(&conn_copy, evdev)
.await
.map_err(|e| error!("Couldn't add new device: {e:?}"))
if let Ok(mut new_devs) = Self::init_hid_devices(
&conn_copy,
evdev,
hid_handles.clone(),
)
.await
.map_err(|e| error!("Couldn't add new device: {e:?}"))
{
devices.lock().await.append(&mut new_devs);
}

View File

@@ -20,7 +20,7 @@ impl ScsiAura {
Self { device, config }
}
pub async fn lock_config(&self) -> MutexGuard<ScsiConfig> {
pub async fn lock_config(&self) -> MutexGuard<'_, ScsiConfig> {
self.config.lock().await
}

View File

@@ -34,7 +34,7 @@ impl ScsiZbus {
}
}
#[interface(name = "org.asuslinux.ScsiAura")]
#[interface(name = "xyz.ljones.ScsiAura")]
impl ScsiZbus {
/// Return the device type for this Aura keyboard
#[zbus(property)]

View File

@@ -9,20 +9,32 @@ const CONFIG_FILE: &str = "slash.ron";
pub struct SlashConfig {
#[serde(skip)]
pub slash_type: SlashType,
pub slash_enabled: bool,
pub slash_brightness: u8,
pub slash_interval: u8,
pub slash_mode: SlashMode,
pub enabled: bool,
pub brightness: u8,
pub display_interval: u8,
pub display_mode: SlashMode,
pub show_on_boot: bool,
pub show_on_shutdown: bool,
pub show_on_sleep: bool,
pub show_on_battery: bool,
pub show_battery_warning: bool,
pub show_on_lid_closed: bool,
}
impl Default for SlashConfig {
fn default() -> Self {
SlashConfig {
slash_enabled: true,
slash_brightness: 255,
slash_interval: 0,
slash_mode: SlashMode::Bounce,
enabled: true,
brightness: 255,
display_interval: 0,
display_mode: SlashMode::Bounce,
slash_type: SlashType::Unsupported,
show_on_boot: true,
show_on_shutdown: true,
show_on_sleep: true,
show_on_battery: true,
show_battery_warning: true,
show_on_lid_closed: true,
}
}
}
@@ -45,10 +57,10 @@ impl StdConfigLoad for SlashConfig {}
impl From<&SlashConfig> for DeviceState {
fn from(config: &SlashConfig) -> Self {
DeviceState {
slash_enabled: config.slash_enabled,
slash_brightness: config.slash_brightness,
slash_interval: config.slash_interval,
slash_mode: config.slash_mode,
slash_enabled: config.enabled,
slash_brightness: config.brightness,
slash_interval: config.display_interval,
slash_mode: config.display_mode,
}
}
}

View File

@@ -3,8 +3,7 @@ use std::sync::Arc;
use config::SlashConfig;
use rog_platform::hid_raw::HidRaw;
use rog_platform::usb_raw::USBRaw;
use rog_slash::usb::{pkt_set_mode, pkt_set_options, pkts_for_init};
use rog_slash::SlashType;
use rog_slash::usb::{slash_pkt_enable, slash_pkt_init, slash_pkt_options, slash_pkt_set_mode};
use tokio::sync::{Mutex, MutexGuard};
use crate::error::RogError;
@@ -28,7 +27,7 @@ impl Slash {
Self { hid, usb, config }
}
pub async fn lock_config(&self) -> MutexGuard<SlashConfig> {
pub async fn lock_config(&self) -> MutexGuard<'_, SlashConfig> {
self.config.lock().await
}
@@ -46,22 +45,22 @@ impl Slash {
pub async fn do_initialization(&self) -> Result<(), RogError> {
// Don't try to initialise these models as the asus drivers already did
let config = self.config.lock().await;
if !matches!(config.slash_type, SlashType::GA605 | SlashType::GU605) {
for pkt in &pkts_for_init(config.slash_type) {
self.write_bytes(pkt).await?;
}
for pkt in &slash_pkt_init(config.slash_type) {
self.write_bytes(pkt).await?;
}
self.write_bytes(&slash_pkt_enable(config.slash_type, config.enabled))
.await?;
// Apply config upon initialization
let option_packets = pkt_set_options(
let option_packets = slash_pkt_options(
config.slash_type,
config.slash_enabled,
config.slash_brightness,
config.slash_interval,
config.enabled,
config.brightness,
config.display_interval,
);
self.write_bytes(&option_packets).await?;
let mode_packets = pkt_set_mode(config.slash_type, config.slash_mode);
let mode_packets = slash_pkt_set_mode(config.slash_type, config.display_mode);
// self.node.write_bytes(&mode_packets[0])?;
self.write_bytes(&mode_packets[1]).await?;

View File

@@ -1,6 +1,10 @@
use config_traits::StdConfig;
use log::{debug, error, warn};
use rog_slash::usb::{pkt_save, pkt_set_mode, pkt_set_options};
use rog_slash::usb::{
slash_pkt_battery_saver, slash_pkt_boot, slash_pkt_enable, slash_pkt_lid_closed,
slash_pkt_low_battery, slash_pkt_options, slash_pkt_save, slash_pkt_set_mode,
slash_pkt_shutdown, slash_pkt_sleep,
};
use rog_slash::{DeviceState, SlashMode};
use zbus::zvariant::OwnedObjectPath;
use zbus::{interface, Connection};
@@ -36,30 +40,37 @@ impl SlashZbus {
}
}
#[interface(name = "org.asuslinux.Slash")]
#[interface(name = "xyz.ljones.Slash")]
impl SlashZbus {
/// Get enabled or not
#[zbus(property)]
async fn enabled(&self) -> bool {
let lock = self.0.lock_config().await;
lock.slash_enabled
lock.enabled
}
/// Set enabled true or false
#[zbus(property)]
async fn set_enabled(&self, enabled: bool) {
let mut config = self.0.lock_config().await;
let brightness = if enabled && config.slash_brightness == 0 {
let brightness = if enabled && config.brightness == 0 {
0x88
} else {
config.slash_brightness
config.brightness
};
self.0
.write_bytes(&pkt_set_options(
.write_bytes(&slash_pkt_enable(config.slash_type, enabled))
.await
.map_err(|err| {
warn!("ctrl_slash::enable {}", err);
})
.ok();
self.0
.write_bytes(&slash_pkt_options(
config.slash_type,
enabled,
brightness,
config.slash_interval,
config.display_interval,
))
.await
.map_err(|err| {
@@ -67,8 +78,8 @@ impl SlashZbus {
})
.ok();
config.slash_enabled = enabled;
config.slash_brightness = brightness;
config.enabled = enabled;
config.brightness = brightness;
config.write();
}
@@ -76,7 +87,7 @@ impl SlashZbus {
#[zbus(property)]
async fn brightness(&self) -> u8 {
let config = self.0.lock_config().await;
config.slash_brightness
config.brightness
}
/// Set brightness level
@@ -85,11 +96,11 @@ impl SlashZbus {
let mut config = self.0.lock_config().await;
let enabled = brightness > 0;
self.0
.write_bytes(&pkt_set_options(
.write_bytes(&slash_pkt_options(
config.slash_type,
enabled,
brightness,
config.slash_interval,
config.display_interval,
))
.await
.map_err(|err| {
@@ -97,15 +108,15 @@ impl SlashZbus {
})
.ok();
config.slash_enabled = enabled;
config.slash_brightness = brightness;
config.enabled = enabled;
config.brightness = brightness;
config.write();
}
#[zbus(property)]
async fn interval(&self) -> u8 {
let config = self.0.lock_config().await;
config.slash_interval
config.display_interval
}
/// Set interval between slash animations (0-255)
@@ -113,11 +124,8 @@ impl SlashZbus {
async fn set_interval(&self, interval: u8) {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&pkt_set_options(
config.slash_type,
config.slash_enabled,
config.slash_brightness,
interval,
.write_bytes(&slash_pkt_options(
config.slash_type, config.enabled, config.brightness, interval,
))
.await
.map_err(|err| {
@@ -125,40 +133,31 @@ impl SlashZbus {
})
.ok();
config.slash_interval = interval;
config.display_interval = interval;
config.write();
}
#[zbus(property)]
async fn slash_mode(&self) -> u8 {
async fn mode(&self) -> zbus::fdo::Result<u8> {
let config = self.0.lock_config().await;
config.slash_interval
Ok(config.display_interval)
}
/// Set interval between slash animations (0-255)
#[zbus(property)]
async fn set_slash_mode(&self, slash_mode: SlashMode) {
async fn set_mode(&self, mode: SlashMode) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
let command_packets = pkt_set_mode(config.slash_type, slash_mode);
let command_packets = slash_pkt_set_mode(config.slash_type, mode);
// self.node.write_bytes(&command_packets[0])?;
self.0.write_bytes(&command_packets[1]).await?;
self.0
.write_bytes(&command_packets[1])
.await
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
self.0
.write_bytes(&pkt_save(config.slash_type))
.await
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
.write_bytes(&slash_pkt_save(config.slash_type))
.await?;
config.slash_mode = slash_mode;
config.display_mode = mode;
config.write();
Ok(())
}
/// Get the device state as stored by asusd
@@ -167,6 +166,111 @@ impl SlashZbus {
let config = self.0.lock_config().await;
DeviceState::from(&*config)
}
#[zbus(property)]
async fn show_on_boot(&self) -> zbus::fdo::Result<bool> {
let config = self.0.lock_config().await;
Ok(config.show_on_boot)
}
#[zbus(property)]
async fn set_show_on_boot(&self, enable: bool) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&slash_pkt_boot(config.slash_type, enable))
.await?;
config.show_on_boot = enable;
config.write();
Ok(())
}
#[zbus(property)]
async fn show_on_sleep(&self) -> zbus::fdo::Result<bool> {
let config = self.0.lock_config().await;
Ok(config.show_on_sleep)
}
#[zbus(property)]
async fn set_show_on_sleep(&self, enable: bool) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&slash_pkt_sleep(config.slash_type, enable))
.await?;
config.show_on_sleep = enable;
config.write();
Ok(())
}
#[zbus(property)]
async fn show_on_shutdown(&self) -> zbus::fdo::Result<bool> {
let config = self.0.lock_config().await;
Ok(config.show_on_shutdown)
}
#[zbus(property)]
async fn set_show_on_shutdown(&self, enable: bool) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&slash_pkt_shutdown(config.slash_type, enable))
.await?;
config.show_on_shutdown = enable;
config.write();
Ok(())
}
#[zbus(property)]
async fn show_on_battery(&self) -> zbus::fdo::Result<bool> {
let config = self.0.lock_config().await;
Ok(config.show_on_battery)
}
#[zbus(property)]
async fn set_show_on_battery(&self, enable: bool) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&slash_pkt_battery_saver(config.slash_type, enable))
.await?;
config.show_on_battery = enable;
config.write();
Ok(())
}
#[zbus(property)]
async fn show_battery_warning(&self) -> zbus::fdo::Result<bool> {
let config = self.0.lock_config().await;
Ok(config.show_battery_warning)
}
#[zbus(property)]
async fn set_show_battery_warning(&self, enable: bool) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&slash_pkt_low_battery(config.slash_type, enable))
.await?;
config.show_battery_warning = enable;
config.write();
Ok(())
}
#[zbus(property)]
async fn show_on_lid_closed(&self) -> zbus::fdo::Result<bool> {
let config = self.0.lock_config().await;
Ok(config.show_on_lid_closed)
}
#[zbus(property)]
async fn set_show_on_lid_closed(&self, enable: bool) -> zbus::Result<()> {
let mut config = self.0.lock_config().await;
self.0
.write_bytes(&slash_pkt_lid_closed(config.slash_type, enable))
.await?;
self.0
.write_bytes(&slash_pkt_save(config.slash_type))
.await?;
config.show_on_lid_closed = enable;
config.write();
Ok(())
}
}
impl Reloadable for SlashZbus {
@@ -174,17 +278,40 @@ impl Reloadable for SlashZbus {
debug!("reloading slash settings");
let config = self.0.lock_config().await;
self.0
.write_bytes(&pkt_set_options(
.write_bytes(&slash_pkt_options(
config.slash_type,
config.slash_enabled,
config.slash_brightness,
config.slash_interval,
config.enabled,
config.brightness,
config.display_interval,
))
.await
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
warn!("set_options {}", err);
})
.ok();
macro_rules! write_bytes_with_warning {
($packet_fn:expr, $cfg:ident, $warn_msg:expr) => {
self.0
.write_bytes(&$packet_fn(config.slash_type, config.$cfg))
.await
.map_err(|err| {
warn!("{} {}", $warn_msg, err);
})
.ok();
};
}
write_bytes_with_warning!(slash_pkt_boot, show_on_boot, "show_on_boot");
write_bytes_with_warning!(slash_pkt_sleep, show_on_sleep, "show_on_sleep");
write_bytes_with_warning!(slash_pkt_shutdown, show_on_shutdown, "show_on_shutdown");
write_bytes_with_warning!(slash_pkt_battery_saver, show_on_battery, "show_on_battery");
write_bytes_with_warning!(
slash_pkt_low_battery,
show_battery_warning,
"show_battery_warning"
);
Ok(())
}
}

View File

@@ -104,23 +104,28 @@ impl DeviceHandle {
/// Try AniMe Matrix HID. If one exists it is initialsed and returned.
pub async fn maybe_anime_hid(
device: Arc<Mutex<HidRaw>>,
prod_id: &str,
_device: Arc<Mutex<HidRaw>>,
_prod_id: &str,
) -> Result<Self, RogError> {
debug!("Testing for HIDRAW AniMe");
let anime_type = AnimeType::from_dmi();
dbg!(prod_id);
if matches!(anime_type, AnimeType::Unsupported) || prod_id != "193b" {
log::info!("Unknown or invalid AniMe: {prod_id:?}, skipping");
return Err(RogError::NotFound("No anime-matrix device".to_string()));
}
info!("Found AniMe Matrix HIDRAW {anime_type:?}: {prod_id}");
// TODO: can't use HIDRAW for anime at the moment
Err(RogError::NotFound(
"Can't use anime over hidraw yet. Skip.".to_string(),
))
let mut config = AniMeConfig::new().load();
config.anime_type = anime_type;
let mut anime = AniMe::new(Some(device), None, Arc::new(Mutex::new(config)));
anime.do_initialization().await?;
Ok(Self::AniMe(anime))
// debug!("Testing for HIDRAW AniMe");
// let anime_type = AnimeType::from_dmi();
// dbg!(prod_id);
// if matches!(anime_type, AnimeType::Unsupported) || prod_id != "193b"
// { log::info!("Unknown or invalid AniMe: {prod_id:?},
// skipping"); return Err(RogError::NotFound("No
// anime-matrix device".to_string())); }
// info!("Found AniMe Matrix HIDRAW {anime_type:?}: {prod_id}");
// let mut config = AniMeConfig::new().load();
// config.anime_type = anime_type;
// let mut anime = AniMe::new(Some(device), None,
// Arc::new(Mutex::new(config))); anime.do_initialization().
// await?; Ok(Self::AniMe(anime))
}
pub async fn maybe_anime_usb() -> Result<Self, RogError> {
@@ -191,6 +196,7 @@ impl DeviceHandle {
Some(Arc::new(Mutex::new(k)))
});
// Load saved mode, colours, brightness, power from disk; apply on reload
let mut config = AuraConfig::load_and_update_config(prod_id);
config.led_type = aura_type;
let aura = Aura {

View File

@@ -1,95 +1,119 @@
use config_traits::{StdConfig, StdConfigLoad1};
use std::collections::HashMap;
use config_traits::{StdConfig, StdConfigLoad2};
use rog_platform::asus_armoury::FirmwareAttribute;
use rog_platform::cpu::CPUEPP;
use rog_platform::platform::ThrottlePolicy;
use rog_platform::platform::PlatformProfile;
use serde::{Deserialize, Serialize};
const CONFIG_FILE: &str = "asusd.ron";
#[derive(Deserialize, Serialize, Debug, PartialEq, PartialOrd)]
/// Default value for base_charge_control_end_threshold when not present in config.
/// Returns 0 so restore_charge_limit() skips restoration for upgraded configs.
fn default_base_charge_limit() -> u8 {
0
}
#[derive(Default, Clone, Deserialize, Serialize, PartialEq)]
pub struct Tuning {
pub enabled: bool,
pub group: HashMap<FirmwareAttribute, i32>,
}
type Tunings = HashMap<PlatformProfile, Tuning>;
#[derive(Deserialize, Serialize, PartialEq)]
pub struct Config {
// The current charge limit applied
pub charge_control_end_threshold: u8,
/// Save charge limit for restoring
#[serde(skip)]
/// Save charge limit for restoring after one-shot full charge
#[serde(default = "default_base_charge_limit")]
pub base_charge_control_end_threshold: u8,
pub panel_od: bool,
pub boot_sound: bool,
pub mini_led_mode: bool,
pub disable_nvidia_powerd_on_battery: bool,
/// An optional command/script to run when power is changed to AC
pub ac_command: String,
/// An optional command/script to run when power is changed to battery
pub bat_command: String,
/// Set true if energy_performance_preference should be set if the
/// throttle/platform profile is changed
pub throttle_policy_linked_epp: bool,
/// Which throttle/profile to use on battery power
pub throttle_policy_on_battery: ThrottlePolicy,
/// platform profile is changed
pub platform_profile_linked_epp: bool,
/// Which platform profile to use on battery power
pub platform_profile_on_battery: PlatformProfile,
/// Should the throttle policy be set on bat/ac change?
pub change_throttle_policy_on_battery: bool,
/// Which throttle/profile to use on AC power
pub throttle_policy_on_ac: ThrottlePolicy,
/// Should the throttle policy be set on bat/ac change?
pub change_throttle_policy_on_ac: bool,
/// The energy_performance_preference for this throttle/platform profile
pub throttle_quiet_epp: CPUEPP,
/// The energy_performance_preference for this throttle/platform profile
pub throttle_balanced_epp: CPUEPP,
/// The energy_performance_preference for this throttle/platform profile
pub throttle_performance_epp: CPUEPP,
/// Defaults to `None` if not supported
pub change_platform_profile_on_battery: bool,
/// Which platform profile to use on AC power
pub platform_profile_on_ac: PlatformProfile,
/// Should the platform profile be set on bat/ac change?
pub change_platform_profile_on_ac: bool,
/// The energy_performance_preference for this platform profile
pub profile_quiet_epp: CPUEPP,
/// The energy_performance_preference for this platform profile
pub profile_balanced_epp: CPUEPP,
/// The energy_performance_preference for this platform profile
pub profile_custom_epp: CPUEPP,
/// The energy_performance_preference for this platform profile
pub profile_performance_epp: CPUEPP,
pub ac_profile_tunings: Tunings,
pub dc_profile_tunings: Tunings,
pub armoury_settings: HashMap<FirmwareAttribute, i32>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl1_spl: Option<u8>,
/// Defaults to `None` if not supported
pub screenpad_gamma: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl2_sppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_fppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_apu_sppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_platform_sppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub nv_dynamic_boost: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub nv_temp_target: Option<u8>,
pub screenpad_sync_primary: Option<bool>,
/// Temporary state for AC/Batt
#[serde(skip)]
pub last_power_plugged: u8,
}
impl Config {
pub fn select_tunings(&mut self, power_plugged: bool, profile: PlatformProfile) -> &mut Tuning {
let config = if power_plugged {
&mut self.ac_profile_tunings
} else {
&mut self.dc_profile_tunings
};
config.entry(profile).or_insert_with(Tuning::default)
}
pub fn select_tunings_ref(
&self,
power_plugged: bool,
profile: PlatformProfile,
) -> Option<&Tuning> {
let config = if power_plugged {
&self.ac_profile_tunings
} else {
&self.dc_profile_tunings
};
config.get(&profile)
}
}
impl Default for Config {
fn default() -> Self {
Self {
charge_control_end_threshold: 100,
// NOTE: This is intentionally 100 (not 0 like the serde default).
// New installs get 100 (no limit). Upgraded configs missing this
// field get 0 via serde, which skips restore_charge_limit().
base_charge_control_end_threshold: 100,
panel_od: false,
boot_sound: false,
mini_led_mode: false,
disable_nvidia_powerd_on_battery: true,
ac_command: Default::default(),
bat_command: Default::default(),
throttle_policy_linked_epp: true,
throttle_policy_on_battery: ThrottlePolicy::Quiet,
change_throttle_policy_on_battery: true,
throttle_policy_on_ac: ThrottlePolicy::Performance,
change_throttle_policy_on_ac: true,
throttle_quiet_epp: CPUEPP::Power,
throttle_balanced_epp: CPUEPP::BalancePower,
throttle_performance_epp: CPUEPP::Performance,
ppt_pl1_spl: Default::default(),
ppt_pl2_sppt: Default::default(),
ppt_fppt: Default::default(),
ppt_apu_sppt: Default::default(),
ppt_platform_sppt: Default::default(),
nv_dynamic_boost: Default::default(),
nv_temp_target: Default::default(),
platform_profile_linked_epp: true,
platform_profile_on_battery: PlatformProfile::Quiet,
change_platform_profile_on_battery: true,
platform_profile_on_ac: PlatformProfile::Performance,
change_platform_profile_on_ac: true,
profile_quiet_epp: CPUEPP::Power,
profile_balanced_epp: CPUEPP::BalancePower,
profile_performance_epp: CPUEPP::Performance,
profile_custom_epp: CPUEPP::Performance,
ac_profile_tunings: HashMap::default(),
dc_profile_tunings: HashMap::default(),
armoury_settings: HashMap::default(),
last_power_plugged: Default::default(),
screenpad_gamma: Default::default(),
screenpad_sync_primary: Default::default(),
}
}
}
@@ -99,8 +123,8 @@ impl StdConfig for Config {
Config {
charge_control_end_threshold: 100,
disable_nvidia_powerd_on_battery: true,
throttle_policy_on_battery: ThrottlePolicy::Quiet,
throttle_policy_on_ac: ThrottlePolicy::Performance,
platform_profile_on_battery: PlatformProfile::Quiet,
platform_profile_on_ac: PlatformProfile::Performance,
ac_command: String::new(),
bat_command: String::new(),
..Default::default()
@@ -116,58 +140,128 @@ impl StdConfig for Config {
}
}
impl StdConfigLoad1<Config507> for Config {}
impl StdConfigLoad2<Config611, Config601> for Config {}
#[derive(Deserialize, Serialize)]
pub struct Config507 {
// The current charge limit applied
pub struct Config611 {
pub charge_control_end_threshold: u8,
#[serde(skip)]
pub base_charge_control_end_threshold: u8,
pub disable_nvidia_powerd_on_battery: bool,
pub ac_command: String,
pub bat_command: String,
pub platform_profile_linked_epp: bool,
pub platform_profile_on_battery: PlatformProfile,
pub change_platform_profile_on_battery: bool,
pub platform_profile_on_ac: PlatformProfile,
pub change_platform_profile_on_ac: bool,
pub profile_quiet_epp: CPUEPP,
pub profile_balanced_epp: CPUEPP,
pub profile_custom_epp: CPUEPP,
pub profile_performance_epp: CPUEPP,
pub ac_profile_tunings: Tunings,
pub dc_profile_tunings: Tunings,
pub armoury_settings: HashMap<FirmwareAttribute, i32>,
#[serde(skip)]
pub last_power_plugged: u8,
}
impl From<Config611> for Config {
fn from(c: Config611) -> Self {
let mut config = Self {
// Restore the base charge limit
charge_control_end_threshold: c.charge_control_end_threshold,
base_charge_control_end_threshold: c.charge_control_end_threshold,
disable_nvidia_powerd_on_battery: c.disable_nvidia_powerd_on_battery,
ac_command: c.ac_command,
bat_command: c.bat_command,
platform_profile_linked_epp: c.platform_profile_linked_epp,
platform_profile_on_battery: c.platform_profile_on_battery,
change_platform_profile_on_battery: c.change_platform_profile_on_battery,
platform_profile_on_ac: c.platform_profile_on_ac,
change_platform_profile_on_ac: c.change_platform_profile_on_ac,
profile_quiet_epp: c.profile_quiet_epp,
profile_balanced_epp: c.profile_balanced_epp,
profile_performance_epp: c.profile_performance_epp,
profile_custom_epp: c.profile_performance_epp,
last_power_plugged: c.last_power_plugged,
ac_profile_tunings: HashMap::default(),
dc_profile_tunings: HashMap::default(),
armoury_settings: HashMap::default(),
screenpad_gamma: None,
screenpad_sync_primary: Default::default(),
};
config.ac_profile_tunings = c.ac_profile_tunings;
config.dc_profile_tunings = c.dc_profile_tunings;
config.armoury_settings = c.armoury_settings;
config
}
}
#[derive(Deserialize, Serialize)]
pub struct Config601 {
pub charge_control_end_threshold: u8,
#[serde(skip)]
pub base_charge_control_end_threshold: u8,
pub panel_od: bool,
pub boot_sound: bool,
pub mini_led_mode: bool,
pub disable_nvidia_powerd_on_battery: bool,
pub ac_command: String,
pub bat_command: String,
pub platform_policy_linked_epp: bool,
pub platform_policy_on_battery: ThrottlePolicy,
pub platform_policy_on_ac: ThrottlePolicy,
//
pub platform_profile_linked_epp: bool,
pub platform_profile_on_battery: PlatformProfile,
pub change_platform_profile_on_battery: bool,
pub platform_profile_on_ac: PlatformProfile,
pub change_platform_profile_on_ac: bool,
pub profile_quiet_epp: CPUEPP,
pub profile_balanced_epp: CPUEPP,
pub profile_performance_epp: CPUEPP,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl1_spl: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl2_sppt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl3_fppt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_fppt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_apu_sppt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_platform_sppt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub nv_dynamic_boost: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub nv_temp_target: Option<u8>,
#[serde(skip)]
pub last_power_plugged: u8,
}
impl From<Config507> for Config {
fn from(c: Config507) -> Self {
impl From<Config601> for Config {
fn from(c: Config601) -> Self {
Self {
// Restore the base charge limit
charge_control_end_threshold: c.charge_control_end_threshold,
base_charge_control_end_threshold: c.charge_control_end_threshold,
panel_od: c.panel_od,
boot_sound: false,
disable_nvidia_powerd_on_battery: c.disable_nvidia_powerd_on_battery,
ac_command: c.ac_command,
bat_command: c.bat_command,
mini_led_mode: c.mini_led_mode,
throttle_policy_linked_epp: true,
throttle_policy_on_battery: c.platform_policy_on_battery,
change_throttle_policy_on_battery: true,
throttle_policy_on_ac: c.platform_policy_on_ac,
change_throttle_policy_on_ac: true,
throttle_quiet_epp: CPUEPP::Power,
throttle_balanced_epp: CPUEPP::BalancePower,
throttle_performance_epp: CPUEPP::Performance,
ppt_pl1_spl: c.ppt_pl1_spl,
ppt_pl2_sppt: c.ppt_pl2_sppt,
ppt_fppt: c.ppt_fppt,
ppt_apu_sppt: c.ppt_apu_sppt,
ppt_platform_sppt: c.ppt_platform_sppt,
nv_dynamic_boost: c.nv_dynamic_boost,
nv_temp_target: c.nv_temp_target,
last_power_plugged: 0,
platform_profile_linked_epp: c.platform_profile_linked_epp,
platform_profile_on_battery: c.platform_profile_on_battery,
change_platform_profile_on_battery: c.change_platform_profile_on_battery,
platform_profile_on_ac: c.platform_profile_on_ac,
change_platform_profile_on_ac: c.change_platform_profile_on_ac,
profile_quiet_epp: c.profile_quiet_epp,
profile_balanced_epp: c.profile_balanced_epp,
profile_performance_epp: c.profile_performance_epp,
profile_custom_epp: c.profile_performance_epp,
last_power_plugged: c.last_power_plugged,
ac_profile_tunings: HashMap::default(),
dc_profile_tunings: HashMap::default(),
armoury_settings: HashMap::default(),
screenpad_gamma: None,
screenpad_sync_primary: Default::default(),
}
}
}

348
asusd/src/ctrl_backlight.rs Normal file
View File

@@ -0,0 +1,348 @@
use std::sync::Arc;
use std::time::Duration;
use config_traits::StdConfig;
use log::{info, warn};
use rog_platform::backlight::{Backlight, BacklightType};
use tokio::sync::Mutex;
use zbus::fdo::Error as FdoErr;
use zbus::object_server::SignalEmitter;
use zbus::{interface, Connection};
use crate::config::Config;
use crate::error::RogError;
use crate::ASUS_ZBUS_PATH;
#[derive(Clone)]
pub struct CtrlBacklight {
backlights: Vec<Backlight>,
config: Arc<Mutex<Config>>,
}
impl CtrlBacklight {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
let mut backlights = Vec::new();
if let Ok(primary) = Backlight::new(BacklightType::Primary) {
info!("Found primary display backlight");
backlights.push(primary);
}
if let Ok(screenpad) = Backlight::new(BacklightType::Screenpad) {
info!("Found screenpad backlight");
backlights.push(screenpad);
}
if backlights.is_empty() {
return Err(RogError::MissingFunction("No backlights found".into()));
}
Ok(Self { backlights, config })
}
fn get_backlight(&self, device_type: &BacklightType) -> Option<&Backlight> {
self.backlights
.iter()
.find(|b| b.device_type() == device_type)
}
async fn set_brightness_with_sync(
&self,
device_type: &BacklightType,
level: i32,
) -> Result<(), FdoErr> {
let sync = self
.config
.lock()
.await
.screenpad_sync_primary
.unwrap_or_default();
// If sync is enabled and we're setting screenpad brightness, set primary first
if sync && *device_type == BacklightType::Screenpad {
if let Some(primary) = self.get_backlight(&BacklightType::Primary) {
if let Ok(primary_max) = primary.get_max_brightness() {
let primary_scaled = level * primary_max / 100;
let _ = primary.set_brightness(primary_scaled);
}
}
}
if let Some(backlight) = self.get_backlight(device_type) {
let max = backlight.get_max_brightness().map_err(|e| {
warn!("Failed to get max brightness: {}", e);
FdoErr::Failed(format!("Failed to get max brightness: {}", e))
})?;
let gamma = self.config.lock().await.screenpad_gamma.unwrap_or(1.0);
let scaled = if *device_type == BacklightType::Screenpad {
// Apply non-linear scaling with the configurable gamma value only for Screenpad
let normalized_level = level as f32 / 100.0;
let gamma_corrected = normalized_level.powf(gamma);
(gamma_corrected * max as f32) as i32
} else {
// Linear scaling for other devices
level * max / 100
};
backlight.set_brightness(scaled).map_err(|e| {
warn!("Failed to set brightness: {}", e);
FdoErr::Failed(format!("Failed to set brightness: {}", e))
})?;
// If sync is enabled and we're setting primary brightness, set screenpad
// afterward
if sync && *device_type == BacklightType::Primary {
for other in self
.backlights
.iter()
.filter(|b| b.device_type() != device_type)
{
if let Ok(other_max) = other.get_max_brightness() {
let other_scaled = if other.device_type() == &BacklightType::Screenpad {
// Apply gamma only to Screenpad
let normalized_level = level as f32 / 100.0;
let gamma_corrected = normalized_level.powf(gamma);
(gamma_corrected * other_max as f32) as i32
} else {
// Linear scaling for other devices
level * other_max / 100
};
let _ = other.set_brightness(other_scaled);
}
}
}
Ok(())
} else {
Err(FdoErr::NotSupported(format!(
"Backlight {:?} not found",
device_type
)))
}
}
async fn get_brightness_percent(&self, device_type: &BacklightType) -> Result<i32, FdoErr> {
if let Some(backlight) = self.get_backlight(device_type) {
let brightness = backlight.get_brightness().map_err(|e| {
warn!("Failed to get brightness: {}", e);
FdoErr::Failed(format!("Failed to get brightness: {}", e))
})?;
let max = backlight.get_max_brightness().map_err(|e| {
warn!("Failed to get max brightness: {}", e);
FdoErr::Failed(format!("Failed to get max brightness: {}", e))
})?;
if *device_type == BacklightType::Screenpad {
let gamma = self.config.lock().await.screenpad_gamma.unwrap_or(1.0);
let normalized = brightness as f32 / max as f32;
let corrected = normalized.powf(1.0 / gamma);
Ok((corrected * 100.0).round() as i32)
} else {
Ok(brightness * 100 / max)
}
} else {
Err(FdoErr::NotSupported(format!(
"Backlight {:?} not found",
device_type
)))
}
}
pub async fn start_watch_primary(&self) -> Result<(), RogError> {
if self.get_backlight(&BacklightType::Screenpad).is_none() {
return Ok(());
}
if let Some(sync) = self.config.lock().await.screenpad_sync_primary {
if !sync {
return Ok(());
}
}
if let Some(backlight) = self.get_backlight(&BacklightType::Primary) {
let watch = backlight.monitor_brightness()?;
let backlights = self.clone();
tokio::spawn(async move {
let mut last_level = 0;
let mut buffer = [0; 32];
use futures_lite::StreamExt;
if let Ok(mut stream) = watch.into_event_stream(&mut buffer) {
loop {
let _ = stream.next().await;
let sync = backlights.config.lock().await.screenpad_sync_primary;
if let Some(sync) = sync {
if !sync {
continue;
}
} else if backlights
.config
.lock()
.await
.screenpad_sync_primary
.is_none()
{
continue;
}
let level = backlights
.get_brightness_percent(&BacklightType::Primary)
.await
.unwrap_or(60);
if last_level != level {
last_level = level;
backlights
.set_brightness_with_sync(&BacklightType::Screenpad, level)
.await
.ok();
}
// other processes cause "MODIFY" event and make this spin 100%, so sleep
tokio::time::sleep(Duration::from_millis(300)).await;
}
// watch
// .into_event_stream(&mut buffer)
// .unwrap()
// .for_each(|_| async {})
// .await;
}
});
}
Ok(())
}
}
#[interface(name = "xyz.ljones.Backlight")]
impl CtrlBacklight {
#[zbus(property)]
async fn screenpad_sync_with_primary(&self) -> bool {
self.config
.lock()
.await
.screenpad_sync_primary
.unwrap_or_default()
}
#[zbus(property)]
async fn set_screenpad_sync_with_primary(&self, sync: bool) -> Result<(), zbus::Error> {
self.config.lock().await.screenpad_sync_primary = Some(sync);
self.config.lock().await.write();
Ok(())
}
#[zbus(property)]
async fn screenpad_gamma(&self) -> String {
(self.config.lock().await.screenpad_gamma.unwrap_or(1.0)).to_string()
}
#[zbus(property)]
async fn set_screenpad_gamma(&self, value: &str) -> Result<(), zbus::Error> {
let gamma: f32 = value
.parse()
.map_err(|_| FdoErr::Failed("Invalid gamma value, must be a valid number".into()))?;
if gamma < 0.1 {
return Err(FdoErr::Failed("Gamma value must be greater than 0".into()).into());
}
if gamma > 2.0 {
return Err(FdoErr::Failed("Gamma value must be 2.0 or less".into()).into());
}
self.config.lock().await.screenpad_gamma = Some(gamma);
self.config.lock().await.write();
Ok(())
}
#[zbus(property)]
async fn primary_brightness(&self) -> Result<i32, FdoErr> {
self.get_brightness_percent(&BacklightType::Primary).await
}
#[zbus(property)]
async fn set_primary_brightness(
&self,
#[zbus(signal_context)] ctxt: SignalEmitter<'_>,
level: i32,
) -> Result<(), zbus::Error> {
if level > 100 {
return Err(FdoErr::Failed("Brightness level must be 0-100".into()).into());
}
self.set_brightness_with_sync(&BacklightType::Primary, level)
.await?;
self.primary_brightness_changed(&ctxt).await?;
Ok(())
}
#[zbus(property)]
async fn screenpad_brightness(&self) -> Result<i32, FdoErr> {
self.get_brightness_percent(&BacklightType::Screenpad).await
}
#[zbus(property)]
async fn set_screenpad_brightness(
&self,
// #[zbus(signal_context)] ctxt: SignalEmitter<'_>,
level: i32,
) -> Result<(), zbus::Error> {
if level > 100 {
return Err(FdoErr::Failed("Brightness level must be 0-100".into()).into());
}
self.set_brightness_with_sync(&BacklightType::Screenpad, level)
.await?;
// self.screenpad_brightness_changed(&ctxt).await?;
Ok(())
}
#[zbus(property)]
async fn screenpad_power(&self) -> Result<bool, FdoErr> {
if let Some(backlight) = self.get_backlight(&BacklightType::Screenpad) {
let power = backlight.get_bl_power().map_err(|e| {
warn!("Failed to get backlight power: {}", e);
FdoErr::Failed(format!("Failed to get backlight power: {}", e))
})?;
Ok(power == 0)
} else {
Err(FdoErr::NotSupported("Screenpad backlight not found".into()))
}
}
#[zbus(property)]
async fn set_screenpad_power(
&self,
#[zbus(signal_context)] ctxt: SignalEmitter<'_>,
power: bool,
) -> Result<(), zbus::Error> {
if let Some(backlight) = self.get_backlight(&BacklightType::Screenpad) {
backlight
.set_bl_power(if power { 0 } else { 1 })
.map_err(|e| {
warn!("Failed to set backlight power: {}", e);
FdoErr::Failed(format!("Failed to set backlight power: {}", e))
})?;
self.screenpad_power_changed(&ctxt).await?;
Ok(())
} else {
Err(FdoErr::NotSupported("Screenpad backlight not found".into()).into())
}
}
}
impl crate::ZbusRun for CtrlBacklight {
async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, ASUS_ZBUS_PATH, server).await;
}
}
impl crate::Reloadable for CtrlBacklight {
async fn reload(&mut self) -> Result<(), RogError> {
info!("Reloading backlight settings");
Ok(())
}
}

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use config_traits::{StdConfig, StdConfigLoad};
use futures_lite::StreamExt;
use log::{debug, error, info, warn};
use rog_platform::platform::{RogPlatform, ThrottlePolicy};
use rog_platform::platform::{PlatformProfile, RogPlatform};
use rog_profiles::error::ProfileError;
use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::{find_fan_curve_node, FanCurvePU, FanCurveProfiles};
@@ -17,13 +17,13 @@ use crate::error::RogError;
use crate::{CtrlTask, CONFIG_PATH_BASE};
pub const FAN_CURVE_ZBUS_NAME: &str = "FanCurves";
pub const FAN_CURVE_ZBUS_PATH: &str = "/org/asuslinux";
pub const FAN_CURVE_ZBUS_PATH: &str = "/xyz/ljones";
#[derive(Deserialize, Serialize, Debug, Default)]
pub struct FanCurveConfig {
pub profiles: FanCurveProfiles,
#[serde(skip)]
pub current: u8,
pub current: PlatformProfile,
}
impl StdConfig for FanCurveConfig {
@@ -54,7 +54,7 @@ pub struct CtrlFanCurveZbus {
impl CtrlFanCurveZbus {
pub fn new() -> Result<Self, RogError> {
let platform = RogPlatform::new()?;
if platform.has_throttle_thermal_policy() {
if platform.has_platform_profile() {
info!("Device has profile control available");
find_fan_curve_node()?;
info!("Device has fan curves available");
@@ -65,16 +65,13 @@ impl CtrlFanCurveZbus {
if config.profiles.balanced.is_empty() || !config.file_path().exists() {
info!("Fetching default fan curves");
let current = platform.get_throttle_thermal_policy()?;
for this in [
ThrottlePolicy::Balanced,
ThrottlePolicy::Performance,
ThrottlePolicy::Quiet,
] {
let current = platform.get_platform_profile()?;
let profiles = platform.get_platform_profile_choices()?;
for this in profiles {
// 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.
platform.set_throttle_thermal_policy(this.into())?;
platform.set_platform_profile(this.into())?;
let mut dev = find_fan_curve_node()?;
fan_curves.set_active_curve_to_defaults(this, &mut dev)?;
@@ -83,7 +80,7 @@ impl CtrlFanCurveZbus {
info!("{}", String::from(curve));
}
}
platform.set_throttle_thermal_policy(current)?;
platform.set_platform_profile(current.as_str())?;
config.profiles = fan_curves;
config.write();
} else {
@@ -101,13 +98,13 @@ impl CtrlFanCurveZbus {
}
}
#[interface(name = "org.asuslinux.FanCurves")]
#[interface(name = "xyz.ljones.FanCurves")]
impl CtrlFanCurveZbus {
/// Set all fan curves for a profile to enabled status. Will also activate a
/// fan curve if in the same profile mode
async fn set_fan_curves_enabled(
&mut self,
profile: ThrottlePolicy,
profile: PlatformProfile,
enabled: bool,
) -> zbus::fdo::Result<()> {
self.config
@@ -128,7 +125,7 @@ impl CtrlFanCurveZbus {
/// activate a fan curve if in the same profile mode
async fn set_profile_fan_curve_enabled(
&mut self,
profile: ThrottlePolicy,
profile: PlatformProfile,
fan: FanCurvePU,
enabled: bool,
) -> zbus::fdo::Result<()> {
@@ -149,7 +146,7 @@ impl CtrlFanCurveZbus {
/// Get the fan-curve data for the currently active ThrottlePolicy
async fn fan_curve_data(
&mut self,
profile: ThrottlePolicy,
profile: PlatformProfile,
) -> zbus::fdo::Result<Vec<CurveData>> {
let curve = self
.config
@@ -165,7 +162,7 @@ impl CtrlFanCurveZbus {
/// Will also activate the fan curve if the user is in the same mode.
async fn set_fan_curve(
&mut self,
profile: ThrottlePolicy,
profile: PlatformProfile,
curve: CurveData,
) -> zbus::fdo::Result<()> {
self.config
@@ -173,7 +170,7 @@ impl CtrlFanCurveZbus {
.await
.profiles
.save_fan_curve(curve, profile)?;
let active: ThrottlePolicy = self.platform.get_throttle_thermal_policy()?.into();
let active: PlatformProfile = self.platform.get_platform_profile()?.into();
if active == profile {
self.config
.lock()
@@ -190,15 +187,15 @@ impl CtrlFanCurveZbus {
///
/// Each platform_profile has a different default and the default can be
/// read only for the currently active profile.
async fn set_curves_to_defaults(&mut self, profile: ThrottlePolicy) -> zbus::fdo::Result<()> {
let active = self.platform.get_throttle_thermal_policy()?;
self.platform.set_throttle_thermal_policy(profile.into())?;
async fn set_curves_to_defaults(&mut self, profile: PlatformProfile) -> zbus::fdo::Result<()> {
let active = self.platform.get_platform_profile()?;
self.platform.set_platform_profile(profile.into())?;
self.config
.lock()
.await
.profiles
.set_active_curve_to_defaults(profile, &mut find_fan_curve_node()?)?;
self.platform.set_throttle_thermal_policy(active)?;
self.platform.set_platform_profile(active.as_str())?;
self.config.lock().await.write();
Ok(())
}
@@ -208,16 +205,16 @@ impl CtrlFanCurveZbus {
///
/// 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: ThrottlePolicy) -> zbus::fdo::Result<()> {
let active = self.platform.get_throttle_thermal_policy()?;
async fn reset_profile_curves(&self, profile: PlatformProfile) -> zbus::fdo::Result<()> {
let active = self.platform.get_platform_profile()?;
self.platform.set_throttle_thermal_policy(profile.into())?;
self.platform.set_platform_profile(profile.into())?;
self.config
.lock()
.await
.profiles
.set_active_curve_to_defaults(active.into(), &mut find_fan_curve_node()?)?;
self.platform.set_throttle_thermal_policy(active)?;
.set_active_curve_to_defaults(active.as_str().into(), &mut find_fan_curve_node()?)?;
self.platform.set_platform_profile(active.as_str())?;
self.config.lock().await.write();
Ok(())
@@ -236,26 +233,31 @@ impl CtrlTask for CtrlFanCurveZbus {
}
async fn create_tasks(&self, _signal_ctxt: SignalEmitter<'static>) -> Result<(), RogError> {
let watch_throttle_thermal_policy = self.platform.monitor_throttle_thermal_policy()?;
let watch_platform_profile = self.platform.monitor_platform_profile()?;
let platform = self.platform.clone();
let config = self.config.clone();
let fan_curves = self.config.clone();
tokio::spawn(async move {
let mut buffer = [0; 32];
if let Ok(mut stream) = watch_throttle_thermal_policy.into_event_stream(&mut buffer) {
if let Ok(mut stream) = watch_platform_profile.into_event_stream(&mut buffer) {
while (stream.next().await).is_some() {
debug!("watch_throttle_thermal_policy changed");
if let Ok(profile) = platform.get_throttle_thermal_policy().map_err(|e| {
error!("get_throttle_thermal_policy error: {e}");
}) {
debug!("watch_platform_profile changed");
if let Ok(profile) =
platform
.get_platform_profile()
.map(|p| p.into())
.map_err(|e| {
error!("get_platform_profile error: {e}");
})
{
if profile != config.lock().await.current {
fan_curves
.lock()
.await
.profiles
.write_profile_curve_to_platform(
profile.into(),
profile,
&mut find_fan_curve_node().unwrap(),
)
.map_err(|e| warn!("write_profile_curve_to_platform, {}", e))
@@ -274,7 +276,7 @@ impl CtrlTask for CtrlFanCurveZbus {
impl crate::Reloadable for CtrlFanCurveZbus {
/// Fetch the active profile and use that to set all related components up
async fn reload(&mut self) -> Result<(), RogError> {
let active = self.platform.get_throttle_thermal_policy()?.into();
let active = self.platform.get_platform_profile()?.into();
let mut config = self.config.lock().await;
if let Ok(mut device) = find_fan_curve_node() {
config

File diff suppressed because it is too large Load Diff

View File

@@ -2,19 +2,26 @@ use std::env;
use std::error::Error;
use std::sync::Arc;
use ::zbus::export::futures_util::lock::Mutex;
use ::zbus::Connection;
use asusd::asus_armoury::{start_attributes_zbus, ArmouryAttributeRegistry};
use asusd::aura_manager::DeviceManager;
use asusd::config::Config;
use asusd::ctrl_backlight::CtrlBacklight;
use asusd::ctrl_fancurves::CtrlFanCurveZbus;
use asusd::ctrl_platform::CtrlPlatform;
use asusd::{print_board_info, start_tasks, CtrlTask, DBUS_NAME};
use config_traits::{StdConfig, StdConfigLoad1};
use asusd::{print_board_info, start_tasks, CtrlTask, ZbusRun, DBUS_NAME};
use config_traits::{StdConfig, StdConfigLoad2};
use log::{error, info};
use rog_platform::asus_armoury::FirmwareAttributes;
use rog_platform::platform::RogPlatform;
use rog_platform::power::AsusPower;
use tokio::sync::Mutex;
use zbus::fdo::ObjectManager;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Starting asusd daemon...");
// console_subscriber::init();
let mut logger = env_logger::Builder::new();
logger
@@ -56,50 +63,93 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
// println!("{:?}", supported.supported_functions());
// Start zbus server
let mut connection = Connection::system().await?;
connection
.object_server()
.at("/", ObjectManager)
.await
.unwrap();
let mut server = Connection::system().await?;
if let Err(e) = server.object_server().at("/", ObjectManager).await {
error!("Failed to register ObjectManager at root '/': {e:?}");
}
let config = Config::new().load();
let cfg_path = config.file_path();
let config = Arc::new(Mutex::new(config));
// supported.add_to_server(&mut connection).await;
let platform = RogPlatform::new()?; // TODO: maybe needs async mutex?
let power = AsusPower::new()?; // TODO: maybe needs async mutex?
let attributes = FirmwareAttributes::new();
let armoury_registry = match start_attributes_zbus(
&server,
platform.clone(),
power.clone(),
attributes.clone(),
config.clone(),
)
.await
{
Ok(registry) => {
info!("attribute on zbus initialized");
registry
}
Err(e) => {
error!("Failed to initialize firmware attributes over zbus: {e:?}");
ArmouryAttributeRegistry::default()
}
};
match CtrlFanCurveZbus::new() {
Ok(ctrl) => {
let sig_ctx = CtrlFanCurveZbus::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
info!("FanCurves: found supported fancurves");
let sig_ctx = CtrlFanCurveZbus::signal_context(&server)?;
start_tasks(ctrl, &mut server, sig_ctx).await?;
info!("FanCurves: initialized");
}
Err(err) => {
error!("FanCurves: {}", err);
}
}
match CtrlBacklight::new(config.clone()) {
Ok(backlight) => {
info!("Backlight: found supported backlight");
backlight.start_watch_primary().await?;
backlight.add_to_server(&mut server).await;
info!("Backlight: initialized");
}
Err(err) => {
error!("Backlight: {}", err);
}
}
match CtrlPlatform::new(
platform,
power,
attributes,
config.clone(),
&cfg_path,
CtrlPlatform::signal_context(&connection)?,
CtrlPlatform::signal_context(&server)?,
server.clone(),
armoury_registry,
) {
Ok(ctrl) => {
let sig_ctx = CtrlPlatform::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
info!("CtrlPlatform: initialized");
let sig_ctx = CtrlPlatform::signal_context(&server)?;
start_tasks(ctrl, &mut server, sig_ctx).await?;
info!("CtrlPlatform: tasks started");
}
Err(err) => {
error!("CtrlPlatform: {}", err);
}
}
let _ = DeviceManager::new(connection.clone()).await?;
let _ = DeviceManager::new(server.clone()).await?;
info!("DeviceManager initialized");
// Request dbus name after finishing initalizing all functions
connection.request_name(DBUS_NAME).await?;
server.request_name(DBUS_NAME).await?;
info!("Startup success on dbus name {DBUS_NAME}: begining dbus server loop");
loop {
// This is just a blocker to idle and ensure the reator reacts
connection.executor().tick().await;
server.executor().tick().await;
}
}

View File

@@ -142,3 +142,10 @@ impl From<RogError> for zbus::fdo::Error {
zbus::fdo::Error::Failed(format!("{}", err))
}
}
impl From<RogError> for zbus::Error {
#[inline]
fn from(err: RogError) -> Self {
zbus::Error::Failure(format!("{}", err))
}
}

View File

@@ -1,11 +1,13 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub mod ctrl_backlight;
/// Control platform profiles + fan-curves if available
pub mod ctrl_fancurves;
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
pub mod ctrl_platform;
pub mod asus_armoury;
pub mod aura_anime;
pub mod aura_laptop;
pub mod aura_manager;
@@ -30,9 +32,11 @@ use zbus::Connection;
use crate::error::RogError;
const CONFIG_PATH_BASE: &str = "/etc/asusd/";
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
pub const ASUS_ZBUS_PATH: &str = "/xyz/ljones";
pub static DBUS_NAME: &str = "xyz.ljones.Asusd";
pub static DBUS_PATH: &str = "/xyz/ljones/Daemon";
pub static DBUS_IFACE: &str = "xyz.ljones.Asusd";
/// This macro adds a function which spawns an `inotify` task on the passed in
/// `Executor`.
@@ -64,7 +68,7 @@ macro_rules! task_watch_item {
&self,
signal_ctxt: SignalEmitter<'static>,
) -> Result<(), RogError> {
use zbus::export::futures_util::StreamExt;
use futures_util::StreamExt;
let ctrl = self.clone();
concat_idents::concat_idents!(watch_fn = monitor_, $name {
@@ -104,7 +108,7 @@ macro_rules! task_watch_item_notify {
&self,
signal_ctxt: SignalEmitter<'static>,
) -> Result<(), RogError> {
use zbus::export::futures_util::StreamExt;
use futures_util::StreamExt;
let ctrl = self.clone();
concat_idents::concat_idents!(watch_fn = monitor_, $name {

View File

@@ -203,7 +203,7 @@ macro_rules! std_config_load {
/// new one created
pub trait $trait_name<$($generic),*>
where
Self: $crate::StdConfig +std::fmt::Debug + DeserializeOwned + Serialize,
Self: $crate::StdConfig + DeserializeOwned + Serialize,
$($generic: DeserializeOwned + Into<Self>),*
{
fn load(mut self) -> Self {

View File

@@ -1,11 +0,0 @@
[package]
name = "cpuctl"
license.workspace = true
version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies]

View File

@@ -1,14 +0,0 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View File

@@ -3,24 +3,24 @@
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy group="adm">
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
<allow send_destination="xyz.ljones.Asusd"/>
<allow receive_sender="xyz.ljones.Asusd"/>
</policy>
<policy group="sudo">
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
<allow send_destination="xyz.ljones.Asusd"/>
<allow receive_sender="xyz.ljones.Asusd"/>
</policy>
<policy group="users">
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
<allow send_destination="xyz.ljones.Asusd"/>
<allow receive_sender="xyz.ljones.Asusd"/>
</policy>
<policy group="wheel">
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
<allow send_destination="xyz.ljones.Asusd"/>
<allow receive_sender="xyz.ljones.Asusd"/>
</policy>
<policy user="root">
<allow own="org.asuslinux.Daemon"/>
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
<allow own="xyz.ljones.Asusd"/>
<allow send_destination="xyz.ljones.Asusd"/>
<allow receive_sender="xyz.ljones.Asusd"/>
</policy>
</busconfig>

View File

@@ -9,11 +9,14 @@ ENV{DMI_FAMILY}=="*Strix*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*Vivo*ook*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*Zenbook*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*ProArt*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*TX Air*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*TX Gaming*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*EXPERTBOOK*", GOTO="asusd_start"
# No match so
GOTO="asusd_end"
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"
ACTION=="add|change", DRIVER=="asus-nb-wmi", TAG+="systemd", ENV{SYSTEMD_WANTS}+="asusd.service"
ACTION=="add|remove", DRIVER=="asus-nb-wmi", TAG+="systemd", ENV{SYSTEMD_WANTS}+="asusd.service"
LABEL="asusd_end"

View File

@@ -6,13 +6,17 @@ After=nvidia-powerd.service systemd-udevd.service
[Service]
Environment=IS_SERVICE=1
Environment=RUST_LOG="info"
# Reduce noisy span logs while keeping useful debug info for asusd and related crates.
# Keep global level at info but allow debug for our crates; silence tracing::span (very noisy)
# RUST_LOG format: <module>=<level>,... (levels: error,warn,info,debug,trace)
Environment=RUST_LOG="info,asusd=debug,rog_platform=debug,tracing::span=error,zbus::object_server=error,zbus::connection::handshake::common=error,zbus::connection::handshake::client=error"
# required to prevent init issues with hid_asus and MCU
ExecStartPre=/bin/sleep 1
ExecStart=/usr/bin/asusd
Restart=on-failure
RestartSec=1
Type=dbus
BusName=org.asuslinux.Daemon
BusName=xyz.ljones.Asusd
SELinuxContext=system_u:system_r:unconfined_t:s0
#SELinuxContext=system_u:object_r:modules_object_t:s0
TimeoutSec=10

View File

@@ -135,7 +135,7 @@ impl crate::ZbusAdd for CtrlAnimeZbus {
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
#[dbus_interface(name = "xyz.ljones.Asusd")]
impl CtrlAnimeZbus {
async fn <zbus method>() {
let lock = self.inner.lock().await;

130
distro-packaging/asusctl.spec Executable file → Normal file
View File

@@ -1,7 +1,7 @@
#
# spec file for package asus-nb-ctrl
#
# Copyright (c) 2020-2021 Luke Jones <luke@ljones.dev>
# Copyright (c) 2020-2025 Luke Jones <luke@ljones.dev>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -20,42 +20,44 @@
%global debug_package %{nil}
%endif
%define version 6.3.1
%define specrelease %{?dist}
%define pkg_release 3%{specrelease}
%define pkg_release 1%{specrelease}
# Use hardening ldflags.
%global rustflags -Clink-arg=-Wl,-z,relro,-z,now
Name: asusctl
Version: 6.0.7
Name: asusctl
Version: %{version}
Release: %{pkg_release}
Summary: Control fan speeds, LEDs, graphics modes, and charge levels for ASUS notebooks
License: MPLv2
Summary: Control fan speeds, LEDs, graphics modes, and charge levels for ASUS notebooks
License: MPLv2
Group: System Environment/Kernel
Group: System Environment/Kernel
URL: https://gitlab.com/asus-linux/asusctl
Source: %{name}-%{version}.tar.gz
Source1: vendor_%{name}_%{version}.tar.xz
Source2: cargo-config
URL: https://gitlab.com/asus-linux/asusctl
Source: https://gitlab.com/asus-linux/asusctl/-/archive/%{version}/%{name}-%{version}.tar.gz
BuildRequires: cargo
%if %{defined fedora}
BuildRequires: rust-packaging
BuildRequires: systemd-rpm-macros
%else
BuildRequires: cargo-packaging
%endif
BuildRequires: git
BuildRequires: clang-devel
BuildRequires: cargo
BuildRequires: cmake
BuildRequires: rust
BuildRequires: rust-std-static
BuildRequires: pkgconfig(expat)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(gbm)
BuildRequires: pkgconfig(libinput)
BuildRequires: pkgconfig(libseat)
BuildRequires: pkgconfig(libudev)
BuildRequires: pkgconfig(xkbcommon)
BuildRequires: pkgconfig(libzstd)
BuildRequires: pkgconfig(gtk+-3.0)
BuildRequires: pkgconfig(gdk-3.0)
BuildRequires: pkgconfig(fontconfig)
BuildRequires: desktop-file-utils
# expat-devel pcre2-devel
%description
asus-nb-ctrl 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.
@@ -66,38 +68,93 @@ asus-nb-ctrl enables third-party apps to use the above with dbus methods.
%package rog-gui
Summary: An experimental GUI for %{name}
Requires: %{name} = %{version}-%{release}
%description rog-gui
A one-stop-shop GUI tool for asusd/asusctl. It aims to provide most controls,
a notification service, and ability to run in the background.
%prep
# %setup -D -T -a 1 -c -n %{name}-%{version}/vendor
# %setup -D -T -a 0 -c
%autosetup
%setup -D -T -a 1
mv Cargo.lock{,.bak}
%cargo_prep
mv Cargo.lock{.bak,}
sed -i 's|replace-with = "local-registry"|replace-with = "vendored-sources"|' .cargo/config
cat %{SOURCE2} >> .cargo/config
mkdir -p .cargo
cat > .cargo/config.toml << 'EOF'
[term]
verbose = true
[net]
offline = false
EOF
%build
export RUSTFLAGS="%{rustflags}"
%cargo_build
#cargo build --release --frozen --offline --config .cargo/config.toml
%if %{defined fedora}
/usr/bin/cargo build --release --locked
%else
/usr/bin/cargo auditable build --release --locked
%endif
%install
export RUSTFLAGS="%{rustflags}"
mkdir -p "%{buildroot}/%{_bindir}" "%{buildroot}%{_docdir}"
%make_install
install -D -m 0644 README.md %{buildroot}/%{_docdir}/%{name}/README.md
install -D -m 0644 rog-anime/README.md %{buildroot}/%{_docdir}/%{name}/README-anime.md
install -D -m 0644 rog-anime/data/diagonal-template.png %{buildroot}/%{_docdir}/%{name}/diagonal-template.png
%define _target_dir target/release
desktop-file-validate %{buildroot}/%{_datadir}/applications/rog-control-center.desktop
# Install binaries
install -D -m 0755 %{_target_dir}/asusd %{buildroot}%{_bindir}/asusd
install -D -m 0755 %{_target_dir}/asusd-user %{buildroot}%{_bindir}/asusd-user
install -D -m 0755 %{_target_dir}/asusctl %{buildroot}%{_bindir}/asusctl
install -D -m 0755 %{_target_dir}/rog-control-center %{buildroot}%{_bindir}/rog-control-center
# Install systemd units
install -D -m 0644 data/asusd.service %{buildroot}%{_unitdir}/asusd.service
install -D -m 0644 data/asusd-user.service %{buildroot}%{_userunitdir}/asusd-user.service
# Install udev rules
install -D -m 0644 data/asusd.rules %{buildroot}%{_udevrulesdir}/99-asusd.rules
# Install dbus config
install -D -m 0644 data/asusd.conf %{buildroot}%{_datadir}/dbus-1/system.d/asusd.conf
# Install asusd data
install -D -m 0644 rog-aura/data/aura_support.ron %{buildroot}%{_datadir}/asusd/aura_support.ron
cp -r rog-anime/data/anime %{buildroot}%{_datadir}/asusd/
# Install rog-gui data
install -D -m 0644 rog-control-center/data/rog-control-center.desktop %{buildroot}%{_datadir}/applications/rog-control-center.desktop
install -D -m 0644 rog-control-center/data/rog-control-center.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/rog-control-center.png
mkdir -p %{buildroot}%{_datadir}/rog-gui/layouts
cp -r rog-aura/data/layouts/*.ron %{buildroot}%{_datadir}/rog-gui/layouts/
# Install icons
install -D -m 0644 data/icons/asus_notif_yellow.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_yellow.png
install -D -m 0644 data/icons/asus_notif_green.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_green.png
install -D -m 0644 data/icons/asus_notif_blue.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_blue.png
install -D -m 0644 data/icons/asus_notif_red.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_red.png
install -D -m 0644 data/icons/asus_notif_orange.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_orange.png
install -D -m 0644 data/icons/asus_notif_white.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_white.png
install -D -m 0644 data/icons/scalable/gpu-compute.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-compute.svg
install -D -m 0644 data/icons/scalable/gpu-hybrid.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-hybrid.svg
install -D -m 0644 data/icons/scalable/gpu-integrated.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-integrated.svg
install -D -m 0644 data/icons/scalable/gpu-nvidia.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-nvidia.svg
install -D -m 0644 data/icons/scalable/gpu-vfio.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-vfio.svg
install -D -m 0644 data/icons/scalable/notification-reboot.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/notification-reboot.svg
# Install docs
install -D -m 0644 README.md %{buildroot}%{_docdir}/%{name}/README.md
install -D -m 0644 rog-anime/README.md %{buildroot}%{_docdir}/%{name}/README-anime.md
install -D -m 0644 rog-anime/data/diagonal-template.png %{buildroot}%{_docdir}/%{name}/diagonal-template.png
# Install LICENSE to asusctl datadir
install -D -m 0644 LICENSE %{buildroot}%{_datadir}/asusctl/LICENSE
desktop-file-validate %{buildroot}%{_datadir}/applications/rog-control-center.desktop
%post
%systemd_post asusd.service
%preun
%systemd_preun asusd.service
%postun
%systemd_postun_with_restart asusd.service
%files
%license LICENSE
@@ -107,8 +164,6 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/rog-control-center.d
%{_unitdir}/asusd.service
%{_userunitdir}/asusd-user.service
%{_udevrulesdir}/99-asusd.rules
#%dir %{_sysconfdir}/asusd/
%{_datadir}/asusd/aura_support.ron
%{_datadir}/dbus-1/system.d/asusd.conf
%{_datadir}/icons/hicolor/512x512/apps/asus_notif_yellow.png
%{_datadir}/icons/hicolor/512x512/apps/asus_notif_green.png
@@ -123,6 +178,7 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/rog-control-center.d
%{_datadir}/icons/hicolor/scalable/status/gpu-vfio.svg
%{_datadir}/icons/hicolor/scalable/status/notification-reboot.svg
%{_docdir}/%{name}/
%{_datadir}/asusctl/
%{_datadir}/asusd/
%files rog-gui

23
extra/index.html Normal file
View File

@@ -0,0 +1,23 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>asusctl docs</title>
<!-- Redirect to the generated crate docs -->
<meta http-equiv="refresh" content="0;url=asusctl/index.html">
<link rel="canonical" href="asusctl/index.html">
<style>
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; color:#222; display:flex; align-items:center; justify-content:center; height:100vh; margin:0 }
.box { text-align:center }
a { color: #0366d6 }
</style>
</head>
<body>
<div class="box">
<h1>asusctl documentation</h1>
<p>Redirecting to the generated docs — if your browser doesn't redirect automatically, <a href="asusctl/index.html">click here</a>.</p>
<p>If you expected a different landing page, update <code>extra/index.html</code> accordingly.</p>
</div>
</body>
</html>

View File

@@ -30,7 +30,6 @@ log.workspace = true
serde.workspace = true
glam.workspace = true
typeshare.workspace = true
zbus = { workspace = true, optional = true }

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

View File

@@ -6,7 +6,6 @@ use std::time::{Duration, Instant};
use dmi_id::DMIID;
use log::info;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[cfg(feature = "dbus")]
use zbus::zvariant::{OwnedValue, Type, Value};
@@ -23,15 +22,19 @@ const BLOCK_END: usize = 634;
const PANE_LEN: usize = BLOCK_END - BLOCK_START;
/// First packet is for GA401 + GA402
pub const USB_PREFIX1: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const USB_PREFIX1: [u8; 7] = [
0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02,
];
/// Second packet is for GA401 + GA402
pub const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
pub const USB_PREFIX2: [u8; 7] = [
0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02,
];
/// Third packet is for GA402 matrix
pub const USB_PREFIX3: [u8; 7] = [0x5e, 0xc0, 0x02, 0xe7, 0x04, 0x73, 0x02];
pub const USB_PREFIX3: [u8; 7] = [
0x5e, 0xc0, 0x02, 0xe7, 0x04, 0x73, 0x02,
];
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[typeshare]
#[derive(Default, Deserialize, PartialEq, Eq, Clone, Copy, Serialize, Debug)]
pub struct Animations {
pub boot: AnimBooting,
@@ -41,9 +44,7 @@ pub struct Animations {
}
// TODO: move this out
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type))]
#[typeshare]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub struct DeviceState {
pub display_enabled: bool,
@@ -56,13 +57,14 @@ pub struct DeviceState {
pub brightness_on_battery: Brightness,
}
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type), zvariant(signature = "s"))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum AnimeType {
GA401,
GA402,
GU604,
G635L,
G835L,
#[default]
Unsupported,
}
@@ -71,12 +73,21 @@ impl FromStr for AnimeType {
type Err = AnimeError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(match s {
"ga401" | "GA401" => Self::GA401,
"ga402" | "GA402" => Self::GA402,
"gu604" | "GU604" => Self::GU604,
_ => Self::Unsupported,
})
let dmi = s.to_uppercase();
if dmi.contains("GA401") {
return Ok(Self::GA401);
} else if dmi.contains("GA402") {
return Ok(Self::GA402);
} else if dmi.contains("GU604") {
return Ok(Self::GU604);
} else if dmi.contains("G635L") {
return Ok(Self::G635L);
} else if dmi.contains("G835L") {
return Ok(Self::G835L);
}
Ok(Self::Unsupported)
}
}
@@ -85,10 +96,17 @@ impl AnimeType {
let board_name = DMIID::new().unwrap_or_default().board_name.to_uppercase();
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
AnimeType::GA401
} else if board_name.contains("GA402R") || board_name.contains("GA402X") {
} else if board_name.contains("GA402R")
|| board_name.contains("GA402X")
|| board_name.contains("GA402N")
{
AnimeType::GA402
} else if board_name.contains("GU604V") {
AnimeType::GU604
} else if board_name.contains("G635L") {
AnimeType::G635L
} else if board_name.contains("G835L") {
AnimeType::G835L
} else {
AnimeType::Unsupported
}
@@ -98,6 +116,9 @@ impl AnimeType {
pub fn width(&self) -> usize {
match self {
AnimeType::GU604 => 70,
// TODO: Find G635L W*H
AnimeType::G635L => 68,
AnimeType::G835L => 68,
_ => 74,
}
}
@@ -107,6 +128,8 @@ impl AnimeType {
match self {
AnimeType::GA401 => 36,
AnimeType::GU604 => 43,
AnimeType::G635L => 34,
AnimeType::G835L => 34,
_ => 39,
}
}
@@ -115,7 +138,9 @@ impl AnimeType {
pub fn data_length(&self) -> usize {
match self {
AnimeType::GA401 => PANE_LEN * 2,
AnimeType::GU604 => PANE_LEN * 3,
// G835L has 810 LEDs: 210 (triangle) + 600 (staggered rectangle)
AnimeType::G635L => 810, // TODO: This is provisional until we have a G635L to test on
AnimeType::G835L => 810,
_ => PANE_LEN * 3,
}
}
@@ -179,13 +204,29 @@ impl TryFrom<AnimeDataBuffer> for AnimePacketType {
}
let mut buffers = match anime.anime {
AnimeType::GA401 => vec![[0; 640]; 2],
AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unsupported => vec![[0; 640]; 3],
AnimeType::GA401 | AnimeType::G635L | AnimeType::G835L => vec![[0; 640]; 2],
AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unsupported => {
vec![[0; 640]; 3]
}
};
for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() {
buffers[idx][BLOCK_START..BLOCK_END].copy_from_slice(chunk);
// G835L has different packing: 627 bytes in pane 1, 183 bytes in pane 2
if anime.anime == AnimeType::G835L || anime.anime == AnimeType::G635L {
let data = anime.data.as_slice();
// Pane 1: first 627 bytes
let pane1_len = PANE_LEN.min(data.len());
buffers[0][BLOCK_START..BLOCK_START + pane1_len].copy_from_slice(&data[..pane1_len]);
// Pane 2: remaining bytes (183)
if data.len() > PANE_LEN {
let pane2_len = data.len() - PANE_LEN;
buffers[1][BLOCK_START..BLOCK_START + pane2_len].copy_from_slice(&data[PANE_LEN..]);
}
} else {
for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() {
buffers[idx][BLOCK_START..BLOCK_START + chunk.len()].copy_from_slice(chunk);
}
}
buffers[0][..7].copy_from_slice(&USB_PREFIX1);
buffers[1][..7].copy_from_slice(&USB_PREFIX2);

View File

@@ -146,6 +146,8 @@ impl AnimeDiagonal {
match anime_type {
AnimeType::GA401 => self.to_ga401_packets(),
AnimeType::GU604 => self.to_gu604_packets(),
AnimeType::G635L => self.to_g835l_packets(), // TODO: Verify with G635L model
AnimeType::G835L => self.to_g835l_packets(),
_ => self.to_ga402_packets(),
}
}
@@ -381,4 +383,80 @@ impl AnimeDiagonal {
AnimeDataBuffer::from_vec(crate::AnimeType::GA402, buf)
}
/// G835L diagonal packing - inverted geometry (rows grow then constant)
/// Triangle (rows 0-27): pairs grow from 1→14 LEDs
/// Rectangle (rows 28-67): constant 15 LEDs
///
/// Diagonal PNG layout for G835L:
/// - Image height = 34 (row pairs)
/// - Image width = 68 (half-step X grid)
/// - Even/odd rows are interleaved in X (staggered by 0.5 LED = 1 px)
fn to_g835l_packets(&self) -> Result<AnimeDataBuffer> {
use log::debug;
let mut buf = vec![0u8; AnimeType::G835L.data_length()];
let mut buf_idx = 0usize;
debug!(
"G835L packing: image dimensions {}x{}, buffer size {}",
self.1.first().map(|r| r.len()).unwrap_or(0),
self.1.len(),
buf.len()
);
// Helper: get row length for G835L
fn row_length(row: usize) -> usize {
if row < 28 {
row / 2 + 1
} else {
15
}
}
// Helper: starting X (in LED units) for the row
fn first_x(row: usize) -> usize {
if row < 28 {
0
} else {
(row - 28) / 2
}
}
// Process all 68 rows
for row in 0..68 {
let len = row_length(row);
let img_y = row / 2;
let base_x = first_x(row);
let stagger = row % 2;
for i in 0..len {
// Half-step X grid: even rows on even pixels, odd rows on odd pixels.
let img_x = (base_x + i) * 2 + stagger;
// Read from image, clamp to bounds
let val = if img_y < self.1.len() && img_x < self.1[img_y].len() {
self.1[img_y][img_x]
} else {
0
};
// Log first LED of each row for debugging
if i == 0 {
debug!(
"Row {}: len={}, first LED at img[{}][{}] = {}",
row, len, img_y, img_x, val
);
}
if buf_idx < buf.len() {
buf[buf_idx] = val;
}
buf_idx += 1;
}
}
debug!("G835L packing complete: {} bytes written", buf_idx);
AnimeDataBuffer::from_vec(AnimeType::G835L, buf)
}
}

View File

@@ -137,8 +137,8 @@ impl AnimeImage {
fn scale_y(anime_type: AnimeType) -> f32 {
match anime_type {
AnimeType::GA401 => 0.3,
AnimeType::GU604 => 0.28,
_ => 0.283,
AnimeType::GA402 => 0.283,
_ => 0.28,
}
}
@@ -149,6 +149,7 @@ impl AnimeImage {
/// square grid, so `first_x` is the x position on that grid where the
/// LED is actually positioned in relation to the Y.
///
/// For GA401/GA402/GU604 (shrinking pattern - diagonal cuts in from left):
/// ```text
/// +------------+
/// | |
@@ -162,6 +163,19 @@ impl AnimeImage {
/// ^ ------+
/// first_x
/// ```
///
/// For G835L/G635L (inverted pattern - triangle grows then rectangle shifts):
/// ```text
/// ● <- Row 0: first_x = 0, width = 1
/// ● <- Row 1: first_x = 0 (stagger), width = 1
/// ● ● <- Row 2: first_x = 0, width = 2
/// ● ● <- Row 3: first_x = 0 (stagger), width = 2
/// ... <- Triangle continues, first_x = 0 for rows 0-27
/// ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● <- Row 28+: first_x grows
/// ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● <- Rectangle shifts right
/// ```
/// Triangle (rows 0-27): first_x = 0 (no cumulative shift)
/// Rectangle (rows 28-67): first_x = (y - 28) / 2 (shifts right)
fn first_x(anime_type: AnimeType, y: u32) -> u32 {
match anime_type {
AnimeType::GA401 => {
@@ -169,7 +183,7 @@ impl AnimeImage {
// first 5 rows for GA401 are always at X = 0
return 0;
}
(y + 1) / 2 - 3
y.div_ceil(2) - 3
}
AnimeType::GU604 => {
// first 9 rows start at zero
@@ -179,13 +193,23 @@ impl AnimeImage {
// and then their offset grows by one every two rows
(y - 9) / 2
}
AnimeType::G635L | AnimeType::G835L => {
// G835L/G635L have inverted geometry - triangle at top-left, rectangle shifts right
// Triangle (rows 0-27): no cumulative shift, just alternating stagger
// Rectangle (rows 28-67): shifts right by ~0.5px per row
if y < 28 {
0
} else {
(y - 28) / 2
}
}
_ => {
// first 11 rows start at zero
if y <= 11 {
return 0;
}
// and then their offset grows by one every two rows
(y + 1) / 2 - 5
y.div_ceil(2) - 5
}
}
}
@@ -213,7 +237,7 @@ impl AnimeImage {
// First 5 rows for GA401 are always 33 physical LEDs long
return 33;
}
36 - (y + 1) / 2
36 - y.div_ceil(2)
}
AnimeType::GU604 => {
if y <= 9 {
@@ -221,6 +245,16 @@ impl AnimeImage {
}
38 - Self::first_x(anime_type, y) + y % 2
}
AnimeType::G635L | AnimeType::G835L => {
// G835L/G635L rows GROW then stay constant (inverted from other devices)
// Triangle (rows 0-27): pairs of rows with same length, 1→14
// Rectangle (rows 28-67): constant 15 LEDs
if y < 28 {
y / 2 + 1
} else {
15
}
}
_ => {
if y <= 11 {
return 34;
@@ -235,8 +269,9 @@ impl AnimeImage {
match anime_type {
// 33.0 = Longest row LED count (physical) plus half-pixel offset
AnimeType::GA401 => (33.0 + 0.5) * Self::scale_x(anime_type),
AnimeType::GU604 => (38.0 + 0.5) * Self::scale_x(anime_type),
AnimeType::G635L => (33.0 + 0.5) * Self::scale_x(anime_type),
AnimeType::G835L => (33.0 + 0.5) * Self::scale_x(anime_type),
_ => (35.0 + 0.5) * Self::scale_x(anime_type),
}
}
@@ -246,6 +281,8 @@ impl AnimeImage {
match anime_type {
AnimeType::GA401 => 55,
AnimeType::GU604 => 62,
AnimeType::G635L => 68,
AnimeType::G835L => 68,
_ => 61,
}
}
@@ -256,6 +293,8 @@ impl AnimeImage {
// 54.0 = End column LED count (physical) plus one dead pixel
AnimeType::GA401 => (54.0 + 1.0) * Self::scale_y(anime_type),
AnimeType::GU604 => 62.0 * Self::scale_y(anime_type),
AnimeType::G635L => 68.0 * Self::scale_y(anime_type),
AnimeType::G835L => 68.0 * Self::scale_y(anime_type),
// GA402 may not have dead pixels and require only the physical LED count
_ => 61.0 * Self::scale_y(anime_type),
}
@@ -269,8 +308,8 @@ impl AnimeImage {
1 | 3 => 35, // Some rows are padded
_ => 36 - y / 2,
},
AnimeType::GU604 => AnimeImage::width(anime_type, y),
// GA402 does not have padding, equivalent to width
// Other devices don't have dead pixels
_ => AnimeImage::width(anime_type, y),
}
}
@@ -321,7 +360,9 @@ impl AnimeImage {
let pos = Vec3::new(led.x(), led.y(), 1.0);
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];
const GROUP: [f32; 4] = [
0.0, 0.5, 1.0, 1.5,
];
for u in &GROUP {
for v in &GROUP {
let sample = x0 + *u * du + *v * dv;
@@ -403,13 +444,35 @@ impl AnimeImage {
let transform =
Mat3::from_scale_angle_translation(self.scale, self.angle, self.translation);
let pos_in_leds = Mat3::from_translation(Vec2::new(20.0, 20.0));
let pos_in_leds = Mat3::from_translation(self.led_center());
// Get LED-to-image coords
let led_from_px = pos_in_leds * led_from_cm * transform * cm_from_px * center;
led_from_px.inverse()
}
fn led_center(&self) -> Vec2 {
if !matches!(self.anime_type, AnimeType::G635L | AnimeType::G835L) {
return Vec2::new(20.0, 20.0);
}
let mut min = Vec2::splat(f32::INFINITY);
let mut max = Vec2::splat(f32::NEG_INFINITY);
for led in self.led_pos.iter().flatten() {
let pos = Vec2::new(led.x(), led.y());
min = min.min(pos);
max = max.max(pos);
}
if min.x.is_finite() {
let mut center = (min + max) * 0.5;
center.y += 1.0;
center
} else {
Vec2::new(20.0, 20.0)
}
}
/// 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()`.

View File

@@ -75,10 +75,7 @@ impl ActionData {
time,
brightness,
} => ActionData::Animation(AnimeGif::from_diagonal_gif(
file,
*time,
*brightness,
anime_type,
file, *time, *brightness, anime_type,
)?),
ActionLoader::AsusImage {
file,
@@ -91,10 +88,7 @@ impl ActionData {
ActionData::Image(Box::new(data))
}
_ => ActionData::Animation(AnimeGif::from_diagonal_png(
file,
anime_type,
*time,
*brightness,
file, anime_type, *time, *brightness,
)?),
},
ActionLoader::ImageAnimation {
@@ -108,24 +102,12 @@ impl ActionData {
if let Some(ext) = file.extension() {
if ext.to_string_lossy().to_lowercase() == "png" {
return Ok(ActionData::Animation(AnimeGif::from_png(
file,
*scale,
*angle,
*translation,
*time,
*brightness,
anime_type,
file, *scale, *angle, *translation, *time, *brightness, anime_type,
)?));
}
}
ActionData::Animation(AnimeGif::from_gif(
file,
*scale,
*angle,
*translation,
*time,
*brightness,
anime_type,
file, *scale, *angle, *translation, *time, *brightness, anime_type,
)?)
}
ActionLoader::Image {
@@ -140,24 +122,13 @@ impl ActionData {
AnimTime::Infinite => {
// If no time then create a plain static image
let image = AnimeImage::from_png(
file,
*scale,
*angle,
*translation,
*brightness,
anime_type,
file, *scale, *angle, *translation, *brightness, anime_type,
)?;
let data = <AnimeDataBuffer>::try_from(&image)?;
ActionData::Image(Box::new(data))
}
_ => ActionData::Animation(AnimeGif::from_png(
file,
*scale,
*angle,
*translation,
*time,
*brightness,
anime_type,
file, *scale, *angle, *translation, *time, *brightness, anime_type,
)?),
}
}

View File

@@ -12,7 +12,6 @@ use std::str::FromStr;
use dmi_id::DMIID;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[cfg(feature = "dbus")]
use zbus::zvariant::{OwnedValue, Type, Value};
@@ -29,7 +28,6 @@ pub const PROD_ID: u16 = 0x193b;
derive(Type, Value, OwnedValue),
zvariant(signature = "u")
)]
#[typeshare]
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
/// Base LED brightness of the display
pub enum Brightness {
@@ -82,7 +80,6 @@ impl From<Brightness> for i32 {
derive(Type, Value, OwnedValue),
zvariant(signature = "s")
)]
#[typeshare]
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub enum AnimBooting {
#[default]
@@ -123,7 +120,6 @@ impl From<AnimBooting> for i32 {
derive(Type, Value, OwnedValue),
zvariant(signature = "s")
)]
#[typeshare]
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub enum AnimAwake {
#[default]
@@ -164,7 +160,6 @@ impl From<AnimAwake> for i32 {
derive(Type, Value, OwnedValue),
zvariant(signature = "s")
)]
#[typeshare]
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub enum AnimSleeping {
#[default]
@@ -205,7 +200,6 @@ impl From<AnimSleeping> for i32 {
derive(Type, Value, OwnedValue),
zvariant(signature = "s")
)]
#[typeshare]
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub enum AnimShutdown {
#[default]
@@ -249,14 +243,21 @@ impl From<AnimShutdown> for i32 {
#[inline]
pub fn get_anime_type() -> AnimeType {
let dmi = DMIID::new().unwrap_or_default();
let board_name = dmi.board_name;
let board_name = dmi.board_name.to_uppercase();
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
AnimeType::GA401
} else if board_name.contains("GA402R") || board_name.contains("GA402X") {
} else if board_name.contains("GA402R")
|| board_name.contains("GA402X")
|| board_name.contains("GA402N")
{
AnimeType::GA402
} else if board_name.contains("GU604V") {
AnimeType::GU604
} else if board_name.contains("G635L") {
AnimeType::G635L
} else if board_name.contains("G835L") {
AnimeType::G835L
} else {
AnimeType::Unsupported
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

556
rog-anime/tests/g835l.rs Normal file
View File

@@ -0,0 +1,556 @@
// TODO: This is a provisional copy paste of GA401
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use rog_anime::*;
#[test]
fn g835l_image_edge_packet_check() {
let pkt0_check = [
0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let pkt1_check = [
0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let mut matrix = AnimeImage::new(
Vec2::new(1.0, 1.0),
0.0,
Vec2::default(),
0.0,
vec![Pixel::default(); 1000],
100,
AnimeType::G835L,
)
.unwrap();
matrix.edge_outline();
let data = AnimeDataBuffer::try_from(&matrix).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
}
#[test]
fn g835l_diagonal_packet_check() {
let pkt0_check = [
0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let pkt1_check = [
0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests/data/g835l-diagonal.png");
let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::G835L).unwrap();
let data = matrix.into_data_buffer(AnimeType::G835L).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
}
#[test]
fn g835l_diagonal_fullbright_packet_check() {
let pkt0_check = [
0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let pkt1_check = [
0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests/data/g835l-diagonal-fullbright.png");
let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::G835L).unwrap();
let data = matrix.into_data_buffer(AnimeType::G835L).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
}
#[test]
fn g835l_diagonal_gif_wave_packet_check() {
let pkt0_frame0_check = [
0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02, 0x7f, 0x92, 0x84, 0xa2, 0x95, 0xac, 0x8a,
0xa0, 0xaf, 0x97, 0xa4, 0xa8, 0x91, 0x9c, 0x9e, 0x99, 0x98, 0x98, 0x91, 0x82, 0x99,
0x97, 0x8d, 0x7c, 0x67, 0x99, 0x8d, 0x7a, 0x63, 0x4a, 0xa0, 0x92, 0x7d, 0x63, 0x48,
0x2e, 0x9a, 0x83, 0x67, 0x4a, 0x2e, 0x17, 0xa6, 0x8d, 0x70, 0x50, 0x32, 0x19, 0x08,
0x9a, 0x7b, 0x5a, 0x3b, 0x20, 0x0c, 0x02, 0xa8, 0x89, 0x67, 0x46, 0x2a, 0x15, 0x09,
0x07, 0x97, 0x75, 0x54, 0x37, 0x21, 0x13, 0x10, 0x16, 0xa6, 0x84, 0x63, 0x45, 0x2e,
0x20, 0x1c, 0x21, 0x2e, 0x91, 0x71, 0x54, 0x3d, 0x2f, 0x2a, 0x2e, 0x3a, 0x4c, 0x9d,
0x7d, 0x61, 0x4c, 0x3e, 0x39, 0x3d, 0x49, 0x5a, 0x6d, 0x87, 0x6d, 0x58, 0x4c, 0x48,
0x4c, 0x58, 0x69, 0x7c, 0x8e, 0x8e, 0x75, 0x63, 0x58, 0x55, 0x5a, 0x67, 0x78, 0x8b,
0x9d, 0xab, 0x7a, 0x69, 0x60, 0x5f, 0x66, 0x74, 0x86, 0x9a, 0xac, 0xba, 0xc1, 0x7a,
0x6c, 0x65, 0x66, 0x6f, 0x7f, 0x93, 0xa7, 0xba, 0xc9, 0xd0, 0xce, 0x6a, 0x65, 0x69,
0x74, 0x86, 0x9c, 0xb2, 0xc7, 0xd6, 0xde, 0xdd, 0xd2, 0x63, 0x61, 0x67, 0x75, 0x89,
0xa1, 0xba, 0xd0, 0xe1, 0xea, 0xea, 0xe0, 0xcc, 0x59, 0x61, 0x71, 0x88, 0xa2, 0xbd,
0xd5, 0xe8, 0xf3, 0xf4, 0xec, 0xd9, 0xbf, 0x4e, 0x58, 0x6a, 0x82, 0x9e, 0xbc, 0xd6,
0xeb, 0xf8, 0xfc, 0xf4, 0xe4, 0xca, 0xac, 0x4b, 0x5f, 0x79, 0x97, 0xb6, 0xd3, 0xea,
0xf9, 0xfe, 0xf9, 0xea, 0xd3, 0xb6, 0x96, 0x3d, 0x51, 0x6c, 0x8c, 0xad, 0xcb, 0xe4,
0xf6, 0xfd, 0xfa, 0xed, 0xd8, 0xbd, 0x9f, 0x82, 0x43, 0x5e, 0x7f, 0xa1, 0xc0, 0xdb,
0xee, 0xf7, 0xf6, 0xeb, 0xd8, 0xc0, 0xa4, 0x89, 0x71, 0x50, 0x70, 0x92, 0xb3, 0xcf,
0xe3, 0xee, 0xee, 0xe6, 0xd5, 0xbe, 0xa4, 0x8c, 0x76, 0x67, 0x62, 0x84, 0xa5, 0xc1,
0xd5, 0xe1, 0xe3, 0xdc, 0xcd, 0xb8, 0xa1, 0x8a, 0x77, 0x6a, 0x64, 0x76, 0x96, 0xb2,
0xc7, 0xd3, 0xd5, 0xcf, 0xc1, 0xae, 0x99, 0x84, 0x73, 0x68, 0x65, 0x6a, 0x89, 0xa4,
0xb8, 0xc4, 0xc6, 0xc0, 0xb3, 0xa1, 0x8d, 0x7a, 0x6b, 0x63, 0x62, 0x69, 0x78, 0x98,
0xab, 0xb5, 0xb8, 0xb1, 0xa4, 0x93, 0x7f, 0x6e, 0x60, 0x59, 0x5b, 0x64, 0x75, 0x8c,
0xa0, 0xa9, 0xaa, 0xa3, 0x95, 0x83, 0x70, 0x5f, 0x53, 0x4d, 0x50, 0x5b, 0x6e, 0x87,
0xa4, 0xa0, 0x9f, 0x96, 0x87, 0x74, 0x61, 0x50, 0x44, 0x3f, 0x42, 0x4f, 0x64, 0x7e,
0x9d, 0xbc, 0x97, 0x8c, 0x7c, 0x68, 0x53, 0x41, 0x34, 0x2f, 0x33, 0x41, 0x56, 0x73,
0x93, 0xb3, 0xd1, 0x86, 0x74, 0x5e, 0x47, 0x34, 0x27, 0x21, 0x25, 0x32, 0x48, 0x65,
0x86, 0xa7, 0xc6, 0xe0, 0x70, 0x57, 0x3f, 0x2a, 0x1b, 0x14, 0x17, 0x24, 0x39, 0x56,
0x77, 0x99, 0xb9, 0xd4, 0xe6, 0x56, 0x3b, 0x24, 0x13, 0x0a, 0x0c, 0x17, 0x2c, 0x48,
0x69, 0x8b, 0xab, 0xc6, 0xd9, 0xe3, 0x3b, 0x22, 0x0f, 0x04, 0x04, 0x0e, 0x21, 0x3c,
0x5b, 0x7d, 0x9c, 0xb7, 0xca, 0xd5, 0xd6, 0x25, 0x0f, 0x03, 0x00, 0x08, 0x19, 0x32,
0x50, 0x70, 0x8f, 0xa9, 0xbc, 0xc6, 0xc7, 0xc0, 0x14, 0x05, 0x01, 0x06, 0x15, 0x2c,
0x49, 0x67, 0x84, 0x9c, 0xae, 0xb7, 0xb8, 0xb0, 0xa2, 0x0c, 0x05, 0x09, 0x16, 0x2b,
0x45, 0x61, 0x7c, 0x93, 0xa3, 0xab, 0xaa, 0xa2, 0x93, 0x81, 0x0e, 0x10, 0x1b, 0x2e,
0x46, 0x60, 0x78, 0x8d, 0x9b, 0xa1, 0x9e, 0x94, 0x85, 0x72, 0x5f, 0x1b, 0x24, 0x35,
0x4b, 0x62, 0x79, 0x8b, 0x96, 0x9a, 0x96, 0x8a, 0x79, 0x65, 0x50, 0x3f, 0x30, 0x40,
0x54, 0x6a, 0x7e, 0x8d, 0x97, 0x98, 0x91, 0x84, 0x70, 0x5a, 0x44, 0x32, 0x26, 0x4d,
0x60, 0x74, 0x87, 0x94, 0x9b, 0x9a, 0x91, 0x81, 0x6c, 0x53, 0x3c, 0x28, 0x1a, 0x15,
0x6e, 0x82, 0x93, 0x9f, 0xa4, 0xa1, 0x96, 0x83, 0x6b, 0x51, 0x37, 0x21, 0x11, 0x0a,
0x0e, 0x91, 0xa1, 0xac, 0xb0, 0xab, 0x9e, 0x89, 0x6f, 0x53, 0x37, 0x1e, 0x0d, 0x04,
0x05, 0x11, 0xb0, 0xbb, 0xbe, 0xb8, 0xaa, 0x93, 0x77, 0x59, 0x3a, 0x20, 0x0c, 0x01,
0x01, 0x0a, 0x1d, 0xca, 0xcd, 0xc7, 0xb7, 0xa0, 0x83, 0x62, 0x42, 0x26, 0x10, 0x03,
0x01, 0x08, 0x19, 0x31, 0xdc, 0xd6, 0xc6, 0xae, 0x90, 0x6f, 0x4e, 0x30, 0x18, 0x0a,
0x05, 0x0a, 0x19, 0x2f, 0x4a, 0xe4, 0xd4, 0xbd, 0x9f, 0x7d, 0x5b, 0x3c, 0x24, 0x14,
0x0d, 0x11, 0x1e, 0x32, 0x4a, 0x64, 0xe1, 0xcb, 0xad, 0x8c, 0x6a, 0x4b, 0x31, 0x20,
0x19, 0x1b, 0x26, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let pkt1_frame0_check = [
0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02, 0x4f, 0x66, 0x7c, 0xd6, 0xba, 0x99, 0x78,
0x59, 0x40, 0x2f, 0x27, 0x28, 0x32, 0x42, 0x57, 0x6d, 0x80, 0x8f, 0xc4, 0xa5, 0x85,
0x67, 0x4f, 0x3e, 0x35, 0x37, 0x40, 0x4f, 0x63, 0x77, 0x89, 0x96, 0x9b, 0xad, 0x8f,
0x73, 0x5c, 0x4c, 0x44, 0x46, 0x4f, 0x5e, 0x71, 0x84, 0x94, 0xa0, 0xa3, 0x9f, 0x96,
0x7b, 0x66, 0x58, 0x52, 0x54, 0x5e, 0x6e, 0x80, 0x93, 0xa2, 0xac, 0xaf, 0xa9, 0x9a,
0x80, 0x6d, 0x61, 0x5c, 0x60, 0x6c, 0x7c, 0x8f, 0xa2, 0xb2, 0xbb, 0xbd, 0xb5, 0xa5,
0x8e, 0x70, 0x66, 0x64, 0x6a, 0x77, 0x89, 0x9d, 0xb1, 0xc1, 0xca, 0xcb, 0xc4, 0xb3,
0x9a, 0x7c, 0x66, 0x67, 0x6f, 0x7e, 0x92, 0xa8, 0xbd, 0xce, 0xd9, 0xda, 0xd3, 0xc1,
0xa8, 0x8a, 0x68, 0x65, 0x70, 0x82, 0x98, 0xb0, 0xc7, 0xd9, 0xe5, 0xe8, 0xe1, 0xd0,
0xb7, 0x98, 0x76, 0x54, 0x6d, 0x81, 0x99, 0xb3, 0xcd, 0xe1, 0xee, 0xf3, 0xed, 0xdd,
0xc5, 0xa6, 0x85, 0x63, 0x45, 0x7b, 0x96, 0xb3, 0xce, 0xe5, 0xf4, 0xfa, 0xf6, 0xe8,
0xd1, 0xb4, 0x93, 0x71, 0x53, 0x3b, 0x8f, 0xad, 0xcb, 0xe4, 0xf5, 0xfe, 0xfc, 0xef,
0xda, 0xbe, 0x9f, 0x7f, 0x61, 0x4a, 0x3b, 0xa5, 0xc4, 0xdf, 0xf2, 0xfd, 0xfd, 0xf2,
0xdf, 0xc5, 0xa8, 0x89, 0x6e, 0x57, 0x49, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let pkt0_frame16_check = [
0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02, 0x95, 0x88, 0x92, 0x75, 0x81, 0x60, 0x8f,
0x6d, 0x4c, 0x7c, 0x5a, 0x3c, 0x8a, 0x69, 0x4a, 0x32, 0x77, 0x59, 0x41, 0x32, 0x83,
0x66, 0x50, 0x40, 0x3a, 0x72, 0x5c, 0x4e, 0x49, 0x4c, 0x79, 0x66, 0x59, 0x56, 0x5a,
0x65, 0x6c, 0x61, 0x5f, 0x66, 0x72, 0x84, 0x6d, 0x66, 0x66, 0x6e, 0x7d, 0x90, 0xa5,
0x65, 0x68, 0x72, 0x83, 0x99, 0xaf, 0xc5, 0x61, 0x65, 0x72, 0x86, 0x9d, 0xb6, 0xcd,
0xdf, 0x5f, 0x6e, 0x84, 0x9d, 0xb9, 0xd2, 0xe6, 0xf2, 0x55, 0x66, 0x7d, 0x99, 0xb7,
0xd2, 0xe8, 0xf7, 0xfc, 0x5a, 0x73, 0x91, 0xb1, 0xce, 0xe6, 0xf7, 0xfe, 0xfb, 0x4c,
0x67, 0x86, 0xa7, 0xc6, 0xe0, 0xf3, 0xfc, 0xfb, 0xf0, 0x58, 0x78, 0x9a, 0xbb, 0xd6,
0xeb, 0xf6, 0xf7, 0xed, 0xdc, 0x4a, 0x6a, 0x8c, 0xad, 0xca, 0xdf, 0xec, 0xee, 0xe7,
0xd7, 0xc1, 0x5b, 0x7d, 0x9f, 0xbc, 0xd2, 0xdf, 0xe3, 0xdd, 0xcf, 0xbb, 0xa4, 0x4f,
0x70, 0x90, 0xad, 0xc3, 0xd0, 0xd5, 0xd0, 0xc3, 0xb1, 0x9b, 0x87, 0x64, 0x83, 0x9f,
0xb4, 0xc1, 0xc6, 0xc1, 0xb5, 0xa3, 0x90, 0x7c, 0x6d, 0x5c, 0x79, 0x93, 0xa7, 0xb3,
0xb7, 0xb2, 0xa6, 0x95, 0x81, 0x6f, 0x61, 0x59, 0x73, 0x8b, 0x9d, 0xa7, 0xa9, 0xa3,
0x97, 0x85, 0x72, 0x60, 0x53, 0x4c, 0x4e, 0x70, 0x86, 0x96, 0x9e, 0x9f, 0x97, 0x89,
0x77, 0x63, 0x51, 0x44, 0x3e, 0x40, 0x4b, 0x86, 0x93, 0x99, 0x97, 0x8e, 0x7e, 0x6a,
0x55, 0x43, 0x35, 0x2f, 0x31, 0x3d, 0x51, 0x8a, 0x95, 0x99, 0x94, 0x88, 0x76, 0x61,
0x4a, 0x36, 0x27, 0x20, 0x22, 0x2e, 0x43, 0x5f, 0x9b, 0x9c, 0x96, 0x87, 0x73, 0x5b,
0x43, 0x2d, 0x1c, 0x14, 0x15, 0x20, 0x34, 0x50, 0x71, 0xa4, 0x9b, 0x8b, 0x74, 0x5a,
0x3f, 0x27, 0x15, 0x0b, 0x0a, 0x14, 0x27, 0x42, 0x62, 0x84, 0xa5, 0x92, 0x7a, 0x5d,
0x40, 0x26, 0x11, 0x05, 0x03, 0x0b, 0x1d, 0x36, 0x55, 0x76, 0x96, 0x9d, 0x83, 0x64,
0x45, 0x29, 0x12, 0x04, 0x00, 0x06, 0x15, 0x2d, 0x4b, 0x6a, 0x89, 0xa4, 0x8f, 0x6f,
0x4e, 0x30, 0x18, 0x07, 0x01, 0x05, 0x12, 0x28, 0x44, 0x62, 0x7f, 0x98, 0xab, 0x7c,
0x5a, 0x3b, 0x21, 0x0f, 0x06, 0x08, 0x14, 0x27, 0x41, 0x5c, 0x77, 0x8f, 0xa0, 0xa9,
0x68, 0x48, 0x2d, 0x1a, 0x10, 0x10, 0x19, 0x2b, 0x42, 0x5c, 0x74, 0x89, 0x98, 0xa0,
0x9e, 0x57, 0x3b, 0x27, 0x1c, 0x1b, 0x23, 0x33, 0x48, 0x5f, 0x76, 0x88, 0x95, 0x9a,
0x97, 0x8c, 0x4a, 0x36, 0x2a, 0x28, 0x2f, 0x3e, 0x51, 0x67, 0x7b, 0x8c, 0x96, 0x99,
0x93, 0x86, 0x73, 0x44, 0x39, 0x37, 0x3e, 0x4b, 0x5e, 0x72, 0x85, 0x93, 0x9b, 0x9c,
0x94, 0x84, 0x6f, 0x57, 0x48, 0x46, 0x4d, 0x5b, 0x6c, 0x80, 0x91, 0x9e, 0xa4, 0xa3,
0x99, 0x87, 0x70, 0x55, 0x3b, 0x54, 0x5c, 0x6a, 0x7c, 0x8f, 0xa0, 0xac, 0xb1, 0xad,
0xa1, 0x8e, 0x74, 0x58, 0x3b, 0x22, 0x69, 0x78, 0x8b, 0x9e, 0xaf, 0xbb, 0xbf, 0xbb,
0xad, 0x98, 0x7d, 0x5e, 0x40, 0x24, 0x0f, 0x84, 0x98, 0xac, 0xbe, 0xca, 0xce, 0xc9,
0xbb, 0xa5, 0x89, 0x68, 0x48, 0x2b, 0x14, 0x05, 0xa2, 0xb8, 0xcb, 0xd8, 0xdd, 0xd8,
0xca, 0xb3, 0x96, 0x75, 0x54, 0x35, 0x1c, 0x0c, 0x05, 0xc0, 0xd5, 0xe3, 0xea, 0xe6,
0xd8, 0xc2, 0xa5, 0x84, 0x61, 0x42, 0x28, 0x16, 0x0e, 0x10, 0xdb, 0xec, 0xf4, 0xf1,
0xe5, 0xd0, 0xb3, 0x92, 0x70, 0x50, 0x36, 0x23, 0x1a, 0x1b, 0x24, 0xf0, 0xfa, 0xfa,
0xef, 0xdb, 0xc0, 0xa0, 0x7e, 0x5f, 0x45, 0x32, 0x28, 0x28, 0x31, 0x40, 0xfc, 0xfe,
0xf5, 0xe3, 0xc9, 0xab, 0x8b, 0x6c, 0x53, 0x41, 0x37, 0x37, 0x3f, 0x4e, 0x61, 0xfd,
0xf7, 0xe7, 0xcf, 0xb3, 0x94, 0x78, 0x60, 0x4f, 0x46, 0x46, 0x4e, 0x5d, 0x6f, 0x82,
0xf4, 0xe7, 0xd1, 0xb7, 0x9b, 0x80, 0x6a, 0x5a, 0x53, 0x54, 0x5d, 0x6c, 0x7e, 0x91,
0xa1, 0xe2, 0xce, 0xb6, 0x9c, 0x84, 0x70, 0x62, 0x5d, 0x60, 0x6a, 0x7a, 0x8d, 0xa0,
0xb1, 0xbb, 0xc8, 0xb2, 0x9a, 0x84, 0x72, 0x67, 0x64, 0x69, 0x75, 0x86, 0x9b, 0xaf,
0xbf, 0xca, 0xcd, 0xa9, 0x93, 0x7f, 0x70, 0x67, 0x66, 0x6d, 0x7c, 0x8f, 0xa5, 0xbb,
0xcd, 0xd8, 0xdc, 0xd5, 0x89, 0x76, 0x69, 0x63, 0x64, 0x6e, 0x7e, 0x94, 0xac, 0xc4,
0xd8, 0xe5, 0xe9, 0xe3, 0xd4, 0x6b, 0x5f, 0x5a, 0x5e, 0x6a, 0x7d, 0x95, 0xaf, 0xc9,
0xdf, 0xed, 0xf3, 0xef, 0xe1, 0xca, 0x52, 0x4f, 0x54, 0x62, 0x77, 0x91, 0xae, 0xca,
0xe1, 0xf2, 0xfa, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let pkt1_frame16_check = [
0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02, 0xeb, 0xd6, 0xb9, 0x41, 0x47, 0x56, 0x6d,
0x89, 0xa8, 0xc6, 0xe0, 0xf3, 0xfd, 0xfd, 0xf2, 0xde, 0xc4, 0xa4, 0x39, 0x49, 0x61,
0x7e, 0x9f, 0xbe, 0xda, 0xef, 0xfb, 0xfd, 0xf5, 0xe3, 0xca, 0xad, 0x8f, 0x3a, 0x53,
0x71, 0x92, 0xb3, 0xd1, 0xe7, 0xf5, 0xf9, 0xf3, 0xe3, 0xcd, 0xb2, 0x95, 0x7b, 0x44,
0x62, 0x84, 0xa6, 0xc4, 0xdc, 0xec, 0xf1, 0xed, 0xdf, 0xcb, 0xb2, 0x98, 0x80, 0x6d,
0x54, 0x76, 0x97, 0xb6, 0xcf, 0xdf, 0xe6, 0xe3, 0xd7, 0xc5, 0xae, 0x96, 0x80, 0x6f,
0x66, 0x68, 0x89, 0xa7, 0xc0, 0xd1, 0xd8, 0xd6, 0xcc, 0xbb, 0xa6, 0x90, 0x7c, 0x6e,
0x66, 0x67, 0x7c, 0x9a, 0xb2, 0xc2, 0xc9, 0xc8, 0xbe, 0xae, 0x9a, 0x86, 0x74, 0x68,
0x63, 0x65, 0x70, 0x8e, 0xa4, 0xb4, 0xba, 0xb8, 0xaf, 0x9f, 0x8c, 0x79, 0x69, 0x5e,
0x5b, 0x60, 0x6d, 0x81, 0x9a, 0xa8, 0xad, 0xaa, 0x9f, 0x90, 0x7d, 0x6a, 0x5b, 0x52,
0x50, 0x57, 0x66, 0x7c, 0x96, 0x9e, 0xa2, 0x9d, 0x92, 0x81, 0x6e, 0x5b, 0x4c, 0x43,
0x42, 0x4a, 0x5b, 0x73, 0x8f, 0xae, 0x9a, 0x94, 0x86, 0x74, 0x60, 0x4c, 0x3d, 0x34,
0x33, 0x3c, 0x4d, 0x66, 0x85, 0xa5, 0xc4, 0x8e, 0x7f, 0x6a, 0x54, 0x40, 0x2f, 0x25,
0x24, 0x2d, 0x3f, 0x58, 0x78, 0x99, 0xba, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests/data/g835l-diagonal.gif");
let gif =
AnimeGif::from_diagonal_gif(&path, AnimTime::Count(1), 1.0, AnimeType::G835L).unwrap();
assert_eq!(gif.frame_count(), 48);
let pkt = AnimePacketType::try_from(gif.frames()[0].frame().clone()).unwrap();
assert_eq!(pkt[0], pkt0_frame0_check);
assert_eq!(pkt[1], pkt1_frame0_check);
let pkt = AnimePacketType::try_from(gif.frames()[16].frame().clone()).unwrap();
assert_eq!(pkt[0], pkt0_frame16_check);
assert_eq!(pkt[1], pkt1_frame16_check);
}
}

View File

@@ -23,6 +23,5 @@ dmi_id = { path = "../dmi-id" }
# cli and logging
log.workspace = true
typeshare.workspace = true
ron = { version = "*", optional = true }

View File

@@ -5,7 +5,7 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -14,7 +14,7 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -23,7 +23,7 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -32,7 +32,43 @@
layout_name: "fa507",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FA617NS",
product_id: "",
layout_name: "fa507",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FA617NT",
product_id: "",
layout_name: "fa507",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FA617XS",
product_id: "",
layout_name: "fa507",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FA617XT",
product_id: "",
layout_name: "fa507",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -41,7 +77,7 @@
layout_name: "fx505d",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -50,7 +86,7 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -59,7 +95,7 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -68,7 +104,7 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -77,7 +113,34 @@
layout_name: "fa506i",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FX607J",
product_id: "",
layout_name: "fa506i",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FX607V",
product_id: "",
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle, Pulse],
basic_zones: [],
advanced_type: Zoned([SingleZone]),
power_zones: [Keyboard],
),
(
device_name: "FX617X",
product_id: "",
layout_name: "fa506i",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -86,7 +149,16 @@
layout_name: "fx505d",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FX706H",
product_id: "",
layout_name: "fx505d",
basic_modes: [Static, Breathe, RainbowCycle],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -95,7 +167,7 @@
layout_name: "g512",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -113,7 +185,7 @@
layout_name: "g513i",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -139,17 +211,26 @@
product_id: "",
layout_name: "g513i",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]),
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G513RW",
product_id: "",
layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G531G",
product_id: "",
layout_name: "gx502",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -158,7 +239,7 @@
layout_name: "gx502",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -179,6 +260,15 @@
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G533QS",
product_id: "18c6",
layout_name: "g533q-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G533Z",
product_id: "",
@@ -188,13 +278,31 @@
advanced_type: PerKey,
power_zones: [Keyboard],
),
(
device_name: "G614FR",
product_id: "",
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
),
(
device_name: "G614J",
product_id: "",
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G614JIR",
product_id: "",
layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
@@ -203,16 +311,34 @@
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G614JU",
product_id: "",
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
),
(
device_name: "G614JZ",
product_id: "",
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G615LR",
product_id: "",
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -224,13 +350,22 @@
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo, RearGlow],
),
(
device_name: "G635L",
product_id: "",
layout_name: "g635l-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
),
(
device_name: "G712LI",
product_id: "",
layout_name: "gl503",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -239,7 +374,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -248,7 +383,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -257,7 +392,7 @@
layout_name: "gx502",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -266,7 +401,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -275,7 +410,7 @@
layout_name: "gx502",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -284,7 +419,7 @@
layout_name: "gx502",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -320,7 +455,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -338,7 +473,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4, BarLeft, BarRight],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard, Lightbar],
),
(
@@ -356,7 +491,7 @@
layout_name: "g533q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -365,7 +500,7 @@
layout_name: "g533q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -374,7 +509,7 @@
layout_name: "g533q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -422,6 +557,15 @@
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G815L",
product_id: "",
layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G834J",
product_id: "",
@@ -431,13 +575,22 @@
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo, RearGlow],
),
(
device_name: "G835L",
product_id: "",
layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
),
(
device_name: "GA401I",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -446,7 +599,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -455,7 +608,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -464,7 +617,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -473,7 +626,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -482,7 +635,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -491,7 +644,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -500,7 +653,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -509,7 +662,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -518,7 +671,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -527,7 +680,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -545,7 +698,7 @@
layout_name: "gl503",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -554,7 +707,7 @@
layout_name: "gl503",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -563,7 +716,7 @@
layout_name: "gl503",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4, Logo, BarLeft, BarRight],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -581,7 +734,7 @@
layout_name: "g533q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -590,7 +743,7 @@
layout_name: "gl503",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -599,7 +752,7 @@
layout_name: "fa507",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -648,7 +801,7 @@
power_zones: [Keyboard],
),
(
device_name: "GU605M",
device_name: "GU605C",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
@@ -657,7 +810,7 @@
power_zones: [Keyboard],
),
(
device_name: "GA605W",
device_name: "GU605M",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
@@ -671,7 +824,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -680,7 +833,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -689,7 +842,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -698,7 +851,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -716,7 +869,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -734,7 +887,7 @@
layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -788,7 +941,7 @@
layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -797,7 +950,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -806,7 +959,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -815,8 +968,8 @@
layout_name: "",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [None],
advanced_type: r#None,
power_zones: [r#None],
),
(
device_name: "GZ301Z",
@@ -824,7 +977,25 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "GZ302",
product_id: "18c6",
layout_name: "",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Logo],
),
(
device_name: "GZ302",
product_id: "1a30",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
@@ -833,7 +1004,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Ally],
),
(
@@ -842,7 +1013,7 @@
layout_name: "ga401q",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Pulse],
basic_zones: [],
advanced_type: None,
advanced_type: r#None,
power_zones: [Ally],
),
])
])

View File

@@ -0,0 +1,375 @@
(
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,
),
"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,
),
"lid_logo": Led(
width: 2.6,
height: 1.2,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_left": Led(
width: 0.6,
height: 3.6,
pad_left: -1.2,
pad_right: 0.2,
pad_top: -3.0,
pad_bottom: 0.3,
),
"lightbar_corner_left": Led(
width: 0.8,
height: 0.6,
pad_left: -0.6,
pad_right: 0.2,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_bottom": Led(
width: 12.6,
height: 0.5,
pad_left: -0.1,
pad_right: -0.1,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_corner_right": Led(
width: 0.8,
height: 0.6,
pad_left: 0.0,
pad_right: 0.2,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_right": Led(
width: 0.6,
height: 3.6,
pad_left: -0.8,
pad_right: 0.2,
pad_top: -3.0,
pad_bottom: 0.3,
),
},
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: 6.5,
pad_right: 6.5,
pad_top: 0.2,
pad_bottom: 0.1,
row: [
(LidLogo, "lid_logo"),
],
),
(
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"),
],
),
],
)

View File

@@ -164,6 +164,25 @@ impl LedSupportFile {
return Some(data);
}
// If the system-wide files were not found (typical in CI or
// development environments), attempt to load the bundled
// `data/aura_support.ron` from the crate so tests and local runs
// behave the same as when the package is installed.
// Attempt to load a bundled `aura_support.ron` included at compile time.
// Using `include_str!` ensures the data is available regardless of
// runtime `CARGO_MANIFEST_DIR` or CI environment differences.
let bundled_buf = include_str!("../data/aura_support.ron");
if !bundled_buf.is_empty() {
if let Ok(tmp) = ron::from_str::<LedSupportFile>(bundled_buf) {
data.0.append(&mut tmp.0.clone());
data.0.sort_by(|a, b| a.device_name.cmp(&b.device_name));
info!("Loaded bundled LED support data (embedded)");
return Some(data);
} else {
warn!("Could not parse embedded bundled data file");
}
}
warn!("Does {} exist?", ASUS_LED_MODE_USER_CONF);
None
}
@@ -191,9 +210,16 @@ mod tests {
product_id: String::new(),
layout_name: "ga401".to_owned(),
basic_modes: vec![AuraModeNum::Static],
basic_zones: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft],
basic_zones: vec![
AuraZone::Key1,
AuraZone::Logo,
AuraZone::BarLeft,
],
advanced_type: AdvancedAuraType::Zoned(vec![LedCode::LightbarRight]),
power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow],
power_zones: vec![
PowerZones::Keyboard,
PowerZones::RearGlow,
],
};
assert!(ron::to_string(&led).is_ok());
@@ -214,9 +240,7 @@ mod tests {
tmp_sort.0.sort_by(|a, b| a.product_id.cmp(&b.product_id));
tmp_sort.0.sort_by(|a, b| a.device_name.cmp(&b.device_name));
for model in tmp_sort.0.iter_mut() {
model
.basic_modes
.sort_by(|a, b| (*a as u8).cmp(&(*b as u8)));
model.basic_modes.sort_by_key(|a| *a as u8);
}
if tmp != tmp_sort {
let sorted =

View File

@@ -2,14 +2,12 @@ use std::fmt::Display;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[cfg(feature = "dbus")]
use zbus::zvariant::{OwnedValue, Type, Value};
use crate::error::Error;
use crate::AURA_LAPTOP_LED_MSG_LEN;
#[typeshare]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(
feature = "dbus",
@@ -79,7 +77,6 @@ impl From<i32> for LedBrightness {
}
}
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)]
pub struct Colour {
@@ -120,7 +117,11 @@ impl From<&[f32; 3]> for Colour {
impl From<Colour> for [f32; 3] {
fn from(c: Colour) -> Self {
[c.r as f32 / 255.0, c.g as f32 / 255.0, c.b as f32 / 255.0]
[
c.r as f32 / 255.0,
c.g as f32 / 255.0,
c.b as f32 / 255.0,
]
}
}
@@ -136,11 +137,12 @@ impl From<&[u8; 3]> for Colour {
impl From<Colour> for [u8; 3] {
fn from(c: Colour) -> Self {
[c.r, c.g, c.b]
[
c.r, c.g, c.b,
]
}
}
#[typeshare]
#[cfg_attr(
feature = "dbus",
derive(Type, Value, OwnedValue),
@@ -200,7 +202,6 @@ impl From<Speed> for u8 {
/// Used for Rainbow mode.
///
/// Enum corresponds to the required integer value
#[typeshare]
#[cfg_attr(
feature = "dbus",
derive(Type, Value, OwnedValue),
@@ -248,7 +249,6 @@ impl From<Direction> for i32 {
}
/// Enum of modes that convert to the actual number required by a USB HID packet
#[typeshare]
#[cfg_attr(
feature = "dbus",
derive(Type, Value, OwnedValue),
@@ -359,8 +359,13 @@ impl From<AuraEffect> for AuraModeNum {
}
}
#[cfg(feature = "dbus")]
impl zbus::zvariant::Basic for AuraModeNum {
const SIGNATURE_CHAR: char = 'u';
const SIGNATURE_STR: &'static str = "u";
}
/// Base effects have no zoning, while multizone is 1-4
#[typeshare]
#[cfg_attr(
feature = "dbus",
derive(Type, Value, OwnedValue),
@@ -432,7 +437,6 @@ impl From<AuraZone> for i32 {
/// ```rust
/// // let bytes: [u8; LED_MSG_LEN] = mode.into();
/// ```
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct AuraEffect {

View File

@@ -1,6 +1,5 @@
use log::warn;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[cfg(feature = "dbus")]
use zbus::zvariant::Type;
@@ -194,7 +193,6 @@ impl LedCode {
}
/// Represents the per-key raw USB packets
#[typeshare]
pub type AuraLaptopUsbPackets = Vec<Vec<u8>>;
/// A `UsbPackets` contains all data to change the full set of keyboard
@@ -204,7 +202,6 @@ pub type AuraLaptopUsbPackets = Vec<Vec<u8>>;
/// to the keyboard EC. One row controls one group of keys, these keys are not
/// necessarily all on the same row of the keyboard, with some splitting between
/// two rows.
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LedUsbPackets {

View File

@@ -5,7 +5,6 @@ use std::ops::{BitAnd, BitOr};
use log::warn;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[cfg(feature = "dbus")]
use zbus::zvariant::{OwnedValue, Type, Value};
@@ -16,7 +15,6 @@ use crate::{AuraDeviceType, PowerZones};
/// - 2021+, the struct is a single zone with 4 states
/// - pre-2021, the struct is 1 or 2 zones and 3 states
/// - Tuf, the struct is 1 zone and 3 states
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuraPowerState {
@@ -54,7 +52,9 @@ impl AuraPowerState {
fn tuf_to_bytes(&self) -> Vec<u8> {
// &cmd, &boot, &awake, &sleep, &keyboard
vec![1, self.boot as u8, self.awake as u8, self.sleep as u8, 1]
vec![
1, self.boot as u8, self.awake as u8, self.sleep as u8, 1,
]
}
/// # Bits for older 0x1866 keyboard model
@@ -106,46 +106,54 @@ impl AuraPowerState {
match self.zone {
PowerZones::Logo => {
self.boot as u32
| (self.awake as u32) << 2
| (self.sleep as u32) << 4
| (self.shutdown as u32) << 6
| ((self.awake as u32) << 2)
| ((self.sleep as u32) << 4)
| ((self.shutdown as u32) << 6)
}
PowerZones::Ally => {
(self.boot as u32)
| (self.awake as u32) << 1
| (self.sleep as u32) << 2
| (self.shutdown as u32) << 3
| ((self.awake as u32) << 1)
| ((self.sleep as u32) << 2)
| ((self.shutdown as u32) << 3)
}
PowerZones::Keyboard => {
(self.boot as u32) << 1
| (self.awake as u32) << 3
| (self.sleep as u32) << 5
| (self.shutdown as u32) << 7
((self.boot as u32) << 1)
| ((self.awake as u32) << 3)
| ((self.sleep as u32) << 5)
| ((self.shutdown as u32) << 7)
}
PowerZones::Lightbar => {
(self.boot as u32) << (7 + 2)
| (self.awake as u32) << (7 + 3)
| (self.sleep as u32) << (7 + 4)
| (self.shutdown as u32) << (7 + 5)
((self.awake as u32) << (7 + 1))
| ((self.boot as u32) << (7 + 2))
| ((self.awake as u32) << (7 + 3))
| ((self.sleep as u32) << (7 + 4))
| ((self.shutdown as u32) << (7 + 5))
}
PowerZones::Lid => {
(self.boot as u32) << (15 + 1)
| (self.awake as u32) << (15 + 2)
| (self.sleep as u32) << (15 + 3)
| (self.shutdown as u32) << (15 + 4)
((self.boot as u32) << (15 + 1))
| ((self.awake as u32) << (15 + 2))
| ((self.sleep as u32) << (15 + 3))
| ((self.shutdown as u32) << (15 + 4))
| ((self.boot as u32) << (15 + 5))
| ((self.awake as u32) << (15 + 6))
| ((self.sleep as u32) << (15 + 7))
| ((self.shutdown as u32) << (15 + 8))
}
PowerZones::RearGlow => {
(self.boot as u32) << (23 + 1)
| (self.awake as u32) << (23 + 2)
| (self.sleep as u32) << (23 + 3)
| (self.shutdown as u32) << (23 + 4)
((self.boot as u32) << (23 + 1))
| ((self.awake as u32) << (23 + 2))
| ((self.sleep as u32) << (23 + 3))
| ((self.shutdown as u32) << (23 + 4))
| ((self.boot as u32) << (23 + 5))
| ((self.awake as u32) << (23 + 6))
| ((self.sleep as u32) << (23 + 7))
| ((self.shutdown as u32) << (23 + 8))
}
PowerZones::None | PowerZones::KeyboardAndLightbar => 0,
}
}
}
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct LaptopAuraPower {
@@ -226,7 +234,13 @@ impl LaptopAuraPower {
pub fn to_bytes(&self, aura_type: AuraDeviceType) -> Vec<u8> {
if let Some(stuff) = self.states.first() {
if stuff.zone == PowerZones::Ally {
return vec![0x5d, 0xd1, 0x09, 0x01, stuff.new_to_byte() as u8];
return vec![
0x5d,
0xd1,
0x09,
0x01,
stuff.new_to_byte() as u8,
];
}
}
match aura_type {
@@ -321,26 +335,30 @@ mod test {
#[test]
fn check_0x1866_control_bytes() {
let power = LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
};
let bytes = power.to_bytes(AuraDeviceType::LaptopKeyboardPre2021);
println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]);
assert_eq!(bytes, [0x08, 0x00, 0x02, 0x00]);
let power = LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
};
let bytes = power.to_bytes(AuraDeviceType::LaptopKeyboardPre2021);
println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]);
@@ -379,184 +397,224 @@ mod test {
#[test]
fn check_0x19b6_control_bytes_binary_rep() {
let boot_logo_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Logo,
boot: true,
awake: false,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Logo,
boot: true,
awake: false,
sleep: false,
shutdown: false,
},
],
});
let boot_keyb_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Keyboard,
boot: true,
awake: false,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Keyboard,
boot: true,
awake: false,
sleep: false,
shutdown: false,
},
],
});
let sleep_logo = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Logo,
boot: false,
awake: false,
sleep: true,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Logo,
boot: false,
awake: false,
sleep: true,
shutdown: false,
},
],
});
let sleep_keyb = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: false,
sleep: true,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: false,
sleep: true,
shutdown: false,
},
],
});
let awake_logo = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Logo,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Logo,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
});
let awake_keyb = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
});
let shut_logo_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Logo,
boot: false,
awake: false,
sleep: false,
shutdown: true,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Logo,
boot: false,
awake: false,
sleep: false,
shutdown: true,
},
],
});
let shut_keyb_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: false,
sleep: false,
shutdown: true,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Keyboard,
boot: false,
awake: false,
sleep: false,
shutdown: true,
},
],
});
let boot_bar__ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lightbar,
boot: true,
awake: false,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lightbar,
boot: true,
awake: false,
sleep: false,
shutdown: false,
},
],
});
let awake_bar_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
});
let sleep_bar_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: false,
sleep: true,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: false,
sleep: true,
shutdown: false,
},
],
});
let shut_bar__ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: false,
sleep: false,
shutdown: true,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lightbar,
boot: false,
awake: false,
sleep: false,
shutdown: true,
},
],
});
let boot_lid__ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lid,
boot: true,
awake: false,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lid,
boot: true,
awake: false,
sleep: false,
shutdown: false,
},
],
});
let awake_lid_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lid,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lid,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
});
let sleep_lid_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lid,
boot: false,
awake: false,
sleep: true,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lid,
boot: false,
awake: false,
sleep: true,
shutdown: false,
},
],
});
let shut_lid__ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::Lid,
boot: false,
awake: false,
sleep: false,
shutdown: true,
}],
states: vec![
AuraPowerState {
zone: PowerZones::Lid,
boot: false,
awake: false,
sleep: false,
shutdown: true,
},
],
});
let boot_rear_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::RearGlow,
boot: true,
awake: false,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::RearGlow,
boot: true,
awake: false,
sleep: false,
shutdown: false,
},
],
});
let awake_rear = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::RearGlow,
boot: false,
awake: true,
sleep: false,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::RearGlow,
boot: false,
awake: true,
sleep: false,
shutdown: false,
},
],
});
let sleep_rear = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::RearGlow,
boot: false,
awake: false,
sleep: true,
shutdown: false,
}],
states: vec![
AuraPowerState {
zone: PowerZones::RearGlow,
boot: false,
awake: false,
sleep: true,
shutdown: false,
},
],
});
let shut_rear_ = to_binary_string_post2021(&LaptopAuraPower {
states: vec![AuraPowerState {
zone: PowerZones::RearGlow,
boot: false,
awake: false,
sleep: false,
shutdown: true,
}],
states: vec![
AuraPowerState {
zone: PowerZones::RearGlow,
boot: false,
awake: false,
sleep: false,
shutdown: true,
},
],
});
assert_eq!(boot_logo_, "00000001, 00000000, 00000000, 00000000");
@@ -569,19 +627,19 @@ mod test {
assert_eq!(shut_keyb_, "10000000, 00000000, 00000000, 00000000");
//
assert_eq!(boot_bar__, "00000000, 00000010, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000100, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000101, 00000000, 00000000");
assert_eq!(sleep_bar_, "00000000, 00001000, 00000000, 00000000");
assert_eq!(shut_bar__, "00000000, 00010000, 00000000, 00000000");
//
assert_eq!(boot_lid__, "00000000, 00000000, 00000001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00000010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 00000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 00001000, 00000000");
assert_eq!(boot_lid__, "00000000, 00000000, 00010001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00100010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 01000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 10001000, 00000000");
//
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00000001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00000010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 00000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 00001000");
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00010001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00100010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 01000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 10001000");
// All on
let byte1 = to_binary_string_post2021(&LaptopAuraPower {
@@ -608,6 +666,6 @@ mod test {
},
],
});
assert_eq!(byte1, "11111111, 00011110, 00001111, 00001111");
assert_eq!(byte1, "11111111, 00011111, 11111111, 11111111");
}
}

View File

@@ -6,7 +6,6 @@
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[cfg(feature = "dbus")]
use zbus::zvariant::{OwnedValue, Type, Value};
@@ -62,9 +61,10 @@ pub const ORANGE: Colour = Colour {
g: 0xa4,
b: 0x00,
};
pub const GRADIENT: [Colour; 7] = [RED, VIOLET, BLUE, TEAL, GREEN, YELLOW, ORANGE];
pub const GRADIENT: [Colour; 7] = [
RED, VIOLET, BLUE, TEAL, GREEN, YELLOW, ORANGE,
];
#[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AuraDeviceType {
@@ -106,17 +106,16 @@ impl From<&str> for AuraDeviceType {
match s.to_lowercase().trim_start_matches("0x") {
"tuf" => AuraDeviceType::LaptopKeyboardTuf,
"1932" => AuraDeviceType::ScsiExtDisk,
"1866" | "18c6" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1866" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1abe" | "1b4c" => Self::Ally,
"19b3" | "193b" => Self::AnimeOrSlash,
"19b6" => Self::LaptopKeyboard2021,
"19b6" | "1a30" | "18c6" => Self::LaptopKeyboard2021,
_ => Self::Unknown,
}
}
}
/// The powerr zones this laptop supports
#[typeshare]
#[cfg_attr(
feature = "dbus",
derive(Type, Value, OwnedValue),

View File

@@ -1,4 +1,7 @@
// Only these two packets must be 17 bytes
pub const AURA_LAPTOP_LED_APPLY: [u8; 17] =
[0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pub const AURA_LAPTOP_LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pub const AURA_LAPTOP_LED_APPLY: [u8; 17] = [
0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
pub const AURA_LAPTOP_LED_SET: [u8; 17] = [
0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];

View File

@@ -12,8 +12,9 @@ edition.workspace = true
default = []
mocking = []
x11 = ["slint/backend-winit-x11"]
# Requires RUSTFLAGS="--cfg tokio_unstable"
# Optional tokio debug feature does not require nightly; remove RUSTFLAGS note.
tokio-debug = ["console-subscriber"]
rog_ally = []
[dependencies]
console-subscriber = { version = "^0.4", optional = true }
@@ -41,6 +42,7 @@ zbus.workspace = true
dirs.workspace = true
notify-rust.workspace = true
concat-idents.workspace = true
futures-util.workspace = true
versions.workspace = true
@@ -48,12 +50,26 @@ versions.workspace = true
git = "https://github.com/slint-ui/slint.git"
default-features = false
features = [
"gettext",
"compat-1-2",
"gettext",
"backend-winit-wayland",
"renderer-winit-femtovg",
"renderer-femtovg",
# "renderer-skia-opengl",
]
[build-dependencies.slint-build]
git = "https://github.com/slint-ui/slint.git"
[package.metadata.deb]
license-file = ["../LICENSE", "4"]
extended-description = """\
The dbus server for asusctl and rog-control-center applications."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
["target/release/rog-control-center", "usr/bin/", "755"],
["../rog_gui-fakeinstall/usr/share/applications/*", "usr/share/share/applications/", "644"],
["../rog_gui-fakeinstall/usr/share/icons/hicolor/512x512/apps/*", "usr/share/icons/hicolor/512x512/apps", "644"],
["../rog_gui-fakeinstall/usr/share/icons/hicolor/scalable/status/*", "usr/share/icons/hicolor/scalable/status", "644"],
]

View File

@@ -5,7 +5,6 @@ use slint_build::CompilerConfiguration;
fn main() {
// write_locales();
let root = env!("CARGO_MANIFEST_DIR");
let mut main = PathBuf::from_str(root).unwrap();
main.push("ui/main_window.slint");
@@ -14,13 +13,12 @@ fn main() {
include.push("ui");
slint_build::print_rustc_flags().unwrap();
// slint_build::compile("ui/main_window.slint").unwrap();
slint_build::compile_with_config(
main,
CompilerConfiguration::new()
// .embed_resources(EmbedResourcesKind::EmbedFiles)
.with_include_paths(vec![include])
.with_style("fluent-dark".into()),
.with_style("fluent".into()),
)
.unwrap();
}

View File

@@ -1,7 +1,6 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=ROG Control Center
Comment=Make your ASUS ROG Laptop go Brrrrr!
Categories=Settings

View File

@@ -9,6 +9,7 @@ pub enum Error {
ConfigLockFail,
XdgVars,
Zbus(zbus::Error),
ZbusFdo(zbus::fdo::Error),
Notification(notify_rust::error::Error),
}
@@ -21,6 +22,7 @@ impl fmt::Display for Error {
Error::ConfigLockFail => write!(f, "Failed to lock user config"),
Error::XdgVars => write!(f, "XDG environment vars appear unset"),
Error::Zbus(err) => write!(f, "Error: {}", err),
Error::ZbusFdo(err) => write!(f, "Error: {}", err),
Error::Notification(err) => write!(f, "Notification Error: {}", err),
}
}
@@ -40,6 +42,12 @@ impl From<zbus::Error> for Error {
}
}
impl From<zbus::fdo::Error> for Error {
fn from(err: zbus::fdo::Error) -> Self {
Error::ZbusFdo(err)
}
}
impl From<notify_rust::error::Error> for Error {
fn from(err: notify_rust::error::Error) -> Self {
Error::Notification(err)

View File

@@ -15,7 +15,7 @@ pub mod notify;
pub mod tray;
pub mod types;
pub mod ui;
pub mod zbus;
pub mod zbus_proxies;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const APP_ICON_PATH: &str = "/usr/share/icons/hicolor/512x512/apps/rog-control-center.png";

View File

@@ -1,5 +1,4 @@
use std::borrow::BorrowMut;
use std::env::args;
use std::env::{self, args};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::{Arc, Mutex};
@@ -9,7 +8,7 @@ use std::time::Duration;
use config_traits::{StdConfig, StdConfigLoad1};
use dmi_id::DMIID;
use gumdrop::Options;
use log::{info, warn, LevelFilter};
use log::{debug, info, warn, LevelFilter};
use rog_control_center::cli_options::CliStart;
use rog_control_center::config::Config;
use rog_control_center::error::Result;
@@ -17,7 +16,7 @@ use rog_control_center::notify::start_notifications;
use rog_control_center::slint::ComponentHandle;
use rog_control_center::tray::init_tray;
use rog_control_center::ui::setup_window;
use rog_control_center::zbus::{
use rog_control_center::zbus_proxies::{
AppState, ROGCCZbus, ROGCCZbusProxyBlocking, ZBUS_IFACE, ZBUS_PATH,
};
use rog_control_center::{print_versions, MainWindow};
@@ -25,14 +24,37 @@ use tokio::runtime::Runtime;
#[tokio::main]
async fn main() -> Result<()> {
// Ensure tracing spans are quiet by default unless user overrides
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "warn,tracing=error,zbus=error");
}
let mut logger = env_logger::Builder::new();
logger
.filter_level(LevelFilter::Warn)
.parse_default_env()
.target(env_logger::Target::Stdout)
.filter_level(LevelFilter::Info)
.parse_default_env()
.target(env_logger::Target::Stderr)
.format_timestamp(None)
.init();
// If we're running under gamescope we have to set WAYLAND_DISPLAY for winit to
// use
if let Ok(gamescope) = env::var("GAMESCOPE_WAYLAND_DISPLAY") {
debug!("Gamescope detected");
if !gamescope.is_empty() {
debug!("Setting WAYLAND_DISPLAY to {}", gamescope);
env::set_var("WAYLAND_DISPLAY", gamescope);
}
// gamescope-0
else if let Ok(wayland) = env::var("WAYLAND_DISPLAY") {
debug!("Wayland display detected");
if wayland.is_empty() {
debug!("Setting WAYLAND_DISPLAY to gamescope-0");
env::set_var("WAYLAND_DISPLAY", "gamescope-0");
}
}
}
// Try to open a proxy and check for app state first
{
let user_con = zbus::blocking::Connection::session()?;
@@ -50,10 +72,15 @@ async fn main() -> Result<()> {
let self_version = env!("CARGO_PKG_VERSION");
let zbus_con = zbus::blocking::Connection::system()?;
let platform_proxy = rog_dbus::zbus_platform::PlatformProxyBlocking::new(&zbus_con)?;
let asusd_version = platform_proxy.version().unwrap();
let asusd_version = platform_proxy
.version()
.map_err(|e| {
println!("Could not get asusd version: {e:?}\nIs asusd.service running?");
})
.unwrap();
if asusd_version != self_version {
println!("Version mismatch: asusctl = {self_version}, asusd = {asusd_version}");
return Ok(());
// return Ok(());
}
// start tokio
@@ -80,7 +107,6 @@ async fn main() -> Result<()> {
let board_name = dmi.board_name;
let prod_family = dmi.product_family;
info!("Running on {board_name}, product: {prod_family}");
let is_rog_ally = prod_family == "RC71L";
let args: Vec<String> = args().skip(1).collect();
@@ -111,16 +137,32 @@ async fn main() -> Result<()> {
config.start_fullscreen = false;
}
let is_rog_ally = {
#[cfg(feature = "rog_ally")]
{
board_name == "RC71L" || board_name == "RC72L" || prod_family == "ROG Ally"
}
#[cfg(not(feature = "rog_ally"))]
{
false
}
};
let is_tuf = {
let b = board_name.to_lowercase();
let p = prod_family.to_lowercase();
b.contains("tuf") || p.contains("tuf")
};
#[cfg(feature = "rog_ally")]
if is_rog_ally {
config.notifications.enabled = false;
config.enable_tray_icon = false;
config.run_in_background = false;
config.startup_in_background = false;
config.start_fullscreen = true;
}
if config.startup_in_background {
config.run_in_background = true;
}
config.write();
let enable_tray_icon = config.enable_tray_icon;
@@ -137,8 +179,8 @@ async fn main() -> Result<()> {
// i_slint_backend_selector::with_platform(|_| Ok(())).unwrap();
if !startup_in_background {
if let Ok(mut lock) = app_state.lock() {
*lock = AppState::MainWindowShouldOpen;
if let Ok(mut app_state) = app_state.lock() {
*app_state = AppState::MainWindowShouldOpen;
}
}
@@ -151,22 +193,61 @@ async fn main() -> Result<()> {
slint::init_translations!(concat!(env!("CARGO_MANIFEST_DIR"), "/translations/"));
}
// Prefetch supported Aura modes once at startup and move into the
// spawned UI thread so the UI uses a stable, immutable list.
let prefetched_supported: std::sync::Arc<Option<Vec<i32>>> = std::sync::Arc::new(
rog_control_center::ui::setup_aura::prefetch_supported_basic_modes().await,
);
thread::spawn(move || {
let mut state = AppState::StartingUp;
loop {
// save as a var, don't hold the lock the entire time or deadlocks happen
if let Ok(lock) = app_state.lock() {
state = *lock;
if is_rog_ally {
let config_copy_2 = config.clone();
let newui = setup_window(config.clone(), prefetched_supported.clone(), is_tuf);
newui.window().on_close_requested(move || {
exit(0);
});
let ui_copy = newui.as_weak();
newui
.window()
.set_rendering_notifier(move |s, _| {
if let slint::RenderingState::BeforeRendering = s {
let config = config_copy_2.clone();
ui_copy
.upgrade_in_event_loop(move |w| {
let fullscreen =
config.lock().is_ok_and(|c| c.start_fullscreen);
if fullscreen && !w.window().is_fullscreen() {
w.window().set_fullscreen(fullscreen);
}
})
.ok();
}
})
.ok();
continue;
}
// save as a var, don't hold the lock the entire time or deadlocks happen
if let Ok(app_state) = app_state.lock() {
state = *app_state;
}
// This sleep is required to give the event loop time to react
sleep(Duration::from_millis(300));
if state == AppState::MainWindowShouldOpen {
if let Ok(mut lock) = app_state.lock() {
*lock = AppState::MainWindowOpen;
if let Ok(mut app_state) = app_state.lock() {
*app_state = AppState::MainWindowOpen;
}
sleep(Duration::from_millis(50));
let config_copy = config.clone();
let app_state_copy = app_state.clone();
// Avoid moving the original `prefetched_supported` into the
// closure — clone an Arc for the closure to capture.
let pref_for_invoke = prefetched_supported.clone();
slint::invoke_from_event_loop(move || {
UI.with(|ui| {
let app_state_copy = app_state_copy.clone();
@@ -174,20 +255,39 @@ async fn main() -> Result<()> {
if let Some(ui) = ui.as_mut() {
ui.window().show().unwrap();
ui.window().on_close_requested(move || {
if let Ok(mut lock) = app_state_copy.lock() {
*lock = AppState::MainWindowClosed;
if let Ok(mut app_state) = app_state_copy.lock() {
*app_state = AppState::MainWindowClosed;
}
slint::CloseRequestResponse::HideWindow
});
} else {
let newui = setup_window(config_copy);
newui.window().show().unwrap();
let config_copy_2 = config_copy.clone();
let newui = setup_window(config_copy, pref_for_invoke.clone(), is_tuf);
newui.window().on_close_requested(move || {
if let Ok(mut lock) = app_state_copy.lock() {
*lock = AppState::MainWindowClosed;
if let Ok(mut app_state) = app_state_copy.lock() {
*app_state = AppState::MainWindowClosed;
}
slint::CloseRequestResponse::HideWindow
});
let ui_copy = newui.as_weak();
newui
.window()
.set_rendering_notifier(move |s, _| {
if let slint::RenderingState::RenderingSetup = s {
let config = config_copy_2.clone();
ui_copy
.upgrade_in_event_loop(move |w| {
let fullscreen =
config.lock().is_ok_and(|c| c.start_fullscreen);
if fullscreen && !w.window().is_fullscreen() {
w.window().set_fullscreen(fullscreen);
}
})
.ok();
}
})
.ok();
ui.replace(newui);
}
});
@@ -197,24 +297,13 @@ async fn main() -> Result<()> {
slint::quit_event_loop().unwrap();
exit(0);
} else if state != AppState::MainWindowOpen {
if let Ok(lock) = config.lock() {
if !lock.run_in_background {
if let Ok(config) = config.lock() {
if !config.run_in_background {
slint::quit_event_loop().unwrap();
exit(0);
}
}
slint::invoke_from_event_loop(move || {
UI.with(|ui| {
let mut ui = ui.take();
if let Some(ui) = ui.borrow_mut() {
ui.window().hide().unwrap();
}
});
})
.unwrap();
}
sleep(Duration::from_millis(300));
}
});
@@ -223,42 +312,6 @@ async fn main() -> Result<()> {
Ok(())
}
// /// Bah.. the icon dosn't work on wayland anyway, but we'll leave it in for
// now. fn load_icon() -> IconData {
// let path = PathBuf::from(APP_ICON_PATH);
// let mut rgba = Vec::new();
// let mut height = 512;
// let mut width = 512;
// if path.exists() {
// if let Ok(data) = std::fs::read(path)
// .map_err(|e| error!("Error reading app icon: {e:?}"))
// .map_err(|e| error!("Error opening app icon: {e:?}"))
// {
// let data = std::io::Cursor::new(data);
// let decoder = png_pong::Decoder::new(data).unwrap().into_steps();
// let png_pong::Step { raster, delay: _ } =
// decoder.last().unwrap().unwrap();
// if let png_pong::PngRaster::Rgba8(ras) = raster {
// rgba = ras.as_u8_slice().to_vec();
// width = ras.width();
// height = ras.height();
// info!("Loaded app icon. Not actually supported in Wayland
// yet"); }
// }
// } else {
// error!("Missing {APP_ICON_PATH}");
// }
// IconData {
// height,
// width,
// rgba
//
//
// / }
// }
fn do_cli_help(parsed: &CliStart) -> bool {
if parsed.help {
println!("{}", CliStart::usage());

View File

@@ -125,10 +125,18 @@ impl Profile {
pub fn fan_curve_data(&self, _p: rog_profiles::Profile) -> Result<FanCurveSet> {
let mut curve = FanCurveSet::default();
curve.cpu.pwm = [30, 40, 60, 100, 140, 180, 200, 250];
curve.cpu.temp = [20, 30, 40, 50, 70, 80, 90, 100];
curve.gpu.pwm = [40, 80, 100, 140, 170, 200, 230, 250];
curve.gpu.temp = [20, 30, 40, 50, 70, 80, 90, 100];
curve.cpu.pwm = [
30, 40, 60, 100, 140, 180, 200, 250,
];
curve.cpu.temp = [
20, 30, 40, 50, 70, 80, 90, 100,
];
curve.gpu.pwm = [
40, 80, 100, 140, 170, 200, 230, 250,
];
curve.gpu.temp = [
20, 30, 40, 50, 70, 80, 90, 100,
];
Ok(curve)
}

View File

@@ -10,17 +10,12 @@ use std::sync::{Arc, Mutex};
use std::time::Duration;
use log::{debug, error, info, warn};
use notify_rust::{Hint, Notification, Timeout, Urgency};
use rog_dbus::zbus_platform::PlatformProxy;
use rog_platform::platform::GpuMode;
use notify_rust::{Hint, Notification, Timeout};
use rog_platform::power::AsusPower;
use serde::{Deserialize, Serialize};
use supergfxctl::actions::UserActionRequired as GfxUserAction;
use supergfxctl::pci_device::{GfxMode, GfxPower};
use supergfxctl::zbus_proxy::DaemonProxy as SuperProxy;
use supergfxctl::pci_device::GfxPower;
use tokio::runtime::Runtime;
use tokio::task::JoinHandle;
use zbus::export::futures_util::StreamExt;
use crate::config::Config;
use crate::error::Result;
@@ -117,26 +112,26 @@ pub fn start_notifications(
if p == 0 && p != last_state {
let prog: Vec<&str> = bat.split_whitespace().collect();
if prog.len() > 1 {
if (!prog.is_empty()) && (!prog[0].is_empty()) {
let mut cmd = Command::new(prog[0]);
for arg in prog.iter().skip(1) {
cmd.arg(*arg);
}
cmd.spawn()
.map_err(|e| error!("AC command error: {e:?}"))
.map_err(|e| error!("Battery power command error: {e:?}"))
.ok();
}
} else if p != last_state {
let prog: Vec<&str> = ac.split_whitespace().collect();
if prog.len() > 1 {
if (!prog.is_empty()) && (!prog[0].is_empty()) {
let mut cmd = Command::new(prog[0]);
for arg in prog.iter().skip(1) {
cmd.arg(*arg);
}
cmd.spawn()
.map_err(|e| error!("AC command error: {e:?}"))
.map_err(|e| error!("AC power command error: {e:?}"))
.ok();
}
}
@@ -146,129 +141,49 @@ pub fn start_notifications(
}
});
let enabled_notifications_copy = config.clone();
let no_supergfx = move |e: &zbus::Error| {
error!("zbus signal: receive_notify_gfx_status: {e}");
warn!("Attempting to start plain dgpu status monitor");
start_dpu_status_mon(enabled_notifications_copy.clone());
};
info!("Attempting to start plain dgpu status monitor");
start_dpu_status_mon(config.clone());
// GPU MUX Mode notif
let enabled_notifications_copy = config.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system().await.map_err(|e| {
error!("zbus signal: receive_notify_gpu_mux_mode: {e}");
e
})?;
let proxy = PlatformProxy::new(&conn).await.map_err(|e| {
error!("zbus signal: receive_notify_gpu_mux_mode: {e}");
e
})?;
// TODO: need to get armoury attrs and iter to find
// let enabled_notifications_copy = config.clone();
// tokio::spawn(async move {
// let conn = zbus::Connection::system().await.map_err(|e| {
// error!("zbus signal: receive_notify_gpu_mux_mode: {e}");
// e
// })?;
// let proxy = PlatformProxy::new(&conn).await.map_err(|e| {
// error!("zbus signal: receive_notify_gpu_mux_mode: {e}");
// e
// })?;
let mut actual_mux_mode = GpuMode::Error;
if let Ok(mode) = proxy.gpu_mux_mode().await {
actual_mux_mode = GpuMode::from(mode);
}
// let mut actual_mux_mode = GpuMode::Error;
// if let Ok(mode) = proxy.gpu_mux_mode().await {
// actual_mux_mode = GpuMode::from(mode);
// }
info!("Started zbus signal thread: receive_notify_gpu_mux_mode");
while let Some(e) = proxy.receive_gpu_mux_mode_changed().await.next().await {
if let Ok(config) = enabled_notifications_copy.lock() {
if !config.notifications.enabled || !config.notifications.receive_notify_gfx {
continue;
}
}
if let Ok(out) = e.get().await {
let mode = GpuMode::from(out);
if mode == actual_mux_mode {
continue;
}
do_mux_notification("Reboot required. BIOS GPU MUX mode set to", &mode).ok();
}
}
Ok::<(), zbus::Error>(())
});
let enabled_notifications_copy = config.clone();
// GPU Mode change/action notif
tokio::spawn(async move {
let conn = zbus::Connection::system().await.inspect_err(|e| {
no_supergfx(e);
})?;
let proxy = SuperProxy::builder(&conn).build().await.inspect_err(|e| {
no_supergfx(e);
})?;
let _ = proxy.mode().await.inspect_err(|e| {
no_supergfx(e);
})?;
let proxy_copy = proxy.clone();
let mut p = proxy.receive_notify_action().await?;
tokio::spawn(async move {
info!("Started zbus signal thread: receive_notify_action");
while let Some(e) = p.next().await {
if let Ok(out) = e.args() {
let action = out.action();
let mode = convert_gfx_mode(proxy.mode().await.unwrap_or_default());
match action {
supergfxctl::actions::UserActionRequired::Reboot => {
do_mux_notification("Graphics mode change requires reboot", &mode)
}
_ => do_gfx_action_notif(<&str>::from(action), *action, mode),
}
.map_err(|e| {
error!("zbus signal: do_gfx_action_notif: {e}");
e
})
.ok();
}
}
});
let mut p = proxy_copy.receive_notify_gfx_status().await?;
tokio::spawn(async move {
info!("Started zbus signal thread: receive_notify_gfx_status");
let mut last_status = GfxPower::Unknown;
while let Some(e) = p.next().await {
if let Ok(out) = e.args() {
let status = out.status;
if status != GfxPower::Unknown && status != last_status {
if let Ok(config) = enabled_notifications_copy.lock() {
if !config.notifications.receive_notify_gfx_status
|| !config.notifications.enabled
{
continue;
}
}
// Required check because status cycles through
// active/unknown/suspended
do_gpu_status_notif("dGPU status changed:", &status)
.show_async()
.await
.unwrap()
.on_close(|_| ());
}
last_status = status;
}
}
});
Ok::<(), zbus::Error>(())
});
// info!("Started zbus signal thread: receive_notify_gpu_mux_mode");
// while let Some(e) =
// proxy.receive_gpu_mux_mode_changed().await.next().await { if let
// Ok(config) = enabled_notifications_copy.lock() { if
// !config.notifications.enabled || !config.notifications.receive_notify_gfx {
// continue;
// }
// }
// if let Ok(out) = e.get().await {
// let mode = GpuMode::from(out);
// if mode == actual_mux_mode {
// continue;
// }
// do_mux_notification("Reboot required. BIOS GPU MUX mode set to",
// &mode).ok(); }
// }
// Ok::<(), zbus::Error>(())
// });
Ok(vec![blocking])
}
fn convert_gfx_mode(gfx: GfxMode) -> GpuMode {
match gfx {
GfxMode::Hybrid => GpuMode::Optimus,
GfxMode::Integrated => GpuMode::Integrated,
GfxMode::NvidiaNoModeset => GpuMode::Optimus,
GfxMode::Vfio => GpuMode::Vfio,
GfxMode::AsusEgpu => GpuMode::Egpu,
GfxMode::AsusMuxDgpu => GpuMode::Ultimate,
GfxMode::None => GpuMode::Error,
}
}
fn base_notification<T>(message: &str, data: &T) -> Notification
where
T: Display,
@@ -294,91 +209,3 @@ fn do_gpu_status_notif(message: &str, data: &GfxPower) -> Notification {
notif.icon(icon);
notif
}
fn do_gfx_action_notif(message: &str, action: GfxUserAction, mode: GpuMode) -> Result<()> {
if matches!(action, GfxUserAction::Reboot) {
do_mux_notification("Graphics mode change requires reboot", &mode).ok();
return Ok(());
}
let mut notif = Notification::new();
notif
.appname(NOTIF_HEADER)
.summary(&format!("Changing to {mode}. {message}"))
//.hint(Hint::Resident(true))
.hint(Hint::Category("device".into()))
.urgency(Urgency::Critical)
.timeout(Timeout::Never)
.icon("dialog-warning")
.hint(Hint::Transient(true));
if matches!(action, GfxUserAction::Logout) {
notif.action("gfx-mode-session-action", "Logout");
let handle = notif.show()?;
if let Ok(desktop) = std::env::var("XDG_CURRENT_DESKTOP") {
if desktop.to_lowercase() == "gnome" {
handle.wait_for_action(|id| {
if id == "gfx-mode-session-action" {
let mut cmd = Command::new("gnome-session-quit");
cmd.spawn().ok();
} else if id == "__closed" {
// TODO: cancel the switching
}
});
} else if desktop.to_lowercase() == "kde" {
handle.wait_for_action(|id| {
if id == "gfx-mode-session-action" {
let mut cmd = Command::new("qdbus");
cmd.args(["org.kde.ksmserver", "/KSMServer", "logout", "1", "0", "0"]);
cmd.spawn().ok();
} else if id == "__closed" {
// TODO: cancel the switching
}
});
} else {
// todo: handle alternatives
}
}
} else {
notif.show()?;
}
Ok(())
}
/// Actual `GpuMode` unused as data is never correct until switched by reboot
fn do_mux_notification(message: &str, m: &GpuMode) -> Result<()> {
let mut notif = base_notification(message, &m.to_string());
notif
.action("gfx-mode-session-action", "Reboot")
.urgency(Urgency::Critical)
.icon("system-reboot-symbolic")
.hint(Hint::Transient(true));
let handle = notif.show()?;
std::thread::spawn(|| {
if let Ok(desktop) = std::env::var("XDG_CURRENT_DESKTOP") {
if desktop.to_lowercase() == "gnome" {
handle.wait_for_action(|id| {
if id == "gfx-mode-session-action" {
let mut cmd = Command::new("gnome-session-quit");
cmd.arg("--reboot");
cmd.spawn().ok();
} else if id == "__closed" {
// TODO: cancel the switching
}
});
} else if desktop.to_lowercase() == "kde" {
handle.wait_for_action(|id| {
if id == "gfx-mode-session-action" {
let mut cmd = Command::new("qdbus");
cmd.args(["org.kde.ksmserver", "/KSMServer", "logout", "1", "1", "0"]);
cmd.spawn().ok();
} else if id == "__closed" {
// TODO: cancel the switching
}
});
}
}
});
Ok(())
}

View File

@@ -14,7 +14,7 @@ use supergfxctl::zbus_proxy::DaemonProxy as GfxProxy;
use versions::Versioning;
use crate::config::Config;
use crate::zbus::{AppState, ROGCCZbusProxyBlocking};
use crate::zbus_proxies::{AppState, ROGCCZbusProxyBlocking};
const TRAY_LABEL: &str = "ROG Control Center";
const TRAY_ICON_PATH: &str = "/usr/share/icons/hicolor/512x512/apps/";
@@ -32,7 +32,10 @@ static ICONS: OnceLock<Icons> = OnceLock::new();
fn read_icon(file: &Path) -> Icon {
let mut path = PathBuf::from(TRAY_ICON_PATH);
path.push(file);
let mut file = OpenOptions::new().read(true).open(path).unwrap();
let mut file = OpenOptions::new()
.read(true)
.open(&path)
.unwrap_or_else(|_| panic!("Missing icon: {:?}", path));
let mut bytes = Vec::new();
file.read_to_end(&mut bytes).unwrap();
@@ -127,7 +130,6 @@ async fn set_tray_icon_and_tip(
};
tray.update(|tray: &mut AsusTray| {
dbg!(power);
tray.current_icon = icon;
tray.current_title = format!(
"ROG: gpu mode = {mode:?}, gpu power =
@@ -160,21 +162,23 @@ pub fn init_tray(_supported_properties: Vec<Properties>, config: Arc<Mutex<Confi
let rog_red = read_icon(&PathBuf::from("asus_notif_red.png"));
let tray = AsusTray {
let tray_init = AsusTray {
current_title: TRAY_LABEL.to_string(),
current_icon: rog_red.clone(),
proxy,
};
let mut tray = tray
.spawn_without_dbus_name()
.await
.map_err(|e| {
// TODO: return an error to the UI
let mut tray;
match tray_init.disable_dbus_name(true).spawn().await {
Ok(t) => tray = t,
Err(e) => {
log::error!(
"Tray unable to be initialised: {e:?}. Do you have a system tray enabled?"
)
})
.unwrap();
);
return;
}
}
info!("Tray started");
let rog_blue = read_icon(&PathBuf::from("asus_notif_blue.png"));
@@ -207,7 +211,15 @@ pub fn init_tray(_supported_properties: Vec<Properties>, config: Arc<Mutex<Confi
}
}
}
Err(e) => warn!("Couldn't get mode form supergfxd: {e:?}"),
Err(e) => match e {
zbus::Error::MethodError(_, _, message) => {
warn!(
"Couldn't get mode from supergfxd: {message:?}, the supergfxd service \
may not be running or installed"
)
}
_ => warn!("Couldn't get mode from supergfxd: {e:?}"),
},
}
info!("Started ROGTray");

View File

@@ -1,24 +1,28 @@
use rog_platform::platform::ThrottlePolicy;
use rog_platform::platform::PlatformProfile;
use rog_profiles::FanCurvePU;
use crate::{FanType, Profile};
impl From<Profile> for ThrottlePolicy {
impl From<Profile> for PlatformProfile {
fn from(value: Profile) -> Self {
match value {
Profile::Balanced => ThrottlePolicy::Balanced,
Profile::Performance => ThrottlePolicy::Performance,
Profile::Quiet => ThrottlePolicy::Quiet,
Profile::Balanced => PlatformProfile::Balanced,
Profile::Performance => PlatformProfile::Performance,
Profile::Quiet => PlatformProfile::Quiet,
Profile::LowPower => PlatformProfile::LowPower,
Profile::Custom => PlatformProfile::Custom,
}
}
}
impl From<ThrottlePolicy> for Profile {
fn from(value: ThrottlePolicy) -> Self {
impl From<PlatformProfile> for Profile {
fn from(value: PlatformProfile) -> Self {
match value {
ThrottlePolicy::Balanced => Profile::Balanced,
ThrottlePolicy::Performance => Profile::Performance,
ThrottlePolicy::Quiet => Profile::Quiet,
PlatformProfile::Balanced => Profile::Balanced,
PlatformProfile::Performance => Profile::Performance,
PlatformProfile::Quiet => Profile::Quiet,
PlatformProfile::LowPower => Profile::LowPower,
PlatformProfile::Custom => Profile::Custom,
}
}
}

View File

@@ -1,13 +1,19 @@
pub mod setup_anime;
pub mod setup_aura;
pub mod setup_fans;
pub mod setup_gpu;
pub mod setup_system;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;
static TOAST_SEQ: AtomicU64 = AtomicU64::new(0);
use config_traits::StdConfig;
use log::warn;
use rog_dbus::list_iface_blocking;
use slint::{ComponentHandle, PhysicalSize, SharedString, Weak};
use slint::{ComponentHandle, SharedString, Weak};
use crate::config::Config;
use crate::ui::setup_anime::setup_anime_page;
@@ -16,21 +22,6 @@ use crate::ui::setup_fans::setup_fan_curve_page;
use crate::ui::setup_system::{setup_system_page, setup_system_page_callbacks};
use crate::{AppSettingsPageData, MainWindow};
// This macro expects are consistent naming between proxy calls and slint
// globals
#[macro_export]
macro_rules! set_ui_props_async {
($ui:ident, $proxy:ident, $global:ident, $proxy_fn:ident) => {
if let Ok(value) = $proxy.$proxy_fn().await {
$ui.upgrade_in_event_loop(move |handle| {
concat_idents::concat_idents!(set = set_, $proxy_fn {
handle.global::<$global>().set(value.into());
});
}).ok();
}
};
}
// this macro sets up:
// - a link from UI callback -> dbus proxy property
// - a link from dbus property signal -> UI state
@@ -41,7 +32,7 @@ macro_rules! set_ui_callbacks {
let handle_copy = $handle.as_weak();
let proxy_copy = $proxy.clone();
let data = $handle.global::<$data>();
concat_idents::concat_idents!(on_set = on_set_, $proxy_fn {
concat_idents::concat_idents!(on_set = on_cb_, $proxy_fn {
data.on_set(move |value| {
let proxy_copy = proxy_copy.clone();
let handle_copy = handle_copy.clone();
@@ -64,7 +55,7 @@ macro_rules! set_ui_callbacks {
tokio::spawn(async move {
let mut x = proxy_copy.receive().await;
concat_idents::concat_idents!(set = set_, $proxy_fn {
use zbus::export::futures_util::StreamExt;
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
handle_copy.upgrade_in_event_loop(move |handle| {
@@ -84,40 +75,77 @@ pub fn show_toast(
handle: Weak<MainWindow>,
result: zbus::Result<()>,
) {
// bump sequence so that any previously spawned timers won't clear newer toasts
let seq = TOAST_SEQ.fetch_add(1, Ordering::SeqCst) + 1;
match result {
Ok(_) => {
slint::invoke_from_event_loop(move || handle.unwrap().invoke_show_toast(success)).ok()
let delayed_handle = handle.clone();
let delayed_text = success.clone();
slint::invoke_from_event_loop(move || handle.unwrap().invoke_show_toast(success)).ok();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(5)).await;
if TOAST_SEQ.load(Ordering::SeqCst) == seq {
slint::invoke_from_event_loop(move || {
delayed_handle
.unwrap()
.invoke_clear_toast_if_matches(delayed_text)
})
.ok();
}
});
}
Err(e) => {
let delayed_handle = handle.clone();
let delayed_text = fail.clone();
slint::invoke_from_event_loop(move || {
log::warn!("{fail}: {e}");
handle.unwrap().invoke_show_toast(fail)
})
.ok();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(5)).await;
if TOAST_SEQ.load(Ordering::SeqCst) == seq {
slint::invoke_from_event_loop(move || {
delayed_handle
.unwrap()
.invoke_clear_toast_if_matches(delayed_text)
})
.ok();
}
});
}
Err(e) => slint::invoke_from_event_loop(move || {
log::warn!("{fail}: {e}");
handle.unwrap().invoke_show_toast(fail)
})
.ok(),
};
}
pub fn setup_window(config: Arc<Mutex<Config>>) -> MainWindow {
let ui = MainWindow::new().unwrap();
if let Ok(lock) = config.try_lock() {
let fullscreen = lock.start_fullscreen;
let width = lock.fullscreen_width;
let height = lock.fullscreen_height;
if fullscreen {
ui.window().set_fullscreen(fullscreen);
ui.window().set_size(PhysicalSize { width, height });
}
};
pub fn setup_window(
config: Arc<Mutex<Config>>,
prefetched_supported: std::sync::Arc<Option<Vec<i32>>>,
is_tuf: bool,
) -> MainWindow {
slint::set_xdg_app_id("rog-control-center")
.map_err(|e| warn!("Couldn't set application ID: {e:?}"))
.ok();
let ui = MainWindow::new()
.map_err(|e| warn!("Couldn't create main window: {e:?}"))
.unwrap();
// propagate TUF flag to the UI so the sidebar can swap logo branding
ui.set_is_tuf(is_tuf);
ui.window()
.show()
.map_err(|e| warn!("Couldn't show main window: {e:?}"))
.unwrap();
let available = list_iface_blocking().unwrap_or_default();
ui.set_sidebar_items_avilable(
[
// Needs to match the order of slint sidebar items
available.contains(&"org.asuslinux.Platform".to_string()),
available.contains(&"org.asuslinux.Aura".to_string()),
available.contains(&"org.asuslinux.Anime".to_string()),
available.contains(&"org.asuslinux.FanCurves".to_string()),
true,
true,
available.contains(&"xyz.ljones.Platform".to_string()),
available.contains(&"xyz.ljones.Aura".to_string()),
available.contains(&"xyz.ljones.Anime".to_string()),
available.contains(&"xyz.ljones.FanCurves".to_string()),
true, // GPU Configuration
true, // App Settings
true, // About
]
.into(),
);
@@ -127,19 +155,23 @@ pub fn setup_window(config: Arc<Mutex<Config>>) -> MainWindow {
});
setup_app_settings_page(&ui, config.clone());
if available.contains(&"org.asuslinux.Platform".to_string()) {
if available.contains(&"xyz.ljones.Platform".to_string()) {
setup_system_page(&ui, config.clone());
setup_system_page_callbacks(&ui, config.clone());
}
if available.contains(&"org.asuslinux.Aura".to_string()) {
setup_aura_page(&ui, config.clone());
if available.contains(&"xyz.ljones.Aura".to_string()) {
setup_aura_page(&ui, config.clone(), prefetched_supported.as_ref().clone());
}
if available.contains(&"org.asuslinux.Anime".to_string()) {
if available.contains(&"xyz.ljones.Anime".to_string()) {
setup_anime_page(&ui, config.clone());
}
if available.contains(&"org.asuslinux.FanCurves".to_string()) {
setup_fan_curve_page(&ui, config);
if available.contains(&"xyz.ljones.FanCurves".to_string()) {
setup_fan_curve_page(&ui, config.clone());
}
// Populate GPU page choices and callbacks
setup_gpu::setup_gpu_page(&ui);
ui
}

View File

@@ -1,7 +1,8 @@
use std::sync::{Arc, Mutex};
use log::{error, info, warn};
use log::{error, info};
use rog_anime::Animations;
use rog_dbus::find_iface_async;
use rog_dbus::zbus_anime::AnimeProxy;
use slint::ComponentHandle;
@@ -12,124 +13,123 @@ use crate::{set_ui_callbacks, set_ui_props_async, AnimePageData, MainWindow};
pub fn setup_anime_page(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
let handle = ui.as_weak();
tokio::spawn(async move {
let Ok(conn) = zbus::Connection::system().await.map_err(|e| warn!("{e:}")) else {
return;
};
let Ok(anime) = AnimeProxy::new(&conn).await.map_err(|e| warn!("{e:}")) else {
info!("This device may not have an AniMe. If not then the error can be ignored");
let Ok(animes) = find_iface_async::<AnimeProxy>("xyz.ljones.Anime").await else {
info!("This device appears to have no aura interfaces");
return;
};
set_ui_props_async!(handle, anime, AnimePageData, brightness);
set_ui_props_async!(handle, anime, AnimePageData, builtins_enabled);
set_ui_props_async!(handle, anime, AnimePageData, enable_display);
set_ui_props_async!(handle, anime, AnimePageData, off_when_lid_closed);
set_ui_props_async!(handle, anime, AnimePageData, off_when_suspended);
set_ui_props_async!(handle, anime, AnimePageData, off_when_unplugged);
for anime in animes {
set_ui_props_async!(handle, anime, AnimePageData, brightness);
set_ui_props_async!(handle, anime, AnimePageData, builtins_enabled);
set_ui_props_async!(handle, anime, AnimePageData, enable_display);
set_ui_props_async!(handle, anime, AnimePageData, off_when_lid_closed);
set_ui_props_async!(handle, anime, AnimePageData, off_when_suspended);
set_ui_props_async!(handle, anime, AnimePageData, off_when_unplugged);
let builtins = anime.builtin_animations().await.unwrap_or_default();
handle
.upgrade_in_event_loop(move |handle| {
{
let global = handle.global::<AnimePageData>();
global.set_boot_anim(builtins.boot as i32);
global.set_awake_anim(builtins.awake as i32);
global.set_sleep_anim(builtins.sleep as i32);
global.set_shutdown_anim(builtins.shutdown as i32);
let builtins = anime.builtin_animations().await.unwrap_or_default();
handle
.upgrade_in_event_loop(move |handle| {
{
let global = handle.global::<AnimePageData>();
global.set_boot_anim(builtins.boot as i32);
global.set_awake_anim(builtins.awake as i32);
global.set_sleep_anim(builtins.sleep as i32);
global.set_shutdown_anim(builtins.shutdown as i32);
let handle_copy = handle.as_weak();
let anime_copy = anime.clone();
global.on_set_builtin_animations(move |boot, awake, sleep, shutdown| {
let handle_copy = handle_copy.clone();
let anime_copy = anime_copy.clone();
tokio::spawn(async move {
show_toast(
"Anime builtin animations changed".into(),
"Failed to set Anime builtin animations".into(),
handle_copy,
anime_copy
.set_builtin_animations(Animations {
boot: boot.into(),
awake: awake.into(),
sleep: sleep.into(),
shutdown: shutdown.into(),
})
.await,
);
let handle_copy = handle.as_weak();
let anime_copy = anime.clone();
global.on_cb_builtin_animations(move |boot, awake, sleep, shutdown| {
let handle_copy = handle_copy.clone();
let anime_copy = anime_copy.clone();
tokio::spawn(async move {
show_toast(
"Anime builtin animations changed".into(),
"Failed to set Anime builtin animations".into(),
handle_copy,
anime_copy
.set_builtin_animations(Animations {
boot: boot.into(),
awake: awake.into(),
sleep: sleep.into(),
shutdown: shutdown.into(),
})
.await,
);
});
});
});
let handle_copy = handle.as_weak();
let anime_copy = anime.clone();
tokio::spawn(async move {
let mut x = anime_copy.receive_builtin_animations_changed().await;
use zbus::export::futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
handle_copy
.upgrade_in_event_loop(move |handle| {
handle
.global::<AnimePageData>()
.set_boot_anim(out.boot.into());
handle
.global::<AnimePageData>()
.set_awake_anim(out.awake.into());
handle
.global::<AnimePageData>()
.set_sleep_anim(out.sleep.into());
handle
.global::<AnimePageData>()
.set_shutdown_anim(out.shutdown.into());
})
.ok();
let handle_copy = handle.as_weak();
let anime_copy = anime.clone();
tokio::spawn(async move {
let mut x = anime_copy.receive_builtin_animations_changed().await;
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
handle_copy
.upgrade_in_event_loop(move |handle| {
handle
.global::<AnimePageData>()
.set_boot_anim(out.boot.into());
handle
.global::<AnimePageData>()
.set_awake_anim(out.awake.into());
handle
.global::<AnimePageData>()
.set_sleep_anim(out.sleep.into());
handle
.global::<AnimePageData>()
.set_shutdown_anim(out.shutdown.into());
})
.ok();
}
}
}
});
}
});
}
set_ui_callbacks!(handle,
AnimePageData(.into()),
anime.brightness(.into()),
"Anime LED brightness successfully set to {}",
"Setting Anime LED brightness failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.builtins_enabled(),
"Keyboard LED mode successfully set to {}",
"Setting keyboard LEDmode failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.enable_display(),
"Anime display successfully set to {}",
"Setting Anime display failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.off_when_lid_closed(),
"Anime off_when_lid_closed successfully set to {}",
"Setting Anime off_when_lid_closed failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.off_when_suspended(),
"Anime off_when_suspended successfully set to {}",
"Setting Anime off_when_suspended failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.off_when_unplugged(),
"Anime off_when_unplugged successfully set to {}",
"Setting Anime off_when_unplugged failed"
);
})
.map_err(|e| error!("setup_anime_page: upgrade_in_event_loop: {e:?}"))
.ok();
set_ui_callbacks!(handle,
AnimePageData(.into()),
anime.brightness(.into()),
"Anime LED brightness successfully set to {}",
"Setting Anime LED brightness failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.builtins_enabled(),
"Keyboard LED mode successfully set to {}",
"Setting keyboard LEDmode failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.enable_display(),
"Anime display successfully set to {}",
"Setting Anime display failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.off_when_lid_closed(),
"Anime off_when_lid_closed successfully set to {}",
"Setting Anime off_when_lid_closed failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.off_when_suspended(),
"Anime off_when_suspended successfully set to {}",
"Setting Anime off_when_suspended failed"
);
set_ui_callbacks!(
handle,
AnimePageData(),
anime.off_when_unplugged(),
"Anime off_when_unplugged successfully set to {}",
"Setting Anime off_when_unplugged failed"
);
})
.map_err(|e| error!("setup_anime_page: upgrade_in_event_loop: {e:?}"))
.ok();
}
});
}

View File

@@ -34,63 +34,103 @@ fn decode_hex(s: &str) -> RgbaColor<u8> {
}
}
/// Returns the first available Aura interface
// TODO: return all
async fn find_aura_iface() -> Result<AuraProxy<'static>, Box<dyn std::error::Error>> {
let conn = zbus::Connection::system().await?;
let f = zbus::fdo::ObjectManagerProxy::new(&conn, "org.asuslinux.Daemon", "/").await?;
let interfaces = f.get_managed_objects().await?;
let mut aura_paths = Vec::new();
for v in interfaces.iter() {
for k in v.1.keys() {
if k.as_str() == "org.asuslinux.Aura" {
println!("Found aura device at {}, {}", v.0, k);
aura_paths.push(v.0.clone());
}
}
let mgr = zbus::fdo::ObjectManagerProxy::new(&conn, "xyz.ljones.Asusd", "/").await?;
let objs = mgr.get_managed_objects().await?;
let mut paths: Vec<zbus::zvariant::OwnedObjectPath> = objs
.iter()
.filter(|(_, ifaces)| ifaces.keys().any(|k| k.as_str() == "xyz.ljones.Aura"))
.map(|(p, _)| p.clone())
.collect();
if paths.len() > 1 {
log::debug!("Multiple aura devices: {paths:?}");
}
if aura_paths.len() > 1 {
println!("Multiple aura devices found: {aura_paths:?}");
println!("TODO: enable selection");
}
if let Some(path) = aura_paths.first() {
return Ok(AuraProxy::builder(&conn)
.path(path.clone())?
.destination("org.asuslinux.Daemon")?
.build()
.await?);
}
Err("No Aura interface".into())
let path = paths.pop().ok_or("No Aura interface")?;
AuraProxy::builder(&conn)
.path(path)?
.destination("xyz.ljones.Asusd")?
.build()
.await
.map_err(Into::into)
}
pub fn setup_aura_page(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
ui.global::<AuraPageData>().on_set_hex_from_colour(|c| {
pub async fn prefetch_supported_basic_modes() -> Option<Vec<i32>> {
let proxy = find_aura_iface().await.ok()?;
let modes = proxy.supported_basic_modes().await.ok()?;
Some(modes.iter().map(|n| (*n).into()).collect())
}
pub fn setup_aura_page(
ui: &MainWindow,
_states: Arc<Mutex<Config>>,
prefetched_supported: Option<Vec<i32>>,
) {
let g = ui.global::<AuraPageData>();
g.on_cb_hex_from_colour(|c| {
format!("#{:02X}{:02X}{:02X}", c.red(), c.green(), c.blue()).into()
});
ui.global::<AuraPageData>()
.on_set_hex_to_colour(|s| decode_hex(s.as_str()).into());
g.on_cb_hex_to_colour(|s| decode_hex(s.as_str()).into());
let handle = ui.as_weak();
tokio::spawn(async move {
let Ok(aura) = find_aura_iface().await else {
info!("This device appears to have no aura interfaces");
info!("No aura interfaces");
return Ok::<(), zbus::Error>(());
};
set_ui_props_async!(handle, aura, AuraPageData, brightness);
set_ui_props_async!(handle, aura, AuraPageData, led_mode);
set_ui_props_async!(handle, aura, AuraPageData, led_mode_data);
set_ui_props_async!(handle, aura, AuraPageData, led_power);
set_ui_props_async!(handle, aura, AuraPageData, device_type);
let modes_vec: Vec<i32> = match prefetched_supported {
Some(p) => p,
None => aura
.supported_basic_modes()
.await
.ok()
.map(|m| m.iter().map(|n| (*n).into()).collect())
.unwrap_or_default(),
};
// Restore saved mode, colours, zone, speed, direction from asusd (persisted to disk).
// Use effect.mode as single source — avoid led_mode() which can fail (try_lock).
let restore = aura.led_mode_data().await.ok();
let raw_mode: Option<i32> = restore.as_ref().map(|d| d.mode.into());
let d_slint = restore.map(|d| d.into());
handle
.upgrade_in_event_loop(move |h| {
let names = h.global::<AuraPageData>().get_mode_names();
let mut raws = Vec::new();
let mut mode_names = Vec::new();
for (i, name) in names.iter().enumerate() {
let raw = i as i32;
if modes_vec.contains(&raw) && i != 9 {
raws.push(raw);
mode_names.push(name.clone());
}
}
h.global::<AuraPageData>()
.set_supported_basic_modes(raws.as_slice().into());
h.global::<AuraPageData>()
.set_available_mode_names(mode_names.as_slice().into());
if let Some(d) = d_slint {
h.global::<AuraPageData>().invoke_update_led_mode_data(d);
if let Some(cm) = raw_mode {
let idx = raws.iter().position(|&r| r == cm).unwrap_or(0) as i32;
h.global::<AuraPageData>().set_current_available_mode(idx);
}
h.invoke_external_colour_change();
}
})
.map_err(|e| error!("{e}"))
.ok();
if let Ok(mut pow3r) = aura.supported_power_zones().await {
let dev_type = aura
let dev = aura
.device_type()
.await
.unwrap_or(AuraDeviceType::LaptopKeyboard2021);
log::debug!("Available LED power modes {pow3r:?}");
handle
.upgrade_in_event_loop(move |handle| {
let names: Vec<SharedString> = handle
@@ -98,135 +138,103 @@ pub fn setup_aura_page(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
.get_power_zone_names()
.iter()
.collect();
if dev_type.is_old_laptop() {
// Need to add the specific KeyboardAndLightbar
if dev.is_old_laptop() {
if pow3r.contains(&PowerZones::Keyboard)
&& pow3r.contains(&PowerZones::Lightbar)
{
pow3r.push(PowerZones::KeyboardAndLightbar);
}
let names: Vec<SharedString> =
pow3r.iter().map(|n| names[(*n) as usize].clone()).collect();
let n: Vec<SharedString> =
pow3r.iter().map(|z| names[(*z) as usize].clone()).collect();
handle
.global::<AuraPageData>()
.set_power_zone_names_old(names.as_slice().into());
.set_power_zone_names_old(n.as_slice().into());
} else {
let power: Vec<SlintPowerZones> =
pow3r.iter().map(|p| (*p).into()).collect();
let p: Vec<SlintPowerZones> = pow3r.iter().map(|z| (*z).into()).collect();
handle
.global::<AuraPageData>()
.set_supported_power_zones(power.as_slice().into());
.set_supported_power_zones(p.as_slice().into());
}
})
.ok();
}
if let Ok(modes) = aura.supported_basic_modes().await {
log::debug!("Available LED modes {modes:?}");
handle
.upgrade_in_event_loop(move |handle| {
let m: Vec<i32> = modes.iter().map(|n| (*n).into()).collect();
handle
.global::<AuraPageData>()
.set_supported_basic_modes(m.as_slice().into());
// Get the translated names
let names = handle.global::<AuraPageData>().get_mode_names();
let res: Vec<SharedString> = names
.iter()
.enumerate()
.filter(|(n, _)| modes.contains(&(*n as i32).into()) && *n != 9)
.map(|(_, i)| i)
.collect();
handle
.global::<AuraPageData>()
.set_available_mode_names(res.as_slice().into());
})
.map_err(|e| error!("{e:}"))
.ok();
}
let proxy_copy = aura.clone();
let proxy = aura.clone();
let weak = handle.clone();
handle
.upgrade_in_event_loop(move |handle| {
set_ui_callbacks!(handle,
.upgrade_in_event_loop(move |h| {
set_ui_callbacks!(h,
AuraPageData(.into()),
proxy_copy.brightness(.into()),
"Keyboard LED brightness successfully set to {}",
"Setting keyboard LED brightness failed"
proxy.brightness(.into()),
"Brightness set to {}",
"Brightness failed"
);
set_ui_callbacks!(handle,
AuraPageData(.into()),
proxy_copy.led_mode(.into()),
"Keyboard LED mode successfully set to {}",
"Setting keyboard LEDmode failed"
);
set_ui_callbacks!(handle,
AuraPageData(.into()),
proxy_copy.led_mode_data(.into()),
"Keyboard LED mode set to {:?}",
"Setting keyboard LED mode failed"
);
// set_ui_callbacks!(handle,
// AuraPageData(.clone().into()),
// proxy_copy.led_power(.into()),
// "Keyboard LED power successfully set to {:?}",
// "Setting keyboard power failed"
// );
handle.invoke_external_colour_change();
})
.ok();
let handle_copy = handle.clone();
let proxy_copy = aura.clone();
handle
.upgrade_in_event_loop(|handle| {
handle
.global::<AuraPageData>()
.on_set_led_power(move |power| {
let handle_copy = handle_copy.clone();
let proxy_copy = aura.clone();
let power: LaptopAuraPower = power.into();
tokio::spawn(async move {
show_toast(
"Aura power settings changed".into(),
"Failed to set Aura power settings".into(),
handle_copy,
proxy_copy.set_led_power(power).await,
);
});
let p = proxy.clone();
let w = weak.clone();
h.global::<AuraPageData>().on_apply_led_mode_data(move || {
let Some(ui) = w.upgrade() else { return };
let slint_effect = ui.global::<AuraPageData>().get_led_mode_data();
let raw: rog_aura::AuraEffect = slint_effect.into();
let pp = p.clone();
let t = w.clone();
tokio::spawn(async move {
let r = pp.set_led_mode_data(raw).await;
show_toast("LED mode applied".into(), "LED mode failed".into(), t, r);
});
});
h.invoke_external_colour_change();
})
.map_err(|e| error!("{e:}"))
.ok();
// Need to update the UI if the mode changes
let handle_copy = handle.clone();
// spawn required since the while let never exits
let weak_power = handle.clone();
let proxy_power = aura.clone();
handle
.upgrade_in_event_loop(|h| {
h.global::<AuraPageData>().on_cb_led_power(move |power| {
let w = weak_power.clone();
let p = proxy_power.clone();
let pw: LaptopAuraPower = power.into();
tokio::spawn(async move {
show_toast(
"Aura power updated".into(),
"Aura power failed".into(),
w,
p.set_led_power(pw).await,
);
});
});
})
.map_err(|e| error!("{e}"))
.ok();
let stream_handle = handle.clone();
let aura_stream = aura.clone();
tokio::spawn(async move {
let mut x = proxy_copy.receive_led_mode_data_changed().await;
use zbus::export::futures_util::StreamExt;
while let Some(e) = x.next().await {
use futures_util::StreamExt;
let mut stream = aura_stream.receive_led_mode_data_changed().await;
while let Some(e) = stream.next().await {
if let Ok(out) = e.get().await {
handle_copy
.upgrade_in_event_loop(move |handle| {
handle
let raw: i32 = out.mode.into();
let data = out.into();
stream_handle
.upgrade_in_event_loop(move |h| {
h.global::<AuraPageData>().invoke_update_led_mode_data(data);
let supported: Vec<i32> = h
.global::<AuraPageData>()
.invoke_update_led_mode_data(out.into());
handle.invoke_external_colour_change();
.get_supported_basic_modes()
.iter()
.collect();
let idx = supported.iter().position(|&x| x == raw).unwrap_or(0) as i32;
h.global::<AuraPageData>().set_current_available_mode(idx);
h.invoke_external_colour_change();
})
.map_err(|e| error!("{e:}"))
.map_err(|e| error!("{e}"))
.ok();
}
}
});
debug!("Aura setup tasks complete");
debug!("Aura setup done");
Ok(())
});
}

View File

@@ -1,8 +1,9 @@
use std::sync::{Arc, Mutex};
use log::{error, info};
use log::error;
use rog_dbus::zbus_fan_curves::FanCurvesProxy;
use rog_platform::platform::ThrottlePolicy;
use rog_dbus::zbus_platform::PlatformProxy;
use rog_platform::platform::PlatformProfile;
use rog_profiles::fan_curve_set::CurveData;
use slint::{ComponentHandle, Model, Weak};
@@ -54,14 +55,17 @@ pub fn update_fan_data(
global.set_performance_available(true);
match fan.fan {
rog_profiles::FanCurvePU::CPU => {
global.set_cpu_fan_available(true);
global.set_performance_cpu_enabled(fan.enabled);
global.set_performance_cpu(collect(&fan.temp, &fan.pwm))
}
rog_profiles::FanCurvePU::GPU => {
global.set_gpu_fan_available(true);
global.set_performance_gpu_enabled(fan.enabled);
global.set_performance_gpu(collect(&fan.temp, &fan.pwm))
}
rog_profiles::FanCurvePU::MID => {
global.set_mid_fan_available(true);
global.set_performance_mid_enabled(fan.enabled);
global.set_performance_mid(collect(&fan.temp, &fan.pwm))
}
@@ -71,12 +75,18 @@ pub fn update_fan_data(
global.set_quiet_available(true);
match fan.fan {
rog_profiles::FanCurvePU::CPU => {
global.set_cpu_fan_available(true);
global.set_quiet_cpu_enabled(fan.enabled);
global.set_quiet_cpu(collect(&fan.temp, &fan.pwm))
}
rog_profiles::FanCurvePU::GPU => {
global.set_gpu_fan_available(true);
global.set_quiet_gpu_enabled(fan.enabled);
global.set_quiet_gpu(collect(&fan.temp, &fan.pwm))
}
rog_profiles::FanCurvePU::MID => {
global.set_mid_fan_available(true);
global.set_quiet_mid_enabled(fan.enabled);
global.set_quiet_mid(collect(&fan.temp, &fan.pwm))
}
}
@@ -91,96 +101,131 @@ pub fn setup_fan_curve_page(ui: &MainWindow, _config: Arc<Mutex<Config>>) {
tokio::spawn(async move {
// Create the connections/proxies here to prevent future delays in process
let conn = if let Ok(conn) = zbus::Connection::system().await.map_err(|e| error!("{e:}")) {
conn
} else {
return;
let conn = match zbus::Connection::system().await {
Ok(conn) => conn,
Err(e) => {
error!("{e:}");
return;
}
};
let fans = if let Ok(fans) = FanCurvesProxy::new(&conn).await.map_err(|e| error!("{e:}")) {
fans
} else {
info!(
"This device may not have an Fan Curve control. If not then the error can be \
ignored"
);
return;
let fans = match FanCurvesProxy::new(&conn).await {
Ok(fans) => fans,
Err(e) => {
error!("{e:}");
return;
}
};
let platform = match PlatformProxy::new(&conn).await {
Ok(platform) => platform,
Err(e) => {
error!("{e:}");
return;
}
};
let platform_profile_choices = match platform.platform_profile_choices().await {
Ok(choices) => choices,
Err(e) => {
error!("{e:}");
return;
}
};
let handle_copy = handle.clone();
// Do initial setup
let Ok(balanced) = fans
.fan_curve_data(ThrottlePolicy::Balanced)
.await
.map_err(|e| error!("{e:}"))
else {
return;
let balanced = match fans.fan_curve_data(PlatformProfile::Balanced).await {
Ok(data) => data,
Err(e) => {
error!("Couldn't get balanced data: {e:}");
return;
}
};
let Ok(perf) = fans
.fan_curve_data(ThrottlePolicy::Performance)
.await
.map_err(|e| error!("{e:}"))
else {
return;
let perf = match fans.fan_curve_data(PlatformProfile::Performance).await {
Ok(data) => data,
Err(e) => {
error!("Couldn't get performance data: {e:}");
return;
}
};
let Ok(quiet) = fans
.fan_curve_data(ThrottlePolicy::Quiet)
.await
.map_err(|e| error!("{e:}"))
else {
return;
// TODO: the fan curve stuff was written donkeys ago with the expectation that
// only 3 profiles existed
let profile = if platform_profile_choices.contains(&PlatformProfile::Quiet) {
PlatformProfile::Quiet
} else {
PlatformProfile::LowPower
};
let quiet = match fans.fan_curve_data(profile).await {
Ok(data) => data,
Err(e) => {
error!("Couldn't get quiet data: {e:}");
return;
}
};
update_fan_data(handle, balanced, perf, quiet);
let choices_for_ui = platform_profile_choices.clone();
let handle_next1 = handle_copy.clone();
handle_copy
.upgrade_in_event_loop(move |handle| {
let global = handle.global::<FanPageData>();
let fans1 = fans.clone();
global.on_set_profile_default(move |profile| {
let fans = fans1.clone();
let handle_next = handle_next1.clone();
tokio::spawn(async move {
if fans.set_curves_to_defaults(profile.into()).await.is_err() {
return;
}
let Ok(balanced) = fans
.fan_curve_data(ThrottlePolicy::Balanced)
.await
.map_err(|e| error!("{e:}"))
else {
return;
};
let Ok(perf) = fans
.fan_curve_data(ThrottlePolicy::Performance)
.await
.map_err(|e| error!("{e:}"))
else {
return;
};
let Ok(quiet) = fans
.fan_curve_data(ThrottlePolicy::Quiet)
.await
.map_err(|e| error!("{e:}"))
else {
return;
};
update_fan_data(handle_next, balanced, perf, quiet);
});
if let Err(e) = handle_copy.upgrade_in_event_loop(move |handle| {
let global = handle.global::<FanPageData>();
let fans1 = fans.clone();
let choices = choices_for_ui.clone();
global.on_set_profile_default(move |profile| {
let fans = fans1.clone();
let handle_next = handle_next1.clone();
let choices = choices.clone();
tokio::spawn(async move {
let mut target: PlatformProfile = profile.into();
if target == PlatformProfile::Quiet
&& !choices.contains(&PlatformProfile::Quiet)
{
target = PlatformProfile::LowPower;
}
if fans.set_curves_to_defaults(target).await.is_err() {
return;
}
let Ok(balanced) = fans
.fan_curve_data(PlatformProfile::Balanced)
.await
.map_err(|e| error!("{e:}"))
else {
return;
};
let Ok(perf) = fans
.fan_curve_data(PlatformProfile::Performance)
.await
.map_err(|e| error!("{e:}"))
else {
return;
};
let Ok(quiet) = fans
.fan_curve_data(PlatformProfile::Quiet)
.await
.map_err(|e| error!("{e:}"))
else {
return;
};
update_fan_data(handle_next, balanced, perf, quiet);
});
global.on_set_fan_data(move |fan, profile, enabled, data| {
let fans = fans.clone();
let data: Vec<Node> = data.iter().collect();
let data = fan_data_for(fan, enabled, data);
tokio::spawn(async move {
fans.set_fan_curve(profile.into(), data)
.await
.map_err(|e| error!("{e:}"))
.ok()
});
});
global.on_set_fan_data(move |fan, profile, enabled, data| {
let fans = fans.clone();
let data: Vec<Node> = data.iter().collect();
let data = fan_data_for(fan, enabled, data);
tokio::spawn(async move {
fans.set_fan_curve(profile.into(), data)
.await
.map_err(|e| error!("{e:}"))
.ok()
});
})
.map_err(|e| error!("setup_fan_curve_page: upgrade_in_event_loop: {e:?}"))
.ok();
});
}) {
error!("setup_fan_curve_page: upgrade_in_event_loop: {e:?}");
}
});
}
@@ -195,6 +240,8 @@ fn fan_data_for(fan: FanType, enabled: bool, data: Vec<Node>) -> CurveData {
pwm[i] = n.y as u8;
}
dbg!(&fan, enabled);
CurveData {
fan: fan.into(),
pwm,

View File

@@ -0,0 +1,182 @@
use log::error;
use rog_platform::asus_armoury::{AttrValue, FirmwareAttributes};
use slint::{ComponentHandle, ModelRc, SharedString};
use crate::{GPUPageData, MainWindow};
// Populate GPU page choices and wire the `cb_set_gpu_mode` callback
pub fn setup_gpu_page(ui: &MainWindow) {
let handle = ui.as_weak();
tokio::spawn(async move {
// Read available attributes
let attrs = FirmwareAttributes::new();
let gpu_mux_available = attrs
.gpu_mux_mode()
.map(|a| a.base_path_exists())
.unwrap_or(false);
// Prepare choice strings
let mut choices: Vec<SharedString> = Vec::new();
choices.push(SharedString::from("Integrated"));
if gpu_mux_available {
choices.push(SharedString::from("Ultimate"));
}
choices.push(SharedString::from("Hybrid"));
// Read current attribute values to initialise UI state
let current_dgpu = attrs
.dgpu_disable()
.and_then(|a| a.current_value().ok())
.unwrap_or(AttrValue::Integer(0));
let current_mux = attrs
.gpu_mux_mode()
.and_then(|a| a.current_value().ok())
.unwrap_or(AttrValue::Integer(1));
// Convert to UI-able values
let dgpu_disabled = matches!(current_dgpu, AttrValue::Integer(v) if v == 1);
// Determine initial index for gpu_mux_mode property
let initial_index: i32 = if gpu_mux_available {
// If mux attr says 0 -> Ultimate, else try dgpu to refine
match current_mux {
AttrValue::Integer(0) => 1, // Ultimate
_ => {
match current_dgpu {
AttrValue::Integer(1) => 0, // Integrated
_ => 2, // Hybrid/Optimus fallback
}
}
}
} else {
// Only Integrated / Hybrid
match current_dgpu {
AttrValue::Integer(1) => 0,
_ => 1,
}
};
let handle_copy = handle.clone();
if let Err(e) = handle.upgrade_in_event_loop(move |handle| {
let global = handle.global::<GPUPageData>();
// set choices model
let model: ModelRc<SharedString> = choices.as_slice().into();
global.set_gpu_modes_choises(model);
global.set_gpu_mux_available(gpu_mux_available);
// set initial state
global.set_dgpu_disabled(if dgpu_disabled { 1 } else { 0 });
global.set_gpu_mux_mode(initial_index);
// register callback
let handle_cb = handle_copy.clone();
global.on_cb_set_gpu_mode(move |index: i32| {
// show a blue toast informing user a reboot is required (auto-clears)
let toast_handle = handle_cb.clone();
crate::ui::show_toast(
SharedString::from(
"GPU mode change scheduled — reboot required for changes to apply.",
),
SharedString::from("Failed to set GPU mode"),
toast_handle.clone(),
Ok(()),
);
let handle_next = handle_cb.clone();
tokio::spawn(async move {
let attrs = FirmwareAttributes::new();
let mux_avail = attrs
.gpu_mux_mode()
.map(|a| a.base_path_exists())
.unwrap_or(false);
// helper to set attribute ignoring errors
if mux_avail {
match index {
0 => {
// Integrated
if let Some(attr) = attrs.dgpu_disable() {
let _ = attr.set_current_value(&AttrValue::Integer(1));
}
if let Some(attr) = attrs.gpu_mux_mode() {
let _ = attr.set_current_value(&AttrValue::Integer(1));
}
}
1 => {
// Ultimate
if let Some(attr) = attrs.dgpu_disable() {
let _ = attr.set_current_value(&AttrValue::Integer(0));
}
if let Some(attr) = attrs.gpu_mux_mode() {
let _ = attr.set_current_value(&AttrValue::Integer(0));
}
}
2 => {
// Dynamic
if let Some(attr) = attrs.dgpu_disable() {
let _ = attr.set_current_value(&AttrValue::Integer(0));
}
if let Some(attr) = attrs.gpu_mux_mode() {
let _ = attr.set_current_value(&AttrValue::Integer(1));
}
}
_ => {}
}
} else {
match index {
0 => {
if let Some(attr) = attrs.dgpu_disable() {
let _ = attr.set_current_value(&AttrValue::Integer(1));
}
}
1 => {
if let Some(attr) = attrs.dgpu_disable() {
let _ = attr.set_current_value(&AttrValue::Integer(0));
}
}
_ => {}
}
};
// After attempting write(s), refresh UI from attributes
let attrs2 = FirmwareAttributes::new();
let cur_dgpu = attrs2
.dgpu_disable()
.and_then(|a| a.current_value().ok())
.unwrap_or(AttrValue::Integer(0));
let cur_mux = attrs2
.gpu_mux_mode()
.and_then(|a| a.current_value().ok())
.unwrap_or(AttrValue::Integer(1));
let dgpu_disabled = matches!(cur_dgpu, AttrValue::Integer(v) if v == 1);
let new_index: i32 = if mux_avail {
match cur_mux {
AttrValue::Integer(0) => 1,
_ => match cur_dgpu {
AttrValue::Integer(1) => 0,
_ => 2,
},
}
} else {
match cur_dgpu {
AttrValue::Integer(1) => 0,
_ => 1,
}
};
if let Err(e) = handle_next.upgrade_in_event_loop(move |h| {
let g = h.global::<GPUPageData>();
g.set_dgpu_disabled(if dgpu_disabled { 1 } else { 0 });
g.set_gpu_mux_mode(new_index);
}) {
error!("setup_gpu callback: upgrade_in_event_loop: {e:?}");
}
});
});
}) {
error!("setup_gpu_page: upgrade_in_event_loop: {e:?}");
}
});
}

View File

@@ -1,40 +1,275 @@
use std::sync::{Arc, Mutex};
use concat_idents::concat_idents;
use log::{debug, error};
use rog_dbus::asus_armoury::AsusArmouryProxy;
use rog_dbus::zbus_backlight::BacklightProxy;
use rog_dbus::zbus_platform::{PlatformProxy, PlatformProxyBlocking};
use rog_platform::asus_armoury::FirmwareAttribute;
use rog_platform::platform::Properties;
use slint::ComponentHandle;
use slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel};
use super::show_toast;
use crate::config::Config;
use crate::{
set_ui_callbacks, set_ui_props_async, AvailableSystemProperties, MainWindow, SystemPageData,
use crate::zbus_proxies::find_iface_async;
use crate::{set_ui_callbacks, AttrMinMax, MainWindow, SystemPageData};
const MINMAX: AttrMinMax = AttrMinMax {
min: 0,
max: 0,
current: -1.0,
};
pub fn setup_system_page(ui: &MainWindow, _config: Arc<Mutex<Config>>) {
let conn = zbus::blocking::Connection::system().unwrap();
let platform = PlatformProxyBlocking::new(&conn).unwrap();
let conn = zbus::blocking::Connection::system()
.map_err(|e| error!("DBus system connection failed: {e:?}"))
.unwrap();
let platform = PlatformProxyBlocking::builder(&conn)
.build()
.map_err(|e| error!("PlatformProxy failed: {e:?}"))
.unwrap();
// let armoury_attrs =
// find_iface::<AsusArmouryProxyBlocking>("xyz.ljones.AsusArmoury").unwrap();
let sys_props = platform.supported_properties().unwrap();
log::debug!("Available system properties: {sys_props:?}");
let props = AvailableSystemProperties {
ac_command: true,
bat_command: true,
charge_control_end_threshold: sys_props.contains(&Properties::ChargeControlEndThreshold),
disable_nvidia_powerd_on_battery: true,
mini_led_mode: sys_props.contains(&Properties::MiniLedMode),
nv_dynamic_boost: sys_props.contains(&Properties::NvDynamicBoost),
nv_temp_target: sys_props.contains(&Properties::NvTempTarget),
panel_od: sys_props.contains(&Properties::PanelOd),
boot_sound: sys_props.contains(&Properties::PostAnimationSound),
ppt_apu_sppt: sys_props.contains(&Properties::PptApuSppt),
ppt_fppt: sys_props.contains(&Properties::PptFppt),
ppt_pl1_spl: sys_props.contains(&Properties::PptPl1Spl),
ppt_pl2_sppt: sys_props.contains(&Properties::PptPl2Sppt),
ppt_platform_sppt: sys_props.contains(&Properties::PptPlatformSppt),
throttle_thermal_policy: sys_props.contains(&Properties::ThrottlePolicy),
// Null everything before the setup step
debug!("Defaulting system page values");
ui.global::<SystemPageData>()
.set_charge_control_end_threshold(-1.0);
ui.global::<SystemPageData>()
.set_charge_control_enabled(false);
ui.global::<SystemPageData>().set_platform_profile(-1);
ui.global::<SystemPageData>().set_panel_overdrive(-1);
ui.global::<SystemPageData>().set_boot_sound(-1);
ui.global::<SystemPageData>().set_screen_auto_brightness(-1);
ui.global::<SystemPageData>().set_mcu_powersave(-1);
ui.global::<SystemPageData>().set_mini_led_mode(-1);
ui.global::<SystemPageData>().set_screenpad_brightness(-1);
ui.global::<SystemPageData>().set_ppt_pl1_spl(MINMAX);
ui.global::<SystemPageData>().set_ppt_pl2_sppt(MINMAX);
ui.global::<SystemPageData>().set_ppt_pl3_fppt(MINMAX);
ui.global::<SystemPageData>().set_ppt_fppt(MINMAX);
ui.global::<SystemPageData>().set_ppt_apu_sppt(MINMAX);
ui.global::<SystemPageData>().set_ppt_platform_sppt(MINMAX);
ui.global::<SystemPageData>().set_nv_dynamic_boost(MINMAX);
ui.global::<SystemPageData>().set_nv_temp_target(MINMAX);
ui.global::<SystemPageData>().set_ppt_enabled(false);
ui.global::<SystemPageData>()
.set_ppt_enabled_available(false);
if let Ok(sys_props) = platform
.supported_properties()
.map_err(|e| log::error!("Failed to get supported properties: {}", e))
{
log::debug!("Available system properties: {:?}", &sys_props);
if sys_props.contains(&Properties::ChargeControlEndThreshold) {
ui.global::<SystemPageData>()
.set_charge_control_end_threshold(60.0);
ui.global::<SystemPageData>()
.set_charge_control_enabled(true);
}
}
}
macro_rules! convert_value {
(bool, $value:expr) => {
$value == 1
};
(i32, $value:expr) => {
$value as i32
};
(f32, $value:expr) => {
$value as f32
};
}
ui.global::<SystemPageData>().set_available(props);
macro_rules! convert_to_dbus {
(bool, $value:expr) => {
if $value {
1
} else {
0
}
};
(i32, $value:expr) => {
$value as i32
};
(f32, $value:expr) => {
$value as i32
};
}
macro_rules! init_property {
($property:ident, $handle:expr, $value:expr, $type:tt) => {{
concat_idents!(setter = set_, $property {
$handle.global::<SystemPageData>().setter(convert_value!($type, $value));
});
}};
}
// For initial setup of min/max/val values
macro_rules! init_minmax_property {
($property:ident, $handle:expr, $attr:expr) => {
let proxy_copy = $attr.clone();
let handle_copy = $handle.as_weak();
tokio::spawn(async move {
let min = proxy_copy.min_value().await.unwrap();
let max = proxy_copy.max_value().await.unwrap();
let current = proxy_copy.current_value().await.unwrap() as f32;
handle_copy
.upgrade_in_event_loop(move |handle| {
concat_idents!(setter = set_, $property {
handle
.global::<SystemPageData>()
.setter(AttrMinMax { min, max, current });
});
})
.ok();
});
};
}
// For handling callbacks from UI value changes
macro_rules! setup_callback {
($property:ident, $handle:expr, $attr:expr, $type:tt) => {
let handle_copy = $handle.as_weak();
let proxy_copy = $attr.clone();
concat_idents!(on_callback = on_cb_, $property {
$handle
.global::<SystemPageData>()
.on_callback(move |v| {
let handle_copy = handle_copy.clone();
let proxy_copy = proxy_copy.clone();
tokio::spawn(async move {
show_toast(
format!("{} successfully set to {}", stringify!($property), v).into(),
format!("Setting {} failed", stringify!($property)).into(),
handle_copy,
proxy_copy.set_current_value(convert_to_dbus!($type, v)).await,
);
});
});
});
};
}
// For handling callbacks from UI value changes
macro_rules! setup_callback_restore_default {
($property:ident, $handle:expr, $attr:expr) => {
let proxy_copy = $attr.clone();
concat_idents!(on_callback = on_cb_default_, $property {
$handle
.global::<SystemPageData>()
.on_callback(move || {
let proxy_copy = proxy_copy.clone();
tokio::spawn(async move {
proxy_copy.restore_default().await.ok();
});
});
});
};
}
macro_rules! setup_external {
($property:ident, $type:tt, $handle:expr, $attr:expr, $value:expr) => {{
// EXTERNAL CHANGES
let handle_copy = $handle.as_weak();
let proxy_copy = $attr.clone();
concat_idents!(setter = set_, $property {
tokio::spawn(async move {
let mut x = proxy_copy.receive_current_value_changed().await;
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
handle_copy
.upgrade_in_event_loop(move |handle| {
handle
.global::<SystemPageData>()
.setter(convert_value!($type, out));
})
.ok();
}
}
});
});
}};
}
// For handling external value changes
macro_rules! setup_value_watch {
($property:ident, $handle:expr, $proxy:expr, $value_type:ident $($conv: tt)*) => {
let handle_copy = $handle.as_weak();
let proxy_copy = $proxy.clone();
tokio::spawn(async move {
let mut x = concat_idents!(recv = receive_, $value_type, _value_changed {
proxy_copy.recv().await
});
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
concat_idents!(getter = get_, $property {
handle_copy
.upgrade_in_event_loop(move |handle| {
let mut tmp: AttrMinMax =
handle.global::<SystemPageData>().getter();
tmp.$value_type = out $($conv)*;
concat_idents!(setter = set_, $property {
handle.global::<SystemPageData>().setter(tmp);
});
})
.ok();
});
}
}
});
};
}
macro_rules! setup_minmax_external {
($property:ident, $handle:expr, $attr:expr, $platform:expr) => {
setup_value_watch!($property, $handle, $attr, current as f32);
setup_value_watch!($property, $handle, $attr, min);
setup_value_watch!($property, $handle, $attr, max);
let handle_copy = $handle.as_weak();
let proxy_copy = $attr.clone();
let platform_proxy_copy = $platform.clone();
tokio::spawn(async move {
let mut x = platform_proxy_copy.receive_platform_profile_changed().await;
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(_) = e.get().await {
debug!("receive_platform_profile_changed, getting new {}", stringify!(attr));
let min = proxy_copy.min_value().await.unwrap();
let max = proxy_copy.max_value().await.unwrap();
let current = proxy_copy.current_value().await.unwrap() as f32;
handle_copy
.upgrade_in_event_loop(move |handle| {
concat_idents!(setter = set_, $property {
handle
.global::<SystemPageData>()
.setter(AttrMinMax { min, max, current });
});
})
.ok();
}
}
});
};
}
// This macro expects are consistent naming between proxy calls and slint
// globals
#[macro_export]
macro_rules! set_ui_props_async {
($ui:ident, $proxy:ident, $global:ident, $proxy_fn:ident) => {
if let Ok(value) = $proxy.$proxy_fn().await {
$ui.upgrade_in_event_loop(move |handle| {
concat_idents::concat_idents!(set = set_, $proxy_fn {
handle.global::<$global>().set(value.into());
});
}).ok();
}
};
}
pub fn setup_system_page_callbacks(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
@@ -44,199 +279,441 @@ pub fn setup_system_page_callbacks(ui: &MainWindow, _states: Arc<Mutex<Config>>)
tokio::spawn(async move {
// Create the connections/proxies here to prevent future delays in process
let conn = zbus::Connection::system().await.unwrap();
let platform = PlatformProxy::new(&conn).await.unwrap();
let conn = zbus::Connection::system()
.await
.map_err(|e| {
log::error!("Failed to connect to system bus: {}", e);
})
.unwrap();
let platform = PlatformProxy::builder(&conn)
.build()
.await
.map_err(|e| {
log::error!("Failed to create platform proxy: {}", e);
})
.unwrap();
let backlight = BacklightProxy::builder(&conn)
.build()
.await
.map_err(|e| {
log::error!("Failed to create backlight proxy: {}", e);
})
.unwrap();
debug!("Setting up system page profile callbacks");
set_ui_props_async!(
handle,
platform,
SystemPageData,
charge_control_end_threshold
);
set_ui_props_async!(handle, platform, SystemPageData, throttle_thermal_policy);
set_ui_props_async!(handle, platform, SystemPageData, throttle_policy_linked_epp);
set_ui_props_async!(handle, platform, SystemPageData, throttle_balanced_epp);
set_ui_props_async!(handle, platform, SystemPageData, throttle_performance_epp);
set_ui_props_async!(handle, platform, SystemPageData, throttle_quiet_epp);
set_ui_props_async!(handle, platform, SystemPageData, throttle_policy_on_battery);
let platform_copy = platform.clone();
if let Ok(mut value) = platform.platform_profile_choices().await {
debug!("Available platform profile choices: {:?}", value);
handle
.upgrade_in_event_loop(move |handle| {
value.sort();
let translate: Vec<SharedString> = handle
.global::<SystemPageData>()
.get_platform_profile_choices()
.iter()
.collect();
let mut indexes = Vec::new();
let strings: Vec<SharedString> = value
.iter()
.filter_map(|p| {
let index = i32::from(*p) as usize;
if index < translate.len() {
indexes.push(index as i32);
Some(translate[index].clone())
} else {
None
}
})
.collect();
let choices = ModelRc::new(VecModel::from(strings));
handle
.global::<SystemPageData>()
.set_platform_profile_choices(choices);
handle
.global::<SystemPageData>()
.set_platform_profile_indexes(ModelRc::from(indexes.as_slice()));
// Set current only after setting the choices up
let handle = handle.as_weak();
tokio::spawn(async move {
if let Ok(value) = platform_copy.platform_profile().await {
let profile_value = <i32>::from(value);
handle
.upgrade_in_event_loop(move |handle| {
if let Some(position) =
indexes.iter().position(|&index| index == profile_value)
{
handle
.global::<SystemPageData>()
.set_platform_profile(position as i32);
}
})
.ok();
}
});
})
.ok();
}
set_ui_props_async!(
handle,
platform,
SystemPageData,
change_throttle_policy_on_battery
platform_profile_linked_epp
);
set_ui_props_async!(handle, platform, SystemPageData, throttle_policy_on_ac);
set_ui_props_async!(handle, platform, SystemPageData, profile_balanced_epp);
set_ui_props_async!(handle, platform, SystemPageData, profile_performance_epp);
set_ui_props_async!(handle, platform, SystemPageData, profile_quiet_epp);
set_ui_props_async!(
handle,
platform,
SystemPageData,
change_throttle_policy_on_ac
platform_profile_on_battery
);
set_ui_props_async!(
handle,
platform,
SystemPageData,
change_platform_profile_on_battery
);
set_ui_props_async!(handle, platform, SystemPageData, platform_profile_on_ac);
set_ui_props_async!(
handle,
platform,
SystemPageData,
change_platform_profile_on_ac
);
set_ui_props_async!(handle, platform, SystemPageData, panel_od);
set_ui_props_async!(handle, platform, SystemPageData, boot_sound);
set_ui_props_async!(handle, platform, SystemPageData, mini_led_mode);
set_ui_props_async!(handle, platform, SystemPageData, ppt_pl1_spl);
set_ui_props_async!(handle, platform, SystemPageData, ppt_pl2_sppt);
set_ui_props_async!(handle, platform, SystemPageData, ppt_fppt);
set_ui_props_async!(handle, platform, SystemPageData, ppt_apu_sppt);
set_ui_props_async!(handle, platform, SystemPageData, ppt_platform_sppt);
set_ui_props_async!(handle, platform, SystemPageData, nv_dynamic_boost);
set_ui_props_async!(handle, platform, SystemPageData, nv_temp_target);
set_ui_props_async!(handle, platform, SystemPageData, enable_ppt_group);
let sys_props = platform.supported_properties().await.unwrap();
log::debug!("Available system properties: {sys_props:?}");
let props = AvailableSystemProperties {
ac_command: true,
bat_command: true,
charge_control_end_threshold: sys_props
.contains(&Properties::ChargeControlEndThreshold),
disable_nvidia_powerd_on_battery: true,
mini_led_mode: sys_props.contains(&Properties::MiniLedMode),
nv_dynamic_boost: sys_props.contains(&Properties::NvDynamicBoost),
nv_temp_target: sys_props.contains(&Properties::NvTempTarget),
panel_od: sys_props.contains(&Properties::PanelOd),
boot_sound: sys_props.contains(&Properties::PostAnimationSound),
ppt_apu_sppt: sys_props.contains(&Properties::PptApuSppt),
ppt_fppt: sys_props.contains(&Properties::PptFppt),
ppt_pl1_spl: sys_props.contains(&Properties::PptPl1Spl),
ppt_pl2_sppt: sys_props.contains(&Properties::PptPl2Sppt),
ppt_platform_sppt: sys_props.contains(&Properties::PptPlatformSppt),
throttle_thermal_policy: sys_props.contains(&Properties::ThrottlePolicy),
};
set_ui_props_async!(handle, backlight, SystemPageData, screenpad_brightness);
if let Ok(value) = backlight.screenpad_gamma().await {
handle
.upgrade_in_event_loop(move |handle| {
handle
.global::<SystemPageData>()
.set_screenpad_gamma(value.parse().unwrap_or(1.0));
})
.ok();
}
// TODO: move the fail/sucess messages to slint
set_ui_props_async!(
handle,
backlight,
SystemPageData,
screenpad_sync_with_primary
);
let platform_copy = platform.clone();
handle
.upgrade_in_event_loop(move |handle| {
handle.global::<SystemPageData>().set_available(props);
debug!("Setting up system page standard callbacks");
let handle_copy = handle.as_weak();
let proxy_copy = platform_copy.clone();
handle
.global::<SystemPageData>()
.on_cb_platform_profile(move |value| {
let proxy_copy = proxy_copy.clone();
let handle_copy = handle_copy.clone();
tokio::spawn(async move {
show_toast(
format!("Throttle policy set to {}", value).into(),
"Setting Throttle policy failed".into(),
handle_copy,
proxy_copy.set_platform_profile(value.into()).await,
);
});
});
let handle_copy = handle.as_weak();
let proxy_copy = platform_copy.clone();
// spawn required since the while let never exits
tokio::spawn(async move {
let mut x = proxy_copy.receive_platform_profile_changed().await;
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
handle_copy
.upgrade_in_event_loop(move |handle| {
let indexes = handle
.global::<SystemPageData>()
.get_platform_profile_indexes();
handle
.global::<SystemPageData>()
.set_platform_profile(out as i32);
let profile_value = <i32>::from(out);
if let Some(position) =
indexes.iter().position(|index| index == profile_value)
{
handle
.global::<SystemPageData>()
.set_platform_profile(position as i32);
}
})
.ok();
}
}
});
set_ui_callbacks!(handle,
SystemPageData(as bool),
platform_copy.enable_ppt_group(as bool),
"Applied PPT group settings {}",
"Setting PPT group settings failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.charge_control_end_threshold(as u8),
platform_copy.charge_control_end_threshold(as u8),
"Charge limit successfully set to {}",
"Setting Charge limit failed"
);
set_ui_callbacks!(
handle,
SystemPageData(),
platform.panel_od(),
"Panel OverDrive successfully set to {}",
"Setting Panel OverDrive failed"
);
set_ui_callbacks!(
handle,
SystemPageData(),
platform.boot_sound(),
"POST Animation sound successfully set to {}",
"Setting POST Animation sound failed"
);
set_ui_callbacks!(
handle,
SystemPageData(),
platform.mini_led_mode(),
"MiniLED mode successfully set to {}",
"Setting MiniLED mode failed"
);
// set_ui_callbacks!(handle,
// SystemPageData(as i32),
// platform_copy.platform_profile(.into()),
// "Throttle policy set to {}",
// "Setting Throttle policy failed"
// );
set_ui_callbacks!(handle,
SystemPageData(as i32),
platform.throttle_thermal_policy(.into()),
"Throttle policy set to {}",
"Setting Throttle policy failed"
);
set_ui_callbacks!(handle,
SystemPageData(as i32),
platform.throttle_balanced_epp(.into()),
platform_copy.profile_balanced_epp(.into()),
"Throttle policy EPP set to {}",
"Setting Throttle policy EPP failed"
);
set_ui_callbacks!(handle,
SystemPageData(as i32),
platform.throttle_performance_epp(.into()),
platform_copy.profile_performance_epp(.into()),
"Throttle policy EPP set to {}",
"Setting Throttle policy EPP failed"
);
set_ui_callbacks!(handle,
SystemPageData(as i32),
platform.throttle_quiet_epp(.into()),
platform_copy.profile_quiet_epp(.into()),
"Throttle policy EPP set to {}",
"Setting Throttle policy EPP failed"
);
set_ui_callbacks!(
handle,
SystemPageData(),
platform.throttle_policy_linked_epp(),
platform_copy.platform_profile_linked_epp(),
"Throttle policy linked to EPP: {}",
"Setting Throttle policy linked to EPP failed"
);
set_ui_callbacks!(handle,
SystemPageData(as i32),
platform.throttle_policy_on_ac(.into()),
platform_copy.platform_profile_on_ac(.into()),
"Throttle policy on AC set to {}",
"Setting Throttle policy on AC failed"
);
set_ui_callbacks!(handle,
SystemPageData(as bool),
platform.change_throttle_policy_on_ac(.into()),
platform_copy.change_platform_profile_on_ac(.into()),
"Throttle policy on AC enabled: {}",
"Setting Throttle policy on AC failed"
);
set_ui_callbacks!(handle,
SystemPageData(as i32),
platform.throttle_policy_on_battery(.into()),
"Throttle policy on abttery set to {}",
platform_copy.platform_profile_on_battery(.into()),
"Throttle policy on battery set to {}",
"Setting Throttle policy on battery failed"
);
set_ui_callbacks!(handle,
SystemPageData(as bool),
platform.change_throttle_policy_on_battery(.into()),
platform_copy.change_platform_profile_on_battery(.into()),
"Throttle policy on battery enabled: {}",
"Setting Throttle policy on AC failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.ppt_pl1_spl(as u8),
"ppt_pl1_spl successfully set to {}",
"Setting ppt_pl1_spl failed"
SystemPageData(as i32),
backlight.screenpad_brightness(as i32),
"Screenpad successfully set to {}",
"Setting screenpad brightness failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.ppt_pl2_sppt(as u8),
"ppt_pl2_sppt successfully set to {}",
"Setting ppt_pl2_sppt failed"
SystemPageData(as bool),
backlight.screenpad_sync_with_primary(as bool),
"Screenpad successfully set to {}",
"Setting screenpad brightness failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.ppt_fppt(as u8),
"ppt_fppt successfully set to {}",
"Setting ppt_fppt failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.ppt_apu_sppt(as u8),
"ppt_apu_sppt successfully set to {}",
"Setting ppt_apu_sppt failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.ppt_platform_sppt(as u8),
"ppt_platform_sppt successfully set to {}",
"Setting ppt_platform_sppt failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.nv_temp_target(as u8),
"nv_temp_target successfully set to {}",
"Setting nv_temp_target failed"
);
set_ui_callbacks!(handle,
SystemPageData(as f32),
platform.nv_dynamic_boost(as u8),
"nv_dynamic_boost successfully set to {}",
"Setting nv_dynamic_boost failed"
SystemPageData(.parse().unwrap_or(1.0)),
backlight.screenpad_gamma(.to_string().as_str()),
"Screenpad successfully set to {}",
"Setting screenpad brightness failed"
);
})
.unwrap();
.ok();
let armoury_attrs;
if let Ok(attrs) = find_iface_async::<AsusArmouryProxy>("xyz.ljones.AsusArmoury").await {
debug!("Found AsusArmoury interfaces");
armoury_attrs = attrs;
handle
.upgrade_in_event_loop(|ui| {
ui.global::<SystemPageData>().set_asus_armoury_loaded(true)
})
.ok();
} else {
error!(
"The kernel module asus-armoury is required, if you do not have this you will \
need to either build or install a kernel which includes the patchwork. This \
driver is in process of being upstreamed"
);
return;
}
for attr in armoury_attrs {
if let Ok(value) = attr.current_value().await {
if let Ok(name) = attr.name().await {
debug!("Setting up {} = {value}", <&str>::from(name));
let platform = platform.clone();
handle
.upgrade_in_event_loop(move |handle| match name {
FirmwareAttribute::ApuMem => {}
FirmwareAttribute::CoresPerformance => {}
FirmwareAttribute::CoresEfficiency => {}
FirmwareAttribute::PptEnabled => {
init_property!(ppt_enabled, handle, value, bool);
setup_callback!(ppt_enabled, handle, attr, bool);
let handle_copy = handle.as_weak();
let proxy_copy = attr.clone();
tokio::spawn(async move {
let mut x = proxy_copy.receive_current_value_changed().await;
use futures_util::StreamExt;
while let Some(e) = x.next().await {
if let Ok(out) = e.get().await {
handle_copy
.upgrade_in_event_loop(move |handle| {
handle
.global::<SystemPageData>()
.set_enable_ppt_group(out == 1);
handle
.global::<SystemPageData>()
.set_ppt_enabled(out == 1);
})
.ok();
}
}
});
handle
.global::<SystemPageData>()
.set_ppt_enabled_available(true);
handle
.global::<SystemPageData>()
.set_enable_ppt_group(value == 1);
}
FirmwareAttribute::PptPl1Spl => {
init_minmax_property!(ppt_pl1_spl, handle, attr);
setup_callback!(ppt_pl1_spl, handle, attr, i32);
setup_callback_restore_default!(ppt_pl1_spl, handle, attr);
setup_minmax_external!(ppt_pl1_spl, handle, attr, platform);
}
FirmwareAttribute::PptPl2Sppt => {
init_minmax_property!(ppt_pl2_sppt, handle, attr);
setup_callback!(ppt_pl2_sppt, handle, attr, i32);
setup_callback_restore_default!(ppt_pl2_sppt, handle, attr);
setup_minmax_external!(ppt_pl2_sppt, handle, attr, platform);
}
FirmwareAttribute::PptPl3Fppt => {
init_minmax_property!(ppt_pl3_fppt, handle, attr);
setup_callback!(ppt_pl3_fppt, handle, attr, i32);
setup_callback_restore_default!(ppt_pl3_fppt, handle, attr);
setup_minmax_external!(ppt_pl3_fppt, handle, attr, platform);
}
FirmwareAttribute::PptFppt => {
init_minmax_property!(ppt_fppt, handle, attr);
setup_callback!(ppt_fppt, handle, attr, i32);
setup_callback_restore_default!(ppt_fppt, handle, attr);
setup_minmax_external!(ppt_fppt, handle, attr, platform);
}
FirmwareAttribute::PptApuSppt => {
init_minmax_property!(ppt_apu_sppt, handle, attr);
setup_callback!(ppt_apu_sppt, handle, attr, i32);
setup_callback_restore_default!(ppt_apu_sppt, handle, attr);
setup_minmax_external!(ppt_apu_sppt, handle, attr, platform);
}
FirmwareAttribute::PptPlatformSppt => {
init_minmax_property!(ppt_platform_sppt, handle, attr);
setup_callback!(ppt_platform_sppt, handle, attr, i32);
setup_callback_restore_default!(ppt_platform_sppt, handle, attr);
setup_minmax_external!(ppt_platform_sppt, handle, attr, platform);
}
FirmwareAttribute::NvDynamicBoost => {
init_minmax_property!(nv_dynamic_boost, handle, attr);
setup_callback!(nv_dynamic_boost, handle, attr, i32);
setup_callback_restore_default!(nv_dynamic_boost, handle, attr);
setup_minmax_external!(nv_dynamic_boost, handle, attr, platform);
}
FirmwareAttribute::NvTempTarget => {
init_minmax_property!(nv_temp_target, handle, attr);
setup_callback!(nv_temp_target, handle, attr, i32);
setup_callback_restore_default!(nv_temp_target, handle, attr);
setup_minmax_external!(nv_temp_target, handle, attr, platform);
}
FirmwareAttribute::DgpuBaseTgp => {}
FirmwareAttribute::DgpuTgp => {}
FirmwareAttribute::ChargeMode => {}
FirmwareAttribute::BootSound => {
init_property!(boot_sound, handle, value, i32);
setup_callback!(boot_sound, handle, attr, i32);
setup_external!(boot_sound, i32, handle, attr, value)
}
FirmwareAttribute::ScreenAutoBrightness => {
init_property!(screen_auto_brightness, handle, value, i32);
setup_callback!(screen_auto_brightness, handle, attr, i32);
setup_external!(screen_auto_brightness, i32, handle, attr, value)
}
FirmwareAttribute::McuPowersave => {
init_property!(mcu_powersave, handle, value, i32);
setup_callback!(mcu_powersave, handle, attr, i32);
setup_external!(mcu_powersave, i32, handle, attr, value)
}
FirmwareAttribute::PanelOverdrive => {
init_property!(panel_overdrive, handle, value, i32);
setup_callback!(panel_overdrive, handle, attr, i32);
setup_external!(panel_overdrive, i32, handle, attr, value)
}
FirmwareAttribute::PanelHdMode => {}
FirmwareAttribute::EgpuConnected => {}
FirmwareAttribute::EgpuEnable => {}
FirmwareAttribute::DgpuDisable => {}
FirmwareAttribute::GpuMuxMode => {}
FirmwareAttribute::MiniLedMode => {
init_property!(mini_led_mode, handle, value, i32);
setup_callback!(mini_led_mode, handle, attr, i32);
setup_external!(mini_led_mode, i32, handle, attr, value);
}
FirmwareAttribute::PendingReboot => {}
FirmwareAttribute::None => {}
})
.ok();
} else {
error!("Attribute with no name, skipping");
}
}
}
handle
.upgrade_in_event_loop(|ui| {
debug!(
"get_asus_armoury_loaded: {:?}",
ui.global::<SystemPageData>().get_asus_armoury_loaded()
);
debug!(
"get_ppt_enabled_available: {:?}",
ui.global::<SystemPageData>().get_ppt_enabled_available()
);
})
.ok();
});
}

View File

@@ -1,68 +0,0 @@
use std::sync::{Arc, Mutex};
use zbus::zvariant::{OwnedValue, Type, Value};
use zbus::{interface, proxy};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Type, Value, OwnedValue)]
#[zvariant(signature = "u")]
pub enum AppState {
MainWindowOpen = 0,
/// If the app is running, open the main window
MainWindowShouldOpen = 1,
MainWindowClosed = 2,
StartingUp = 3,
QuitApp = 4,
LockFailed = 5,
}
pub struct ROGCCZbus {
state: Arc<Mutex<AppState>>,
}
impl ROGCCZbus {
pub fn new() -> Self {
Self {
state: Arc::new(Mutex::new(AppState::StartingUp)),
}
}
pub fn clone_state(&self) -> Arc<Mutex<AppState>> {
self.state.clone()
}
}
pub const ZBUS_PATH: &str = "/xyz/ljones/rogcc";
pub const ZBUS_IFACE: &str = "xyz.ljones.rogcc";
#[interface(name = "xyz.ljones.rogcc")]
impl ROGCCZbus {
/// Return the device type for this Aura keyboard
#[zbus(property)]
async fn state(&self) -> AppState {
if let Ok(lock) = self.state.try_lock() {
return *lock;
}
AppState::LockFailed
}
#[zbus(property)]
async fn set_state(&self, state: AppState) {
if let Ok(mut lock) = self.state.try_lock() {
*lock = state;
}
}
}
#[proxy(
interface = "xyz.ljones.rogcc",
default_service = "xyz.ljones.rogcc",
default_path = "/xyz/ljones/rogcc"
)]
pub trait ROGCCZbus {
/// EnableDisplay property
#[zbus(property)]
fn state(&self) -> zbus::Result<AppState>;
#[zbus(property)]
fn set_state(&self, state: AppState) -> zbus::Result<()>;
}

View File

@@ -0,0 +1,150 @@
use std::sync::{Arc, Mutex};
use zbus::blocking::proxy::ProxyImpl;
use zbus::blocking::{fdo, Connection};
use zbus::zvariant::{OwnedValue, Type, Value};
use zbus::{interface, proxy};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Type, Value, OwnedValue)]
#[zvariant(signature = "u")]
pub enum AppState {
MainWindowOpen = 0,
/// If the app is running, open the main window
MainWindowShouldOpen = 1,
MainWindowClosed = 2,
StartingUp = 3,
QuitApp = 4,
LockFailed = 5,
}
pub struct ROGCCZbus {
state: Arc<Mutex<AppState>>,
}
impl ROGCCZbus {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
state: Arc::new(Mutex::new(AppState::StartingUp)),
}
}
pub fn clone_state(&self) -> Arc<Mutex<AppState>> {
self.state.clone()
}
}
pub const ZBUS_PATH: &str = "/xyz/ljones/rogcc";
pub const ZBUS_IFACE: &str = "xyz.ljones.rogcc";
#[interface(name = "xyz.ljones.rogcc")]
impl ROGCCZbus {
/// Return the device type for this Aura keyboard
#[zbus(property)]
async fn state(&self) -> AppState {
if let Ok(lock) = self.state.try_lock() {
return *lock;
}
AppState::LockFailed
}
#[zbus(property)]
async fn set_state(&self, state: AppState) {
if let Ok(mut lock) = self.state.try_lock() {
*lock = state;
}
}
}
#[proxy(
interface = "xyz.ljones.rogcc",
default_service = "xyz.ljones.rogcc",
default_path = "/xyz/ljones/rogcc"
)]
pub trait ROGCCZbus {
/// EnableDisplay property
#[zbus(property)]
fn state(&self) -> zbus::Result<AppState>;
#[zbus(property)]
fn set_state(&self, state: AppState) -> zbus::Result<()>;
}
pub fn find_iface<T>(iface_name: &str) -> Result<Vec<T>, Box<dyn std::error::Error>>
where
T: ProxyImpl<'static> + From<zbus::Proxy<'static>>,
{
let conn = Connection::system().unwrap();
let f = fdo::ObjectManagerProxy::new(&conn, "xyz.ljones.Asusd", "/").unwrap();
let interfaces = f.get_managed_objects().unwrap();
let mut paths = Vec::new();
for v in interfaces.iter() {
// let o: Vec<zbus::names::OwnedInterfaceName> = v.1.keys().map(|e|
// e.to_owned()).collect(); println!("{}, {:?}", v.0, o);
for k in v.1.keys() {
if k.as_str() == iface_name {
// println!("Found {iface_name} device at {}, {}", v.0, k);
paths.push(v.0.clone());
}
}
}
if paths.len() > 1 {
log::warn!("Multiple asusd interfaces devices found");
}
if !paths.is_empty() {
let mut ctrl = Vec::new();
paths.sort_by(|a, b| a.cmp(b));
for path in paths {
ctrl.push(
T::builder(&conn)
.path(path.clone())?
.destination("xyz.ljones.Asusd")?
.build()?,
);
}
return Ok(ctrl);
}
Err("No Aura interface".into())
}
pub async fn find_iface_async<T>(iface_name: &str) -> Result<Vec<T>, Box<dyn std::error::Error>>
where
T: zbus::proxy::ProxyImpl<'static> + From<zbus::Proxy<'static>>,
{
let conn = zbus::Connection::system().await.unwrap();
let f = zbus::fdo::ObjectManagerProxy::new(&conn, "xyz.ljones.Asusd", "/")
.await
.unwrap();
let interfaces = f.get_managed_objects().await.unwrap();
let mut paths = Vec::new();
for v in interfaces.iter() {
// let o: Vec<zbus::names::OwnedInterfaceName> = v.1.keys().map(|e|
// e.to_owned()).collect(); println!("{}, {:?}", v.0, o);
for k in v.1.keys() {
if k.as_str() == iface_name {
// println!("Found {iface_name} device at {}, {}", v.0, k);
paths.push(v.0.clone());
}
}
}
if paths.len() > 1 {
log::warn!("Multiple asusd interfaces devices found");
}
if !paths.is_empty() {
let mut ctrl = Vec::new();
paths.sort_by(|a, b| a.cmp(b));
for path in paths {
ctrl.push(
T::builder(&conn)
.path(path.clone())?
.destination("xyz.ljones.Asusd")?
.build()
.await?,
);
}
return Ok(ctrl);
}
Err("No interface".into())
}

View File

@@ -0,0 +1,684 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-06-09 00:20+0000\n"
"PO-Revision-Date: 2024-07-19 11:32+0400\n"
"Last-Translator: Rəşad Qasımlı <rashadgasimli2005@gmail.com>\n"
"Language-Team: Azerbaijan <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: az\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: rog-control-center/ui/pages/anime.slint:6
msgctxt "Anime Brightness"
msgid "Off"
msgstr "Sönülü"
#: rog-control-center/ui/pages/anime.slint:7
msgctxt "Anime Brightness"
msgid "Low"
msgstr "Aşağı"
#: rog-control-center/ui/pages/anime.slint:8
msgctxt "Anime Brightness"
msgid "Med"
msgstr "Orta"
#: rog-control-center/ui/pages/anime.slint:9
msgctxt "Anime Brightness"
msgid "High"
msgstr "Yüksək"
#: rog-control-center/ui/pages/anime.slint:23
msgctxt "AnimePageData"
msgid "Glitch Construction"
msgstr "Nasazlıq İnşaatı"
#: rog-control-center/ui/pages/anime.slint:23
msgctxt "AnimePageData"
msgid "Static Emergence"
msgstr "Statik Ortaya Çıxma"
#: rog-control-center/ui/pages/anime.slint:25
msgctxt "AnimePageData"
msgid "Binary Banner Scroll"
msgstr "İkili Afiş Sürüşdürmə"
#: rog-control-center/ui/pages/anime.slint:25
msgctxt "AnimePageData"
msgid "Rog Logo Glitch"
msgstr "Rog Logo Nasazlığı"
#: rog-control-center/ui/pages/anime.slint:27
msgctxt "AnimePageData"
msgid "Banner Swipe"
msgstr "Afiş Sürüşdürmə"
#: rog-control-center/ui/pages/anime.slint:27
msgctxt "AnimePageData"
msgid "Starfield"
msgstr "Ulduz Sahəsi"
#: rog-control-center/ui/pages/anime.slint:29
msgctxt "AnimePageData"
msgid "Glitch Out"
msgstr "Nasazlıq"
#: rog-control-center/ui/pages/anime.slint:29
msgctxt "AnimePageData"
msgid "See Ya"
msgstr "Görüşərik"
#: rog-control-center/ui/pages/anime.slint:50
msgctxt "Anime Brightness"
msgid "Brightness"
msgstr "Parlaqlıq"
#: rog-control-center/ui/pages/anime.slint:66
msgctxt "PageAnime"
msgid "Enable display"
msgstr "Ekranı aktivləşdir"
#: rog-control-center/ui/pages/anime.slint:74 rog-control-center/ui/pages/anime.slint:97
msgctxt "PageAnime"
msgid "Advanced"
msgstr "Qabaqcıl"
#: rog-control-center/ui/pages/anime.slint:89
msgctxt "PageAnime"
msgid "Use built-in animations"
msgstr "Yerləşik animasiyalardan istifadə edin"
#: rog-control-center/ui/pages/anime.slint:146
msgctxt "PageAnime"
msgid "Set which builtin animations are played"
msgstr "Hansı yerləşik animasiyaların oynadılacağını ayarlayın"
#: rog-control-center/ui/pages/anime.slint:150
msgctxt "Anime built-in selection"
msgid "Boot Animation"
msgstr "Açılış Animasiyası"
#: rog-control-center/ui/pages/anime.slint:160
msgctxt "Anime built-in selection"
msgid "Running Animation"
msgstr "İşləyən Animasiya"
#: rog-control-center/ui/pages/anime.slint:170
msgctxt "Anime built-in selection"
msgid "Sleep Animation"
msgstr "Yuxu Animasiyası"
#: rog-control-center/ui/pages/anime.slint:180
msgctxt "Anime built-in selection"
msgid "Shutdown Animation"
msgstr "Söndürmə Animasiyası"
#: rog-control-center/ui/pages/anime.slint:220
msgctxt "PageAnime"
msgid "Advanced Display Settings"
msgstr "Qabaqcıl Ekran Parametrləri"
#: rog-control-center/ui/pages/anime.slint:225
msgctxt "PageAnime"
msgid "Off when lid closed"
msgstr "Qapaq bağlandıqda söndür"
#: rog-control-center/ui/pages/anime.slint:234
msgctxt "PageAnime"
msgid "Off when suspended"
msgstr "Gözlədiləndə söndür"
#: rog-control-center/ui/pages/anime.slint:243
msgctxt "PageAnime"
msgid "Off when on battery"
msgstr "Batareyadaykən söndür"
#: rog-control-center/ui/pages/app_settings.slint:26
msgctxt "PageAppSettings"
msgid "Run in background after closing"
msgstr "Bağlandıqdan sonra arxafonda işlət"
#: rog-control-center/ui/pages/app_settings.slint:34
msgctxt "PageAppSettings"
msgid "Start app in background (UI closed)"
msgstr "Tətbiqi arxafonda başlat (İİ sönülü vəziyyətdə)"
#: rog-control-center/ui/pages/app_settings.slint:42
msgctxt "PageAppSettings"
msgid "Enable system tray icon"
msgstr "Sistem nimçə ikonunu aktivləşdir"
#: rog-control-center/ui/pages/app_settings.slint:50
msgctxt "PageAppSettings"
msgid "Enable dGPU notifications"
msgstr "Xarici ekran kartı bildirimlərini aktivləşdir"
#: rog-control-center/ui/pages/aura.slint:28
msgctxt "PageAura"
msgid "Brightness"
msgstr "Parlaqlıq"
#: rog-control-center/ui/pages/aura.slint:39
msgctxt "PageAura"
msgid "Aura mode"
msgstr "Aura rejimi"
#: rog-control-center/ui/pages/aura.slint:59
msgctxt "PageAura"
msgid "Colour 1"
msgstr "Rəng 1"
#: rog-control-center/ui/pages/aura.slint:85
msgctxt "PageAura"
msgid "Colour 2"
msgstr "Rəng 2"
#: rog-control-center/ui/pages/aura.slint:119
msgctxt "PageAura"
msgid "Zone"
msgstr "Qurşaq"
#: rog-control-center/ui/pages/aura.slint:142
msgctxt "PageAura"
msgid "Direction"
msgstr "İstiqamət"
#: rog-control-center/ui/pages/aura.slint:164
msgctxt "PageAura"
msgid "Speed"
msgstr "Sürət"
#: rog-control-center/ui/pages/aura.slint:185
msgctxt "PageAura"
msgid "Power Settings"
msgstr "Enerji Parametrləri"
#: rog-control-center/ui/pages/aura.slint:270
msgctxt "PageAura"
msgid "Power Zones"
msgstr "Enerji qurşaqları"
#: rog-control-center/ui/pages/fans.slint:26
msgctxt "FanTab"
msgid "This fan is not avilable on this machine"
msgstr "Bu ventilyator bu cihazda mövcud deyil"
#: rog-control-center/ui/pages/fans.slint:34
msgctxt "FanTab"
msgid "Enabled"
msgstr "Aktiv"
#: rog-control-center/ui/pages/fans.slint:43
msgctxt "FanTab"
msgid "Apply"
msgstr "Tətbiq et"
#: rog-control-center/ui/pages/fans.slint:51
msgctxt "FanTab"
msgid "Cancel"
msgstr "Ləğv et"
#: rog-control-center/ui/pages/fans.slint:59
msgctxt "FanTab"
msgid "Factory Default (all fans)"
msgstr "Zavod standartı (bütün ventilyatorlar)"
#: rog-control-center/ui/pages/fans.slint:72
msgctxt "PageFans"
msgid "Balanced"
msgstr "Balanslaşdırılmış"
#: rog-control-center/ui/pages/fans.slint:75 rog-control-center/ui/pages/fans.slint:134 rog-control-center/ui/pages/fans.slint:193
msgctxt "PageFans"
msgid "CPU"
msgstr "Prosessor"
#: rog-control-center/ui/pages/fans.slint:93 rog-control-center/ui/pages/fans.slint:152 rog-control-center/ui/pages/fans.slint:211
msgctxt "PageFans"
msgid "Mid"
msgstr "Orta"
#: rog-control-center/ui/pages/fans.slint:111 rog-control-center/ui/pages/fans.slint:170 rog-control-center/ui/pages/fans.slint:229
msgctxt "PageFans"
msgid "GPU"
msgstr "Ekran kartı"
#: rog-control-center/ui/pages/fans.slint:131
msgctxt "PageFans"
msgid "Performance"
msgstr "Performans"
#: rog-control-center/ui/pages/fans.slint:190
msgctxt "PageFans"
msgid "Quiet"
msgstr "Sakit"
#: rog-control-center/ui/pages/system.slint:26
msgctxt "SystemPageData"
msgid "Balanced"
msgstr "Balanslaşdırılmış"
#: rog-control-center/ui/pages/system.slint:26 rog-control-center/ui/pages/system.slint:30
msgctxt "SystemPageData"
msgid "Performance"
msgstr "Performans"
#: rog-control-center/ui/pages/system.slint:26
msgctxt "SystemPageData"
msgid "Quiet"
msgstr "Sakit"
#: rog-control-center/ui/pages/system.slint:29
msgctxt "SystemPageData"
msgid "Default"
msgstr "Standart"
#: rog-control-center/ui/pages/system.slint:31
msgctxt "SystemPageData"
msgid "BalancePerformance"
msgstr "Taraz-Performans"
#: rog-control-center/ui/pages/system.slint:32
msgctxt "SystemPageData"
msgid "BalancePower"
msgstr "Taraz-Enerji"
#: rog-control-center/ui/pages/system.slint:33
msgctxt "SystemPageData"
msgid "Power"
msgstr "Enerji"
#: rog-control-center/ui/pages/system.slint:110
msgctxt "PageSystem"
msgid "Base system settings"
msgstr "Əsas sistem parametrləri"
#: rog-control-center/ui/pages/system.slint:115
msgctxt "PageSystem"
msgid "Charge limit"
msgstr "Şarj limiti"
#: rog-control-center/ui/pages/system.slint:127
msgctxt "PageSystem"
msgid "Throttle Policy"
msgstr "Enerji Siyasəti"
#: rog-control-center/ui/pages/system.slint:137
msgctxt "PageSystem"
msgid "Advanced"
msgstr "Qabaqcıl"
#: rog-control-center/ui/pages/system.slint:149
msgctxt "PageSystem"
msgid "Panel Overdrive"
msgstr "Panel aşırma"
#: rog-control-center/ui/pages/system.slint:157
msgctxt "PageSystem"
msgid "MiniLED Mode"
msgstr "MiniLED Rejimi"
#: rog-control-center/ui/pages/system.slint:165
msgctxt "PageSystem"
msgid "POST boot sound"
msgstr "POST açılış səsi"
#: rog-control-center/ui/pages/system.slint:183
msgctxt "PageSystem"
msgid "System performance settings"
msgstr "Sistem performans parametrləri"
#: rog-control-center/ui/pages/system.slint:188
msgctxt "ppt_pl1_spl"
msgid "PL1, sustained power limit"
msgstr "ES1, davamlı enerji limiti"
#: rog-control-center/ui/pages/system.slint:198
msgctxt "ppt_pl2_sppt"
msgid "PL2, turbo power limit"
msgstr "ES2, turbo enerji limiti"
#: rog-control-center/ui/pages/system.slint:208
msgctxt "ppt_fppt"
msgid "FPPT, Fast Power Limit"
msgstr "SPEİ, sürətli enerji limiti"
#: rog-control-center/ui/pages/system.slint:218
msgctxt "ppt_apu_sppt"
msgid "SPPT, APU slow power limit"
msgstr "YPEİ, APU yavaş enerji limiti"
#: rog-control-center/ui/pages/system.slint:228
msgctxt "ppt_platform_sppt"
msgid "Slow package power tracking limit"
msgstr "Yavaş paket enerji izləmə limiti"
#: rog-control-center/ui/pages/system.slint:238
msgctxt "nv_dynamic_boost"
msgid "dGPU boost overclock"
msgstr "Xarici ekran kartının sürət aşırtma sürətini artırma"
#: rog-control-center/ui/pages/system.slint:248
msgctxt "nv_temp_target"
msgid "dGPU temperature max"
msgstr "Xarici ekran kartının maksimum temperaturu"
#: rog-control-center/ui/pages/system.slint:294
msgctxt "PageSystem"
msgid "Energy Performance Preference linked to Throttle Policy"
msgstr "Enerji Performans Üstünlüyü Enerji Siyasətinə bağlıdır"
#: rog-control-center/ui/pages/system.slint:298
msgctxt "PageSystem"
msgid "Change EPP based on Throttle Policy"
msgstr "EPÜ-yü Enerji Siyasəti üçün dəyişdirin"
#: rog-control-center/ui/pages/system.slint:306
msgctxt "PageSystem"
msgid "EPP for Balanced Policy"
msgstr "Balanslaşdırılmış Siyasət üçün EPÜ"
#: rog-control-center/ui/pages/system.slint:316
msgctxt "PageSystem"
msgid "EPP for Performance Policy"
msgstr "Perfomans Siyasəti üçün EPÜ"
#: rog-control-center/ui/pages/system.slint:326
msgctxt "PageSystem"
msgid "EPP for Quiet Policy"
msgstr "Sakit Siyasət üçün EPÜ"
#: rog-control-center/ui/pages/system.slint:344
msgctxt "PageSystem"
msgid "Throttle Policy for power state"
msgstr "Enerji vəziyyəti üçün Enerji Siyasəti"
#: rog-control-center/ui/pages/system.slint:350
msgctxt "PageSystem"
msgid "Throttle Policy on Battery"
msgstr "Batareyadaykən Enerji Siyasəti"
#: rog-control-center/ui/pages/system.slint:360 rog-control-center/ui/pages/system.slint:381
msgctxt "PageSystem"
msgid "Enabled"
msgstr "Aktiv"
#: rog-control-center/ui/pages/system.slint:371
msgctxt "PageSystem"
msgid "Throttle Policy on AC"
msgstr "Şarjdaykən Enerji Siyasəti"
#: rog-control-center/ui/types/aura_types.slint:49
msgctxt "Aura power zone"
msgid "Logo"
msgstr "Loqo"
#: rog-control-center/ui/types/aura_types.slint:50 rog-control-center/ui/types/aura_types.slint:59
msgctxt "Aura power zone"
msgid "Keyboard"
msgstr "Klaviatura"
#: rog-control-center/ui/types/aura_types.slint:51 rog-control-center/ui/types/aura_types.slint:60
msgctxt "Aura power zone"
msgid "Lightbar"
msgstr "İşıq Çubuğu"
#: rog-control-center/ui/types/aura_types.slint:52
msgctxt "Aura power zone"
msgid "Lid"
msgstr "Qapaq"
#: rog-control-center/ui/types/aura_types.slint:53
msgctxt "Aura power zone"
msgid "Rear Glow"
msgstr "Arxa Parıltı"
#: rog-control-center/ui/types/aura_types.slint:54 rog-control-center/ui/types/aura_types.slint:61
msgctxt "Aura power zone"
msgid "Keyboard and Lightbar"
msgstr "Klaviatura və İşıq Çubuğu"
#: rog-control-center/ui/types/aura_types.slint:64
msgctxt "Aura brightness"
msgid "Off"
msgstr "Sönülü"
#: rog-control-center/ui/types/aura_types.slint:65
msgctxt "Aura brightness"
msgid "Low"
msgstr "Aşağı"
#: rog-control-center/ui/types/aura_types.slint:66
msgctxt "Aura brightness"
msgid "Med"
msgstr "Orta"
#: rog-control-center/ui/types/aura_types.slint:67
msgctxt "Aura brightness"
msgid "High"
msgstr "Yüksək"
#: rog-control-center/ui/types/aura_types.slint:72 rog-control-center/ui/types/aura_types.slint:87
msgctxt "Basic aura mode"
msgid "Static"
msgstr "Statik"
#: rog-control-center/ui/types/aura_types.slint:73 rog-control-center/ui/types/aura_types.slint:88
msgctxt "Basic aura mode"
msgid "Breathe"
msgstr "Nəfəs Alma"
#: rog-control-center/ui/types/aura_types.slint:74 rog-control-center/ui/types/aura_types.slint:89
msgctxt "Basic aura mode"
msgid "Strobe"
msgstr "Fləş"
#: rog-control-center/ui/types/aura_types.slint:75
msgctxt "Basic aura mode"
msgid "Rainbow"
msgstr "Göyqurşağı"
#: rog-control-center/ui/types/aura_types.slint:76
msgctxt "Basic aura mode"
msgid "Star"
msgstr "Ulduz"
#: rog-control-center/ui/types/aura_types.slint:77
msgctxt "Basic aura mode"
msgid "Rain"
msgstr "Yağış"
#: rog-control-center/ui/types/aura_types.slint:78
msgctxt "Basic aura mode"
msgid "Highlight"
msgstr "Vurğulama"
#: rog-control-center/ui/types/aura_types.slint:79
msgctxt "Basic aura mode"
msgid "Laser"
msgstr "Lazer"
#: rog-control-center/ui/types/aura_types.slint:80
msgctxt "Basic aura mode"
msgid "Ripple"
msgstr "Dalğalanma"
#: rog-control-center/ui/types/aura_types.slint:81
msgctxt "Basic aura mode"
msgid "Nothing"
msgstr "Heç nə"
#: rog-control-center/ui/types/aura_types.slint:82
msgctxt "Basic aura mode"
msgid "Pulse"
msgstr "Nəbz"
#: rog-control-center/ui/types/aura_types.slint:83
msgctxt "Basic aura mode"
msgid "Comet"
msgstr "Quyruqlu Ulduz"
#: rog-control-center/ui/types/aura_types.slint:84
msgctxt "Basic aura mode"
msgid "Flash"
msgstr "Fləş"
#: rog-control-center/ui/types/aura_types.slint:96
msgctxt "Aura zone"
msgid "None"
msgstr "Heç biri"
#: rog-control-center/ui/types/aura_types.slint:97
msgctxt "Aura zone"
msgid "Key1"
msgstr "Açar1"
#: rog-control-center/ui/types/aura_types.slint:98
msgctxt "Aura zone"
msgid "Key2"
msgstr "Açar2"
#: rog-control-center/ui/types/aura_types.slint:99
msgctxt "Aura zone"
msgid "Key3"
msgstr "Açar3"
#: rog-control-center/ui/types/aura_types.slint:100
msgctxt "Aura zone"
msgid "Key4"
msgstr "Açar5"
#: rog-control-center/ui/types/aura_types.slint:101
msgctxt "Aura zone"
msgid "Logo"
msgstr "Loqo"
#: rog-control-center/ui/types/aura_types.slint:102
msgctxt "Aura zone"
msgid "Lightbar Left"
msgstr "İşıq Çubuğu Sol"
#: rog-control-center/ui/types/aura_types.slint:103
msgctxt "Aura zone"
msgid "Lightbar Right"
msgstr "İşıq Çubuğu Sağ"
#: rog-control-center/ui/types/aura_types.slint:107
msgctxt "Aura direction"
msgid "Right"
msgstr "Sağ"
#: rog-control-center/ui/types/aura_types.slint:108
msgctxt "Aura direction"
msgid "Left"
msgstr "Sol"
#: rog-control-center/ui/types/aura_types.slint:109
msgctxt "Aura direction"
msgid "Up"
msgstr "Yuxarı"
#: rog-control-center/ui/types/aura_types.slint:110
msgctxt "Aura direction"
msgid "Down"
msgstr "Aşağı"
#: rog-control-center/ui/types/aura_types.slint:114
msgctxt "Aura speed"
msgid "Low"
msgstr "Aşağı"
#: rog-control-center/ui/types/aura_types.slint:115
msgctxt "Aura speed"
msgid "Medium"
msgstr "Orta"
#: rog-control-center/ui/types/aura_types.slint:116
msgctxt "Aura speed"
msgid "High"
msgstr "Yüksək"
#: rog-control-center/ui/widgets/aura_power.slint:33
msgctxt "AuraPowerGroup"
msgid "Boot"
msgstr "Açılış"
#: rog-control-center/ui/widgets/aura_power.slint:43
msgctxt "AuraPowerGroup"
msgid "Awake"
msgstr "Oyaq"
#: rog-control-center/ui/widgets/aura_power.slint:53
msgctxt "AuraPowerGroup"
msgid "Sleep"
msgstr "Yuxu"
#: rog-control-center/ui/widgets/aura_power.slint:63
msgctxt "AuraPowerGroup"
msgid "Shutdown"
msgstr "Söndür"
#: rog-control-center/ui/widgets/aura_power.slint:102
msgctxt "AuraPowerGroupOld"
msgid "Zone Selection"
msgstr "Bölgə seçimi"
#: rog-control-center/ui/widgets/aura_power.slint:114
msgctxt "AuraPowerGroupOld"
msgid "Boot"
msgstr "Açılış"
#: rog-control-center/ui/widgets/aura_power.slint:124
msgctxt "AuraPowerGroupOld"
msgid "Awake"
msgstr "Oyaq"
#: rog-control-center/ui/widgets/aura_power.slint:134
msgctxt "AuraPowerGroupOld"
msgid "Sleep"
msgstr "Yuxu"
#: rog-control-center/ui/main_window.slint:51
msgctxt "MainWindow"
msgid "ROG"
msgstr ""
#: rog-control-center/ui/main_window.slint:53
msgctxt "Menu1"
msgid "System Control"
msgstr "Sistem Nəzarəti"
#: rog-control-center/ui/main_window.slint:54
msgctxt "Menu2"
msgid "Keyboard Aura"
msgstr "Klaviatura Aura"
#: rog-control-center/ui/main_window.slint:55
msgctxt "Menu3"
msgid "AniMe Matrix"
msgstr "AniMe Matrisi"
#: rog-control-center/ui/main_window.slint:56
msgctxt "Menu4"
msgid "Fan Curves"
msgstr "Fan Əyriləri"
#: rog-control-center/ui/main_window.slint:57
msgctxt "Menu5"
msgid "App Settings"
msgstr "Tətbiq Parametrləri"
#: rog-control-center/ui/main_window.slint:58
msgctxt "Menu6"
msgid "About"
msgstr "Haqqında"
#: rog-control-center/ui/main_window.slint:70
msgctxt "MainWindow"
msgid "Quit App"
msgstr "Tətbiqdən Çıxın"

View File

@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-12-24 22:29+0000\n"
"POT-Creation-Date: 2025-04-05 19:36+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -12,204 +12,44 @@ msgstr ""
"Language: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: rog-control-center/ui/pages/system.slint:26
msgctxt "SystemPageData"
msgid "Balanced"
#: rog-control-center/ui/main_window.slint:55
msgctxt "MainWindow"
msgid "ROG"
msgstr ""
#: rog-control-center/ui/pages/system.slint:26 rog-control-center/ui/pages/system.slint:30
msgctxt "SystemPageData"
msgid "Performance"
#: rog-control-center/ui/main_window.slint:57
msgctxt "Menu1"
msgid "System Control"
msgstr ""
#: rog-control-center/ui/pages/system.slint:26
msgctxt "SystemPageData"
msgid "Quiet"
#: rog-control-center/ui/main_window.slint:58
msgctxt "Menu2"
msgid "Keyboard Aura"
msgstr ""
#: rog-control-center/ui/pages/system.slint:29
msgctxt "SystemPageData"
msgid "Default"
#: rog-control-center/ui/main_window.slint:59
msgctxt "Menu3"
msgid "AniMe Matrix"
msgstr ""
#: rog-control-center/ui/pages/system.slint:31
msgctxt "SystemPageData"
msgid "BalancePerformance"
#: rog-control-center/ui/main_window.slint:60
msgctxt "Menu4"
msgid "Fan Curves"
msgstr ""
#: rog-control-center/ui/pages/system.slint:32
msgctxt "SystemPageData"
msgid "BalancePower"
#: rog-control-center/ui/main_window.slint:61
msgctxt "Menu5"
msgid "App Settings"
msgstr ""
#: rog-control-center/ui/pages/system.slint:33
msgctxt "SystemPageData"
msgid "Power"
#: rog-control-center/ui/main_window.slint:62
msgctxt "Menu6"
msgid "About"
msgstr ""
#: rog-control-center/ui/pages/system.slint:110
msgctxt "PageSystem"
msgid "Base system settings"
msgstr ""
#: rog-control-center/ui/pages/system.slint:115
msgctxt "PageSystem"
msgid "Charge limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:127
msgctxt "PageSystem"
msgid "Throttle Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:137
msgctxt "PageSystem"
msgid "Advanced"
msgstr ""
#: rog-control-center/ui/pages/system.slint:149
msgctxt "PageSystem"
msgid "Panel Overdrive"
msgstr ""
#: rog-control-center/ui/pages/system.slint:157
msgctxt "PageSystem"
msgid "MiniLED Mode"
msgstr ""
#: rog-control-center/ui/pages/system.slint:165
msgctxt "PageSystem"
msgid "POST boot sound"
msgstr ""
#: rog-control-center/ui/pages/system.slint:183
msgctxt "PageSystem"
msgid "System performance settings"
msgstr ""
#: rog-control-center/ui/pages/system.slint:188
msgctxt "ppt_pl1_spl"
msgid "PL1, sustained power limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:198
msgctxt "ppt_pl2_sppt"
msgid "PL2, turbo power limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:208
msgctxt "ppt_fppt"
msgid "FPPT, Fast Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:218
msgctxt "ppt_apu_sppt"
msgid "SPPT, APU slow power limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:228
msgctxt "ppt_platform_sppt"
msgid "Slow package power tracking limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:238
msgctxt "nv_dynamic_boost"
msgid "dGPU boost overclock"
msgstr ""
#: rog-control-center/ui/pages/system.slint:248
msgctxt "nv_temp_target"
msgid "dGPU temperature max"
msgstr ""
#: rog-control-center/ui/pages/system.slint:294
msgctxt "PageSystem"
msgid "Energy Performance Preference linked to Throttle Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:298
msgctxt "PageSystem"
msgid "Change EPP based on Throttle Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:306
msgctxt "PageSystem"
msgid "EPP for Balanced Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:316
msgctxt "PageSystem"
msgid "EPP for Performance Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:326
msgctxt "PageSystem"
msgid "EPP for Quiet Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:344
msgctxt "PageSystem"
msgid "Throttle Policy for power state"
msgstr ""
#: rog-control-center/ui/pages/system.slint:350
msgctxt "PageSystem"
msgid "Throttle Policy on Battery"
msgstr ""
#: rog-control-center/ui/pages/system.slint:360 rog-control-center/ui/pages/system.slint:381
msgctxt "PageSystem"
msgid "Enabled"
msgstr ""
#: rog-control-center/ui/pages/system.slint:371
msgctxt "PageSystem"
msgid "Throttle Policy on AC"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:28
msgctxt "PageAura"
msgid "Brightness"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:39
msgctxt "PageAura"
msgid "Aura mode"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:59
msgctxt "PageAura"
msgid "Colour 1"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:85
msgctxt "PageAura"
msgid "Colour 2"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:119
msgctxt "PageAura"
msgid "Zone"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:142
msgctxt "PageAura"
msgid "Direction"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:164
msgctxt "PageAura"
msgid "Speed"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:185
msgctxt "PageAura"
msgid "Power Settings"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:270
msgctxt "PageAura"
msgid "Power Zones"
#: rog-control-center/ui/main_window.slint:74
msgctxt "MainWindow"
msgid "Quit App"
msgstr ""
#: rog-control-center/ui/pages/anime.slint:6
@@ -337,6 +177,322 @@ msgctxt "PageAnime"
msgid "Off when on battery"
msgstr ""
#: rog-control-center/ui/pages/system.slint:20
msgctxt "SystemPageData"
msgid "Balanced"
msgstr ""
#: rog-control-center/ui/pages/system.slint:20 rog-control-center/ui/pages/system.slint:27
msgctxt "SystemPageData"
msgid "Performance"
msgstr ""
#: rog-control-center/ui/pages/system.slint:20
msgctxt "SystemPageData"
msgid "Quiet"
msgstr ""
#: rog-control-center/ui/pages/system.slint:20
msgctxt "SystemPageData"
msgid "LowPower"
msgstr ""
#: rog-control-center/ui/pages/system.slint:26
msgctxt "SystemPageData"
msgid "Default"
msgstr ""
#: rog-control-center/ui/pages/system.slint:28
msgctxt "SystemPageData"
msgid "BalancePerformance"
msgstr ""
#: rog-control-center/ui/pages/system.slint:29
msgctxt "SystemPageData"
msgid "BalancePower"
msgstr ""
#: rog-control-center/ui/pages/system.slint:30
msgctxt "SystemPageData"
msgid "Power"
msgstr ""
#: rog-control-center/ui/pages/system.slint:159
msgctxt "PageSystem"
msgid "Power settings"
msgstr ""
#: rog-control-center/ui/pages/system.slint:164
msgctxt "PageSystem"
msgid "Charge limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:179
msgctxt "PageSystem"
msgid "Platform Profile"
msgstr ""
#: rog-control-center/ui/pages/system.slint:189
msgctxt "PageSystem"
msgid "Advanced"
msgstr ""
#: rog-control-center/ui/pages/system.slint:209
msgctxt "PageSystem"
msgid "Screenpad brightness"
msgstr ""
#: rog-control-center/ui/pages/system.slint:233
msgctxt "PageSystem"
msgid "Sync with primary"
msgstr ""
#: rog-control-center/ui/pages/system.slint:253
msgctxt "PageSystem"
msgid "Armoury settings"
msgstr ""
#: rog-control-center/ui/pages/system.slint:263
msgctxt "no_asus_armoury_driver_1"
msgid "The asus-armoury driver is not loaded"
msgstr ""
#: rog-control-center/ui/pages/system.slint:269
msgctxt "no_asus_armoury_driver_2"
msgid "For advanced features you will require a kernel with this driver added."
msgstr ""
#: rog-control-center/ui/pages/system.slint:280
msgctxt "PageSystem"
msgid "Panel Overdrive"
msgstr ""
#: rog-control-center/ui/pages/system.slint:288
msgctxt "PageSystem"
msgid "MiniLED Mode"
msgstr ""
#: rog-control-center/ui/pages/system.slint:296
msgctxt "PageSystem"
msgid "POST boot sound"
msgstr ""
#: rog-control-center/ui/pages/system.slint:312
msgctxt "ppt_warning"
msgid "The following settings are not applied until the toggle is enabled."
msgstr ""
#: rog-control-center/ui/pages/system.slint:317 rog-control-center/ui/pages/system.slint:324
msgctxt "ppt_group_enabled"
msgid "Enable Tuning"
msgstr ""
#: rog-control-center/ui/pages/system.slint:334 rog-control-center/ui/pages/system.slint:335
msgctxt "ppt_pl1_spl"
msgid "CPU Sustained Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:336
msgctxt "ppt_pl1_spl_help"
msgid ""
"Long-term CPU power limit that affects sustained workload performance. "
"Higher values may increase heat and power consumption."
msgstr ""
#: rog-control-center/ui/pages/system.slint:352 rog-control-center/ui/pages/system.slint:353
msgctxt "ppt_pl2_sppt"
msgid "CPU Turbo Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:354
msgctxt "ppt_pl2_sppt_help"
msgid ""
"Short-term CPU power limit for boost periods. Controls maximum power during "
"brief high-performance bursts."
msgstr ""
#: rog-control-center/ui/pages/system.slint:370 rog-control-center/ui/pages/system.slint:371
msgctxt "ppt_pl3_fppt"
msgid "CPU Fast Burst Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:372
msgctxt "ppt_pl3_fppt_help"
msgid ""
"Ultra-short duration power limit for instantaneous CPU bursts. Affects "
"responsiveness during sudden workload spikes."
msgstr ""
#: rog-control-center/ui/pages/system.slint:387 rog-control-center/ui/pages/system.slint:388
msgctxt "ppt_fppt"
msgid "Fast Package Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:389
msgctxt "ppt_fppt_help"
msgid ""
"Ultra-short duration power limit for system package. Controls maximum power "
"during millisecond-scale load spikes."
msgstr ""
#: rog-control-center/ui/pages/system.slint:405 rog-control-center/ui/pages/system.slint:406
msgctxt "ppt_apu_sppt"
msgid "APU Sustained Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:407
msgctxt "ppt_apu_sppt_help"
msgid ""
"Long-term power limit for integrated graphics and CPU combined. Affects "
"sustained performance of APU-based workloads."
msgstr ""
#: rog-control-center/ui/pages/system.slint:423 rog-control-center/ui/pages/system.slint:424
msgctxt "ppt_platform_sppt"
msgid "Platform Sustained Power Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:425
msgctxt "ppt_platform_sppt_help"
msgid ""
"Overall system power limit for sustained operations. Controls total platform "
"power consumption over extended periods."
msgstr ""
#: rog-control-center/ui/pages/system.slint:441 rog-control-center/ui/pages/system.slint:442
msgctxt "nv_dynamic_boost"
msgid "GPU Power Boost"
msgstr ""
#: rog-control-center/ui/pages/system.slint:443
msgctxt "nv_dynamic_boost_help"
msgid ""
"Additional power allocation for GPU dynamic boost. Higher values increase "
"GPU performance but generate more heat."
msgstr ""
#: rog-control-center/ui/pages/system.slint:459 rog-control-center/ui/pages/system.slint:460
msgctxt "nv_temp_target"
msgid "GPU Temperature Limit"
msgstr ""
#: rog-control-center/ui/pages/system.slint:461
msgctxt "nv_temp_target_help"
msgid ""
"Maximum GPU temperature threshold in Celsius. GPU will throttle to maintain "
"temperature below this limit."
msgstr ""
#: rog-control-center/ui/pages/system.slint:513
msgctxt "PageSystem"
msgid "Energy Performance Preference linked to Throttle Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:517
msgctxt "PageSystem"
msgid "Change EPP based on Throttle Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:525
msgctxt "PageSystem"
msgid "EPP for Balanced Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:535
msgctxt "PageSystem"
msgid "EPP for Performance Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:545
msgctxt "PageSystem"
msgid "EPP for Quiet Policy"
msgstr ""
#: rog-control-center/ui/pages/system.slint:563
msgctxt "PageSystem"
msgid "Throttle Policy for power state"
msgstr ""
#: rog-control-center/ui/pages/system.slint:569
msgctxt "PageSystem"
msgid "Throttle Policy on Battery"
msgstr ""
#: rog-control-center/ui/pages/system.slint:579 rog-control-center/ui/pages/system.slint:600
msgctxt "PageSystem"
msgid "Enabled"
msgstr ""
#: rog-control-center/ui/pages/system.slint:590
msgctxt "PageSystem"
msgid "Throttle Policy on AC"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:28
msgctxt "PageAura"
msgid "Brightness"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:39
msgctxt "PageAura"
msgid "Aura mode"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:59
msgctxt "PageAura"
msgid "Colour 1"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:85
msgctxt "PageAura"
msgid "Colour 2"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:119
msgctxt "PageAura"
msgid "Zone"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:142
msgctxt "PageAura"
msgid "Direction"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:164
msgctxt "PageAura"
msgid "Speed"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:185
msgctxt "PageAura"
msgid "Power Settings"
msgstr ""
#: rog-control-center/ui/pages/aura.slint:270
msgctxt "PageAura"
msgid "Power Zones"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:26
msgctxt "PageAppSettings"
msgid "Run in background after closing"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:34
msgctxt "PageAppSettings"
msgid "Start app in background (UI closed)"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:42
msgctxt "PageAppSettings"
msgid "Enable system tray icon"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:50
msgctxt "PageAppSettings"
msgid "Enable dGPU notifications"
msgstr ""
#: rog-control-center/ui/pages/fans.slint:26
msgctxt "FanTab"
msgid "This fan is not avilable on this machine"
@@ -392,24 +548,49 @@ msgctxt "PageFans"
msgid "Quiet"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:26
msgctxt "PageAppSettings"
msgid "Run in background after closing"
#: rog-control-center/ui/widgets/common.slint:126
msgctxt "confirm_reset"
msgid "Are you sure you want to reset this?"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:34
msgctxt "PageAppSettings"
msgid "Start app in background (UI closed)"
#: rog-control-center/ui/widgets/aura_power.slint:33
msgctxt "AuraPowerGroup"
msgid "Boot"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:42
msgctxt "PageAppSettings"
msgid "Enable system tray icon"
#: rog-control-center/ui/widgets/aura_power.slint:43
msgctxt "AuraPowerGroup"
msgid "Awake"
msgstr ""
#: rog-control-center/ui/pages/app_settings.slint:50
msgctxt "PageAppSettings"
msgid "Enable dGPU notifications"
#: rog-control-center/ui/widgets/aura_power.slint:53
msgctxt "AuraPowerGroup"
msgid "Sleep"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:63
msgctxt "AuraPowerGroup"
msgid "Shutdown"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:102
msgctxt "AuraPowerGroupOld"
msgid "Zone Selection"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:114
msgctxt "AuraPowerGroupOld"
msgid "Boot"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:124
msgctxt "AuraPowerGroupOld"
msgid "Awake"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:134
msgctxt "AuraPowerGroupOld"
msgid "Sleep"
msgstr ""
#: rog-control-center/ui/types/aura_types.slint:52
@@ -607,83 +788,3 @@ msgctxt "Aura speed"
msgid "High"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:33
msgctxt "AuraPowerGroup"
msgid "Boot"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:43
msgctxt "AuraPowerGroup"
msgid "Awake"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:53
msgctxt "AuraPowerGroup"
msgid "Sleep"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:63
msgctxt "AuraPowerGroup"
msgid "Shutdown"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:102
msgctxt "AuraPowerGroupOld"
msgid "Zone Selection"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:114
msgctxt "AuraPowerGroupOld"
msgid "Boot"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:124
msgctxt "AuraPowerGroupOld"
msgid "Awake"
msgstr ""
#: rog-control-center/ui/widgets/aura_power.slint:134
msgctxt "AuraPowerGroupOld"
msgid "Sleep"
msgstr ""
#: rog-control-center/ui/main_window.slint:51
msgctxt "MainWindow"
msgid "ROG"
msgstr ""
#: rog-control-center/ui/main_window.slint:53
msgctxt "Menu1"
msgid "System Control"
msgstr ""
#: rog-control-center/ui/main_window.slint:54
msgctxt "Menu2"
msgid "Keyboard Aura"
msgstr ""
#: rog-control-center/ui/main_window.slint:55
msgctxt "Menu3"
msgid "AniMe Matrix"
msgstr ""
#: rog-control-center/ui/main_window.slint:56
msgctxt "Menu4"
msgid "Fan Curves"
msgstr ""
#: rog-control-center/ui/main_window.slint:57
msgctxt "Menu5"
msgid "App Settings"
msgstr ""
#: rog-control-center/ui/main_window.slint:58
msgctxt "Menu6"
msgid "About"
msgstr ""
#: rog-control-center/ui/main_window.slint:70
msgctxt "MainWindow"
msgid "Quit App"
msgstr ""

View File

@@ -0,0 +1,771 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2025-03-01 07:51+0000\n"
"PO-Revision-Date: 2025-03-18 00:19-0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.5\n"
#: rog-control-center/ui/pages/system.slint:20
msgctxt "SystemPageData"
msgid "Balanced"
msgstr "Equilibrado"
#: rog-control-center/ui/pages/system.slint:20 rog-control-center/ui/pages/system.slint:24
msgctxt "SystemPageData"
msgid "Performance"
msgstr "Performance"
#: rog-control-center/ui/pages/system.slint:20
msgctxt "SystemPageData"
msgid "Quiet"
msgstr "Silencioso"
#: rog-control-center/ui/pages/system.slint:23
msgctxt "SystemPageData"
msgid "Default"
msgstr "Padrão"
#: rog-control-center/ui/pages/system.slint:25
msgctxt "SystemPageData"
msgid "BalancePerformance"
msgstr "Equilibrado Performance"
#: rog-control-center/ui/pages/system.slint:26
msgctxt "SystemPageData"
msgid "BalancePower"
msgstr "Equilibrado Força"
#: rog-control-center/ui/pages/system.slint:27
msgctxt "SystemPageData"
msgid "Power"
msgstr "Energia"
#: rog-control-center/ui/pages/system.slint:147
msgctxt "PageSystem"
msgid "Power settings"
msgstr "Configurações de Energia"
#: rog-control-center/ui/pages/system.slint:152
msgctxt "PageSystem"
msgid "Charge limit"
msgstr "Limite de Carga"
#: rog-control-center/ui/pages/system.slint:167
msgctxt "PageSystem"
msgid "Platform Profile"
msgstr "Perfil de Plataforma"
#: rog-control-center/ui/pages/system.slint:177
msgctxt "PageSystem"
msgid "Advanced"
msgstr "Avançado"
#: rog-control-center/ui/pages/system.slint:195
msgctxt "PageSystem"
msgid "Armoury settings"
msgstr "Configurações Armoury"
#: rog-control-center/ui/pages/system.slint:205
msgctxt "no_asus_armoury_driver_1"
msgid "The asus-armoury driver is not loaded"
msgstr "O driver asus-armoury não está carregado"
#: rog-control-center/ui/pages/system.slint:211
msgctxt "no_asus_armoury_driver_2"
msgid "For advanced features you will require a kernel with this driver added."
msgstr "Para recursos avançados é necessário um Kernel com esse driver adicionado."
#: rog-control-center/ui/pages/system.slint:222
msgctxt "PageSystem"
msgid "Panel Overdrive"
msgstr "Overdrive do Painel"
#: rog-control-center/ui/pages/system.slint:230
msgctxt "PageSystem"
msgid "MiniLED Mode"
msgstr "Modo MiniLED"
#: rog-control-center/ui/pages/system.slint:238
msgctxt "PageSystem"
msgid "POST boot sound"
msgstr "Som PÓS inicialização"
#: rog-control-center/ui/pages/system.slint:254
msgctxt "ppt_warning"
msgid "The following settings are not applied until the toggle is enabled."
msgstr "As seguintes configurações não são aplicadas até que o seletor esteja habilitado."
#: rog-control-center/ui/pages/system.slint:259 rog-control-center/ui/pages/system.slint:266
msgctxt "ppt_group_enabled"
msgid "Enable Tuning"
msgstr "Habilitar ajustes"
#: rog-control-center/ui/pages/system.slint:277 rog-control-center/ui/pages/system.slint:278
msgctxt "ppt_pl1_spl"
msgid "CPU Sustained Power Limit"
msgstr "Limite Sustentado de Energia da CPU"
#: rog-control-center/ui/pages/system.slint:279
msgctxt "ppt_pl1_spl_help"
msgid ""
"Long-term CPU power limit that affects sustained workload performance. Higher values may increase heat and power consumption."
msgstr ""
"Limite de Energia da CPU que afeta o desempenho de cargas sustentada de trabalho. Valores mais altos podem aumentar a "
"temperatura e o consumo de energia."
#: rog-control-center/ui/pages/system.slint:295 rog-control-center/ui/pages/system.slint:296
msgctxt "ppt_pl2_sppt"
msgid "CPU Turbo Power Limit"
msgstr "Limite Turbo de Energia da CPU"
#: rog-control-center/ui/pages/system.slint:297
msgctxt "ppt_pl2_sppt_help"
msgid "Short-term CPU power limit for boost periods. Controls maximum power during brief high-performance bursts."
msgstr ""
"Limite de Energia de curto prazo do Processador para períodos de picos rápidos. Controla a Energia máxima durante picos curtos "
"de alta performance."
#: rog-control-center/ui/pages/system.slint:313 rog-control-center/ui/pages/system.slint:314
msgctxt "ppt_pl3_fppt"
msgid "CPU Fast Burst Power Limit"
msgstr "Limite de energia de pico rápido da CPU"
#: rog-control-center/ui/pages/system.slint:315
msgctxt "ppt_pl3_fppt_help"
msgid "Ultra-short duration power limit for instantaneous CPU bursts. Affects responsiveness during sudden workload spikes."
msgstr ""
"Limite de Energia de duração ultra-curta para picos instantâneos de Processamento. Afeta a responsividade durante picos de "
"trabalho repentinos."
#: rog-control-center/ui/pages/system.slint:330 rog-control-center/ui/pages/system.slint:331
msgctxt "ppt_fppt"
msgid "Fast Package Power Limit"
msgstr "Limite de Energia Rápido do Pacote"
#: rog-control-center/ui/pages/system.slint:332
msgctxt "ppt_fppt_help"
msgid "Ultra-short duration power limit for system package. Controls maximum power during millisecond-scale load spikes."
msgstr ""
"Limite de energia do pacote do sistema de duração ultra curta. Controla a energia máxima durante picos de carga em escala de "
"milissegundos."
#: rog-control-center/ui/pages/system.slint:348 rog-control-center/ui/pages/system.slint:349
msgctxt "ppt_apu_sppt"
msgid "APU Sustained Power Limit"
msgstr "Limite de Força Sustentada para APU"
#: rog-control-center/ui/pages/system.slint:350
msgctxt "ppt_apu_sppt_help"
msgid "Long-term power limit for integrated graphics and CPU combined. Affects sustained performance of APU-based workloads."
msgstr ""
"Limite de Força de Longo-termo para Gráficos Integrados e Processador combinados.Afeta a perfomance sustentada em cargas "
"baseadas na APU."
#: rog-control-center/ui/pages/system.slint:366 rog-control-center/ui/pages/system.slint:367
msgctxt "ppt_platform_sppt"
msgid "Platform Sustained Power Limit"
msgstr "Limite de Força Sustentado da Plataforma"
#: rog-control-center/ui/pages/system.slint:368
msgctxt "ppt_platform_sppt_help"
msgid "Overall system power limit for sustained operations. Controls total platform power consumption over extended periods."
msgstr "Limite geral de força do sistema para operações prolongadas. Controla o Consumo total de força por períodos extendidos."
#: rog-control-center/ui/pages/system.slint:384 rog-control-center/ui/pages/system.slint:385
msgctxt "nv_dynamic_boost"
msgid "GPU Power Boost"
msgstr "Incremento de força da GPU"
#: rog-control-center/ui/pages/system.slint:386
msgctxt "nv_dynamic_boost_help"
msgid "Additional power allocation for GPU dynamic boost. Higher values increase GPU performance but generate more heat."
msgstr ""
"Alocação adicional de força para o Aumento dinâmico da GPU. Valores mais altosaumentam a perfomance da GPU ao custo de gerar "
"mais calor."
#: rog-control-center/ui/pages/system.slint:402 rog-control-center/ui/pages/system.slint:403
msgctxt "nv_temp_target"
msgid "GPU Temperature Limit"
msgstr "Limite de Temperatura da GPU"
#: rog-control-center/ui/pages/system.slint:404
msgctxt "nv_temp_target_help"
msgid "Maximum GPU temperature threshold in Celsius. GPU will throttle to maintain temperature below this limit."
msgstr "Limite de Temperatura Máxima da GPU em Celsius.A GPU irá desacelerar para manter A Temperatura abaixo deste Limite."
#: rog-control-center/ui/pages/system.slint:456
msgctxt "PageSystem"
msgid "Energy Performance Preference linked to Throttle Policy"
msgstr "Preferência de Performance Energética ligada a Política de Proteção de Sobre-aquecimento"
#: rog-control-center/ui/pages/system.slint:460
msgctxt "PageSystem"
msgid "Change EPP based on Throttle Policy"
msgstr "Alterar o PPE baseado na Política de Proteção de Sobre-aquecimento"
#: rog-control-center/ui/pages/system.slint:468
msgctxt "PageSystem"
msgid "EPP for Balanced Policy"
msgstr "PPE para a Política Equilibrada"
#: rog-control-center/ui/pages/system.slint:478
msgctxt "PageSystem"
msgid "EPP for Performance Policy"
msgstr "PPE para a Política de Desempenho"
#: rog-control-center/ui/pages/system.slint:488
msgctxt "PageSystem"
msgid "EPP for Quiet Policy"
msgstr "PPE para a Política Silenciosa"
#: rog-control-center/ui/pages/system.slint:506
msgctxt "PageSystem"
msgid "Throttle Policy for power state"
msgstr "Política de Proteção de Sobre-aquecimento para o Estaddo de Força"
#: rog-control-center/ui/pages/system.slint:512
msgctxt "PageSystem"
msgid "Throttle Policy on Battery"
msgstr "Política de Proteção de Sobre-aquecimento Ligado na Bateria"
#: rog-control-center/ui/pages/system.slint:522 rog-control-center/ui/pages/system.slint:543
msgctxt "PageSystem"
msgid "Enabled"
msgstr "Habilitado"
#: rog-control-center/ui/pages/system.slint:533
msgctxt "PageSystem"
msgid "Throttle Policy on AC"
msgstr "Política de Proteção de Sobre-aquecimento Ligado na Fonte"
#: rog-control-center/ui/pages/aura.slint:28
msgctxt "PageAura"
msgid "Brightness"
msgstr "Brilho"
#: rog-control-center/ui/pages/aura.slint:39
msgctxt "PageAura"
msgid "Aura mode"
msgstr "Modo Aura"
#: rog-control-center/ui/pages/aura.slint:59
msgctxt "PageAura"
msgid "Colour 1"
msgstr "Cor 1"
#: rog-control-center/ui/pages/aura.slint:85
msgctxt "PageAura"
msgid "Colour 2"
msgstr "Cor 2"
#: rog-control-center/ui/pages/aura.slint:119
msgctxt "PageAura"
msgid "Zone"
msgstr "Zona"
#: rog-control-center/ui/pages/aura.slint:142
msgctxt "PageAura"
msgid "Direction"
msgstr "Direção"
#: rog-control-center/ui/pages/aura.slint:164
msgctxt "PageAura"
msgid "Speed"
msgstr "Velocidade"
#: rog-control-center/ui/pages/aura.slint:185
msgctxt "PageAura"
msgid "Power Settings"
msgstr "Configurações de Energia"
#: rog-control-center/ui/pages/aura.slint:270
msgctxt "PageAura"
msgid "Power Zones"
msgstr "Zonas de Energia"
#: rog-control-center/ui/pages/anime.slint:6
msgctxt "Anime Brightness"
msgid "Off"
msgstr "Desligado"
#: rog-control-center/ui/pages/anime.slint:7
msgctxt "Anime Brightness"
msgid "Low"
msgstr "Baixo"
#: rog-control-center/ui/pages/anime.slint:8
msgctxt "Anime Brightness"
msgid "Med"
msgstr "Médio"
#: rog-control-center/ui/pages/anime.slint:9
msgctxt "Anime Brightness"
msgid "High"
msgstr "Alto"
#: rog-control-center/ui/pages/anime.slint:23
msgctxt "AnimePageData"
msgid "Glitch Construction"
msgstr "Construção de Falha"
#: rog-control-center/ui/pages/anime.slint:23
msgctxt "AnimePageData"
msgid "Static Emergence"
msgstr "Emergência Estática"
#: rog-control-center/ui/pages/anime.slint:25
msgctxt "AnimePageData"
msgid "Binary Banner Scroll"
msgstr "Rolagem Binária de Banner"
#: rog-control-center/ui/pages/anime.slint:25
msgctxt "AnimePageData"
msgid "Rog Logo Glitch"
msgstr "Falha no Logo ROG"
#: rog-control-center/ui/pages/anime.slint:27
msgctxt "AnimePageData"
msgid "Banner Swipe"
msgstr "Deslizamento de Banner"
#: rog-control-center/ui/pages/anime.slint:27
msgctxt "AnimePageData"
msgid "Starfield"
msgstr "Campo Estelar"
#: rog-control-center/ui/pages/anime.slint:29
msgctxt "AnimePageData"
msgid "Glitch Out"
msgstr "Falhando"
#: rog-control-center/ui/pages/anime.slint:29
msgctxt "AnimePageData"
msgid "See Ya"
msgstr "Te Vejo por Aí"
#: rog-control-center/ui/pages/anime.slint:50
msgctxt "Anime Brightness"
msgid "Brightness"
msgstr "Brilho"
#: rog-control-center/ui/pages/anime.slint:66
msgctxt "PageAnime"
msgid "Enable display"
msgstr "Habilitar Tela"
#: rog-control-center/ui/pages/anime.slint:74 rog-control-center/ui/pages/anime.slint:97
msgctxt "PageAnime"
msgid "Advanced"
msgstr "Avançado"
#: rog-control-center/ui/pages/anime.slint:89
msgctxt "PageAnime"
msgid "Use built-in animations"
msgstr "Usar animações padrão"
#: rog-control-center/ui/pages/anime.slint:146
msgctxt "PageAnime"
msgid "Set which builtin animations are played"
msgstr "Definir quais animações padrão são tocadas"
#: rog-control-center/ui/pages/anime.slint:150
msgctxt "Anime built-in selection"
msgid "Boot Animation"
msgstr "Animação de Inicilização"
#: rog-control-center/ui/pages/anime.slint:160
msgctxt "Anime built-in selection"
msgid "Running Animation"
msgstr "Animação de Execução"
#: rog-control-center/ui/pages/anime.slint:170
msgctxt "Anime built-in selection"
msgid "Sleep Animation"
msgstr "Animação de Dormir"
#: rog-control-center/ui/pages/anime.slint:180
msgctxt "Anime built-in selection"
msgid "Shutdown Animation"
msgstr "Animação de Desligamento"
#: rog-control-center/ui/pages/anime.slint:220
msgctxt "PageAnime"
msgid "Advanced Display Settings"
msgstr "Configurações Avançadas da Tela"
#: rog-control-center/ui/pages/anime.slint:225
msgctxt "PageAnime"
msgid "Off when lid closed"
msgstr "Desligado quando a tampa estiver fechada"
#: rog-control-center/ui/pages/anime.slint:234
msgctxt "PageAnime"
msgid "Off when suspended"
msgstr "Desligado enquanto suspenso"
#: rog-control-center/ui/pages/anime.slint:243
msgctxt "PageAnime"
msgid "Off when on battery"
msgstr "Desligado enquanto na bateria"
#: rog-control-center/ui/pages/fans.slint:26
msgctxt "FanTab"
msgid "This fan is not avilable on this machine"
msgstr "Esta ventoinha não está disponível nessa máquina"
#: rog-control-center/ui/pages/fans.slint:34
msgctxt "FanTab"
msgid "Enabled"
msgstr "Habilitado"
#: rog-control-center/ui/pages/fans.slint:43
msgctxt "FanTab"
msgid "Apply"
msgstr "Aplicar"
#: rog-control-center/ui/pages/fans.slint:51
msgctxt "FanTab"
msgid "Cancel"
msgstr "Cancelar"
#: rog-control-center/ui/pages/fans.slint:59
msgctxt "FanTab"
msgid "Factory Default (all fans)"
msgstr "Padrão de Fabrica (todas as ventoinhas)"
#: rog-control-center/ui/pages/fans.slint:72
msgctxt "PageFans"
msgid "Balanced"
msgstr "Equilibrado"
#: rog-control-center/ui/pages/fans.slint:75 rog-control-center/ui/pages/fans.slint:134 rog-control-center/ui/pages/fans.slint:193
msgctxt "PageFans"
msgid "CPU"
msgstr "Processador"
#: rog-control-center/ui/pages/fans.slint:93 rog-control-center/ui/pages/fans.slint:152 rog-control-center/ui/pages/fans.slint:211
msgctxt "PageFans"
msgid "Mid"
msgstr "Médio"
#: rog-control-center/ui/pages/fans.slint:111 rog-control-center/ui/pages/fans.slint:170 rog-control-center/ui/pages/fans.slint:229
msgctxt "PageFans"
msgid "GPU"
msgstr "Placa de Vídeo"
#: rog-control-center/ui/pages/fans.slint:131
msgctxt "PageFans"
msgid "Performance"
msgstr "Performance"
#: rog-control-center/ui/pages/fans.slint:190
msgctxt "PageFans"
msgid "Quiet"
msgstr "Silencioso"
#: rog-control-center/ui/pages/app_settings.slint:26
msgctxt "PageAppSettings"
msgid "Run in background after closing"
msgstr "Executar em pano de fundo após fechar"
#: rog-control-center/ui/pages/app_settings.slint:34
msgctxt "PageAppSettings"
msgid "Start app in background (UI closed)"
msgstr "Iniciar Aplicação em pano de fundo (Interface Gráfica fechada)"
#: rog-control-center/ui/pages/app_settings.slint:42
msgctxt "PageAppSettings"
msgid "Enable system tray icon"
msgstr "Habilitar icone da bandeja de sistema"
#: rog-control-center/ui/pages/app_settings.slint:50
msgctxt "PageAppSettings"
msgid "Enable dGPU notifications"
msgstr "Habilitar notificações da GPU dedicada"
#: rog-control-center/ui/types/aura_types.slint:52
msgctxt "Aura power zone"
msgid "Logo"
msgstr "Logo"
#: rog-control-center/ui/types/aura_types.slint:53 rog-control-center/ui/types/aura_types.slint:63
msgctxt "Aura power zone"
msgid "Keyboard"
msgstr "Teclado"
#: rog-control-center/ui/types/aura_types.slint:54 rog-control-center/ui/types/aura_types.slint:64
msgctxt "Aura power zone"
msgid "Lightbar"
msgstr "Barra de Luz"
#: rog-control-center/ui/types/aura_types.slint:55
msgctxt "Aura power zone"
msgid "Lid"
msgstr "Tampa"
#: rog-control-center/ui/types/aura_types.slint:56
msgctxt "Aura power zone"
msgid "Rear Glow"
msgstr "Brilho Traseiro"
#: rog-control-center/ui/types/aura_types.slint:57 rog-control-center/ui/types/aura_types.slint:65
msgctxt "Aura power zone"
msgid "Keyboard and Lightbar"
msgstr "Teclado e Barra de Luz"
#: rog-control-center/ui/types/aura_types.slint:58
msgctxt "Aura power zone"
msgid "Ally"
msgstr "Ally"
#: rog-control-center/ui/types/aura_types.slint:68
msgctxt "Aura brightness"
msgid "Off"
msgstr "Desligado"
#: rog-control-center/ui/types/aura_types.slint:69
msgctxt "Aura brightness"
msgid "Low"
msgstr "Baixo"
#: rog-control-center/ui/types/aura_types.slint:70
msgctxt "Aura brightness"
msgid "Med"
msgstr "Médio"
#: rog-control-center/ui/types/aura_types.slint:71
msgctxt "Aura brightness"
msgid "High"
msgstr "Alto"
#: rog-control-center/ui/types/aura_types.slint:76 rog-control-center/ui/types/aura_types.slint:91
msgctxt "Basic aura mode"
msgid "Static"
msgstr "Estático"
#: rog-control-center/ui/types/aura_types.slint:77 rog-control-center/ui/types/aura_types.slint:92
msgctxt "Basic aura mode"
msgid "Breathe"
msgstr "Respiração"
#: rog-control-center/ui/types/aura_types.slint:78 rog-control-center/ui/types/aura_types.slint:93
msgctxt "Basic aura mode"
msgid "Strobe"
msgstr "Estroboscópio"
#: rog-control-center/ui/types/aura_types.slint:79
msgctxt "Basic aura mode"
msgid "Rainbow"
msgstr "Arco-Íris"
#: rog-control-center/ui/types/aura_types.slint:80
msgctxt "Basic aura mode"
msgid "Star"
msgstr "Estrela"
#: rog-control-center/ui/types/aura_types.slint:81
msgctxt "Basic aura mode"
msgid "Rain"
msgstr "Chuva"
#: rog-control-center/ui/types/aura_types.slint:82
msgctxt "Basic aura mode"
msgid "Highlight"
msgstr "Destaque"
#: rog-control-center/ui/types/aura_types.slint:83
msgctxt "Basic aura mode"
msgid "Laser"
msgstr "Lase"
#: rog-control-center/ui/types/aura_types.slint:84
msgctxt "Basic aura mode"
msgid "Ripple"
msgstr "Ondas"
#: rog-control-center/ui/types/aura_types.slint:85
msgctxt "Basic aura mode"
msgid "Nothing"
msgstr "Nenhum"
#: rog-control-center/ui/types/aura_types.slint:86
msgctxt "Basic aura mode"
msgid "Pulse"
msgstr "Pulso"
#: rog-control-center/ui/types/aura_types.slint:87
msgctxt "Basic aura mode"
msgid "Comet"
msgstr "Cometa"
#: rog-control-center/ui/types/aura_types.slint:88
msgctxt "Basic aura mode"
msgid "Flash"
msgstr "Piscando"
#: rog-control-center/ui/types/aura_types.slint:100
msgctxt "Aura zone"
msgid "None"
msgstr "Nenhuma"
#: rog-control-center/ui/types/aura_types.slint:101
msgctxt "Aura zone"
msgid "Key1"
msgstr "Tecla1"
#: rog-control-center/ui/types/aura_types.slint:102
msgctxt "Aura zone"
msgid "Key2"
msgstr "Tecla2"
#: rog-control-center/ui/types/aura_types.slint:103
msgctxt "Aura zone"
msgid "Key3"
msgstr "Tecla3"
#: rog-control-center/ui/types/aura_types.slint:104
msgctxt "Aura zone"
msgid "Key4"
msgstr "Tecla4"
#: rog-control-center/ui/types/aura_types.slint:105
msgctxt "Aura zone"
msgid "Logo"
msgstr "Logo"
#: rog-control-center/ui/types/aura_types.slint:106
msgctxt "Aura zone"
msgid "Lightbar Left"
msgstr "Barra de Luza Esquerda"
#: rog-control-center/ui/types/aura_types.slint:107
msgctxt "Aura zone"
msgid "Lightbar Right"
msgstr "Barra de Luz Direita"
#: rog-control-center/ui/types/aura_types.slint:111
msgctxt "Aura direction"
msgid "Right"
msgstr "Direita"
#: rog-control-center/ui/types/aura_types.slint:112
msgctxt "Aura direction"
msgid "Left"
msgstr "Esquerda"
#: rog-control-center/ui/types/aura_types.slint:113
msgctxt "Aura direction"
msgid "Up"
msgstr "Cima"
#: rog-control-center/ui/types/aura_types.slint:114
msgctxt "Aura direction"
msgid "Down"
msgstr "Baixo"
#: rog-control-center/ui/types/aura_types.slint:118
msgctxt "Aura speed"
msgid "Low"
msgstr "Baixa"
#: rog-control-center/ui/types/aura_types.slint:119
msgctxt "Aura speed"
msgid "Medium"
msgstr "Média"
#: rog-control-center/ui/types/aura_types.slint:120
msgctxt "Aura speed"
msgid "High"
msgstr "Alta"
#: rog-control-center/ui/widgets/aura_power.slint:33
msgctxt "AuraPowerGroup"
msgid "Boot"
msgstr "Inicilização"
#: rog-control-center/ui/widgets/aura_power.slint:43
msgctxt "AuraPowerGroup"
msgid "Awake"
msgstr "Acordado"
#: rog-control-center/ui/widgets/aura_power.slint:53
msgctxt "AuraPowerGroup"
msgid "Sleep"
msgstr "Dormir"
#: rog-control-center/ui/widgets/aura_power.slint:63
msgctxt "AuraPowerGroup"
msgid "Shutdown"
msgstr "Desligar"
#: rog-control-center/ui/widgets/aura_power.slint:102
msgctxt "AuraPowerGroupOld"
msgid "Zone Selection"
msgstr "Seleção de Zona"
#: rog-control-center/ui/widgets/aura_power.slint:114
msgctxt "AuraPowerGroupOld"
msgid "Boot"
msgstr "Inicilizacao"
#: rog-control-center/ui/widgets/aura_power.slint:124
msgctxt "AuraPowerGroupOld"
msgid "Awake"
msgstr "Acordado"
#: rog-control-center/ui/widgets/aura_power.slint:134
msgctxt "AuraPowerGroupOld"
msgid "Sleep"
msgstr "Dormir"
#: rog-control-center/ui/widgets/common.slint:136
msgctxt "confirm_reset"
msgid "Are you sure you want to reset this?"
msgstr "Tem certeza que deseja resetar isso?"
#: rog-control-center/ui/main_window.slint:55
msgctxt "MainWindow"
msgid "ROG"
msgstr "ROG"
#: rog-control-center/ui/main_window.slint:57
msgctxt "Menu1"
msgid "System Control"
msgstr "Controles do Sistema"
#: rog-control-center/ui/main_window.slint:58
msgctxt "Menu2"
msgid "Keyboard Aura"
msgstr "Teclado Aura"
#: rog-control-center/ui/main_window.slint:59
msgctxt "Menu3"
msgid "AniMe Matrix"
msgstr "AniMe Matrix"
#: rog-control-center/ui/main_window.slint:60
msgctxt "Menu4"
msgid "Fan Curves"
msgstr "Curvas das Ventoinhas"
#: rog-control-center/ui/main_window.slint:61
msgctxt "Menu5"
msgid "App Settings"
msgstr "Configuracoes do App"
#: rog-control-center/ui/main_window.slint:62
msgctxt "Menu6"
msgid "About"
msgstr "Sobre"
#: rog-control-center/ui/main_window.slint:74
msgctxt "MainWindow"
msgid "Quit App"
msgstr "Sair do App"

Some files were not shown because too many files have changed in this diff Show More